001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/enterprise/servlet/OGCServletController.java $
002    // $Id: OGCServletController.java 18195 2009-06-18 15:55:39Z mschneider $
003    /*----------------------------------------------------------------------------
004     This file is part of deegree, http://deegree.org/
005     Copyright (C) 2001-2009 by:
006       Department of Geography, University of Bonn
007     and
008       lat/lon GmbH
009    
010     This library is free software; you can redistribute it and/or modify it under
011     the terms of the GNU Lesser General Public License as published by the Free
012     Software Foundation; either version 2.1 of the License, or (at your option)
013     any later version.
014     This library is distributed in the hope that it will be useful, but WITHOUT
015     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
016     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
017     details.
018     You should have received a copy of the GNU Lesser General Public License
019     along with this library; if not, write to the Free Software Foundation, Inc.,
020     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021    
022     Contact information:
023    
024     lat/lon GmbH
025     Aennchenstr. 19, 53177 Bonn
026     Germany
027     http://lat-lon.de/
028    
029     Department of Geography, University of Bonn
030     Prof. Dr. Klaus Greve
031     Postfach 1147, 53001 Bonn
032     Germany
033     http://www.geographie.uni-bonn.de/deegree/
034    
035     e-mail: info@deegree.org
036    ----------------------------------------------------------------------------*/
037    
038    package org.deegree.enterprise.servlet;
039    
040    import static java.lang.Character.isDigit;
041    import static java.lang.System.getProperty;
042    import static java.lang.System.setProperty;
043    import static org.deegree.enterprise.servlet.ServiceLookup.getInstance;
044    import static org.deegree.framework.log.LoggerFactory.getLogger;
045    import static org.deegree.framework.util.StringTools.arrayToString;
046    
047    import java.beans.Introspector;
048    import java.io.IOException;
049    import java.io.OutputStream;
050    import java.io.PrintWriter;
051    import java.lang.reflect.InvocationTargetException;
052    import java.lang.reflect.Method;
053    import java.net.InetAddress;
054    import java.net.URL;
055    import java.nio.charset.Charset;
056    import java.sql.Driver;
057    import java.sql.DriverManager;
058    import java.sql.SQLException;
059    import java.text.MessageFormat;
060    import java.util.Enumeration;
061    import java.util.HashMap;
062    import java.util.Iterator;
063    import java.util.Map;
064    
065    import javax.imageio.spi.IIORegistry;
066    import javax.servlet.ServletContext;
067    import javax.servlet.ServletException;
068    import javax.servlet.http.HttpServletRequest;
069    import javax.servlet.http.HttpServletResponse;
070    import javax.xml.parsers.DocumentBuilderFactory;
071    import javax.xml.transform.TransformerFactory;
072    
073    import org.apache.commons.logging.LogFactory;
074    import org.apache.log4j.LogManager;
075    import org.deegree.crs.configuration.CRSConfiguration;
076    import org.deegree.enterprise.AbstractOGCServlet;
077    import org.deegree.enterprise.ServiceException;
078    import org.deegree.framework.log.ILogger;
079    import org.deegree.framework.util.CharsetUtils;
080    import org.deegree.framework.util.KVP2Map;
081    import org.deegree.framework.util.StringTools;
082    import org.deegree.framework.util.WebappResourceResolver;
083    import org.deegree.framework.version.Version;
084    import org.deegree.framework.xml.XMLFragment;
085    import org.deegree.ogcwebservices.ExceptionReport;
086    import org.deegree.ogcwebservices.OGCRequestFactory;
087    import org.deegree.ogcwebservices.OGCWebServiceException;
088    import org.deegree.ogcwebservices.OGCWebServiceRequest;
089    import org.deegree.ogcwebservices.wmps.configuration.WMPSConfigurationDocument;
090    import org.deegree.ogcwebservices.wms.configuration.WMSConfigurationDocument;
091    import org.deegree.ogcwebservices.wms.configuration.WMSConfigurationDocument_1_3_0;
092    import org.deegree.owscommon.XMLFactory;
093    import org.xml.sax.SAXException;
094    
095    /**
096     * An <code>OGCServletController</code> handles all incoming requests. The controller for all OGC service requests.
097     * Dispatcher to specific handler for WMS, WFS and other.
098     *
099     * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a>
100     * @author last edited by: $Author: mschneider $
101     *
102     * @version $Revision: 18195 $, $Date: 22.04.2008 16:23:34$
103     * @see <a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html">Front controller </a>
104     */
105    public class OGCServletController extends AbstractOGCServlet {
106    
107        /**
108         * address is the url of the client which requests.
109         */
110        public static String address = null;
111    
112        private static final long serialVersionUID = -4461759017823581221L;
113    
114        private static ILogger LOG;
115    
116        private static final String SERVICE = "services";
117    
118        private static final String HANDLER_CLASS = ".handler";
119    
120        private static final String HANDLER_CONF = ".config";
121    
122        private static final Map<Class<?>, String> SERVICE_FACTORIES_MAPPINGS = new HashMap<Class<?>, String>();
123    
124        private static final String ERR_MSG = "Can't set configuration for {0}";
125    
126        /**
127         *
128         *
129         * @param request
130         * @param response
131         * @TODO refactor and optimize code for initializing handler
132         */
133        public void doService( HttpServletRequest request, HttpServletResponse response ) {
134            if ( response.isCommitted() ) {
135                LOG.logWarning( "The response object is already committed, cannot proceed!" );
136                return;
137            }
138    
139            long startTime = System.currentTimeMillis();
140            address = request.getRequestURL().toString();
141    
142            String service = null;
143            try {
144                OGCWebServiceRequest ogcRequest = OGCRequestFactory.create( request );
145    
146                LOG.logInfo( StringTools.concat( 500, "Handling request '", ogcRequest.getId(), "' from '",
147                                                 request.getRemoteAddr(), "' to service: '", ogcRequest.getServiceName(),
148                                                 "'" ) );
149    
150                // get service from request
151                service = ogcRequest.getServiceName().toUpperCase();
152    
153                // get handler instance
154                ServiceDispatcher handler = ServiceLookup.getInstance().getHandler( service, request.getRemoteAddr() );
155                // dispatch request to specific handler
156                handler.perform( ogcRequest, response );
157            } catch ( OGCWebServiceException e ) {
158                LOG.logError( e.getMessage(), e );
159                sendException( response, e, request, service );
160            } catch ( ServiceException e ) {
161                if ( e.getNestedException() instanceof OGCWebServiceException ) {
162                    sendException( response, (OGCWebServiceException) e.getNestedException(), request, service );
163                } else {
164                    sendException( response, new OGCWebServiceException( this.getClass().getName(), e.getMessage() ),
165                                   request, service );
166                }
167                LOG.logError( e.getMessage(), e );
168            } catch ( Exception e ) {
169                sendException( response, new OGCWebServiceException( this.getClass().getName(), e.getMessage() ), request,
170                               service );
171                LOG.logError( e.getMessage(), e );
172            }
173            if ( LOG.isDebug() ) {
174                LOG.logDebug( "OGCServletController: request performed in "
175                              + Long.toString( System.currentTimeMillis() - startTime ) + " milliseconds." );
176            }
177        }
178    
179        /**
180         * Sends the passed <code>OGCWebServiceException</code> to the calling client.
181         *
182         * @param response
183         * @param e
184         * @param request
185         * @param service
186         *            the service name, if known
187         */
188        private static void sendException( HttpServletResponse response, OGCWebServiceException e,
189                                           HttpServletRequest request, String service ) {
190            LOG.logInfo( "Sending OGCWebServiceException to client." );
191    
192            Map<?, ?> pmap = request.getParameterMap();
193            Map<String, String> map = new HashMap<String, String>( pmap.size() );
194            for ( Object o : pmap.keySet() ) {
195                String[] tmp = (String[]) pmap.get( o );
196                for ( int i = 0; i < tmp.length; i++ ) {
197                    tmp[i] = tmp[i].trim();
198                }
199                map.put( ( (String) o ).toLowerCase(), arrayToString( tmp, ',' ) );
200            }
201    
202            boolean isWMS130 = false, isCSW = false, isWCTS = false, isWFS = false, isWFS100 = false;
203    
204            if ( service == null ) {
205                service = map.get( "service" );
206            }
207    
208            String version = map.get( "version" );
209    
210            if ( service != null ) {
211                if ( "wms".equalsIgnoreCase( service ) ) {
212                    isWMS130 = version != null && version.equals( "1.3.0" );
213                }
214                if ( "wfs".equalsIgnoreCase( service ) ) {
215                    isWFS = true;
216                    isWFS100 = version != null && version.equals( "1.0.0" );
217                }
218    
219                isCSW = "csw".equalsIgnoreCase( service );
220                isWCTS = "wcts".equalsIgnoreCase( service );
221                isWFS = "wfs".equalsIgnoreCase( service );
222            } else {
223                try {
224                    XMLFragment doc = new XMLFragment( request.getReader(), XMLFragment.DEFAULT_URL );
225                    service = OGCRequestFactory.getTargetService( "", "", doc.getRootElement().getOwnerDocument() );
226                    isCSW = "csw".equalsIgnoreCase( service );
227                    isWCTS = "wcts".equalsIgnoreCase( service );
228                    isWFS = "wfs".equalsIgnoreCase( service );
229                    isWFS100 = isWFS && doc.getRootElement().getAttribute( "version" ) != null
230                               && doc.getRootElement().getAttribute( "version" ).equals( "1.0.0" );
231                } catch ( SAXException e1 ) {
232                    // ignore
233                } catch ( IOException e1 ) {
234                    // ignore
235                } catch ( IllegalStateException e1 ) {
236                    // ignore, that happens in some tomcats
237                }
238            }
239    
240            try {
241                XMLFragment doc;
242                String contentType = "text/xml";
243    
244                if ( !( isWMS130 || isCSW || isWCTS || isWFS ) ) {
245                    // apply the simplest of heuristics...
246                    String req = request.getRequestURI().toLowerCase();
247                    if ( req.indexOf( "csw" ) != -1 ) {
248                        isCSW = true;
249                    } else if ( req.indexOf( "wcts" ) != -1 ) {
250                        isWCTS = true;
251                    } else if ( req.indexOf( "wfs" ) != -1 ) {
252                        isWFS = true;
253                    }
254    
255                    if ( isWFS ) {
256                        isWFS100 = req.indexOf( "1.0.0" ) != -1;
257                    }
258    
259                    if ( !( isWMS130 || isCSW || isWCTS || isWFS || isWFS100 ) ) {
260                        isWMS130 = version != null && version.equals( "1.3.0" );
261                    }
262                }
263    
264                // send exception format INIMAGE etc. for WMS
265                if ( service != null && service.equalsIgnoreCase( "wms" ) ) {
266                    ServiceDispatcher handler = getInstance().getHandler( service, request.getRemoteAddr() );
267                    if ( handler instanceof WMSHandler ) {
268                        WMSHandler h = (WMSHandler) handler;
269                        String format = map.get( "format" );
270                        String eFormat = map.get( "exceptions" );
271                        try {
272                            h.determineExceptionFormat( eFormat, format, version, response );
273                            h.writeServiceExceptionReport( e );
274                            return;
275                        } catch ( Exception ex ) {
276                            LOG.logDebug( "Error while sending the exception in special format."
277                                          + " Continuing in default mode.", ex );
278                        }
279                    }
280                }
281    
282                if ( isWMS130 || "wcs".equalsIgnoreCase( e.getLocator() ) ) {
283                    doc = XMLFactory.exportNS( new ExceptionReport( new OGCWebServiceException[] { e } ) );
284                } else if ( isCSW ) {
285                    doc = XMLFactory.exportExceptionReport( new ExceptionReport( new OGCWebServiceException[] { e } ) );
286                } else if ( isWCTS ) {
287                    doc = org.deegree.owscommon_1_1_0.XMLFactory.exportException( e );
288                } else if ( isWFS100 ) {
289                    doc = XMLFactory.exportExceptionReportWFS100( e );
290                } else if ( isWFS ) {
291                    doc = XMLFactory.exportExceptionReportWFS( e );
292                } else {
293                    contentType = "application/vnd.ogc.se_xml";
294                    doc = XMLFactory.export( new ExceptionReport( new OGCWebServiceException[] { e } ) );
295                }
296    
297                response.setContentType( contentType );
298                OutputStream os = response.getOutputStream();
299                doc.write( os );
300                os.close();
301            } catch ( Exception ex ) {
302                LOG.logError( "ERROR: " + ex.getMessage(), ex );
303            }
304        }
305    
306        /**
307         *
308         * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
309         *      javax.servlet.http.HttpServletResponse)
310         */
311        @Override
312        protected void doGet( HttpServletRequest request, HttpServletResponse response )
313                                throws ServletException, IOException {
314    
315            LOG.logDebug( "query string ", request.getQueryString() );
316            if ( request.getParameter( "RELOADDEEGREE" ) != null ) {
317                reloadServices( request, response );
318            } else {
319                this.doService( request, response );
320            }
321        }
322    
323        /**
324         *
325         * @param request
326         * @param response
327         * @throws ServletException
328         * @throws IOException
329         */
330        private void reloadServices( HttpServletRequest request, HttpServletResponse response )
331                                throws ServletException, IOException {
332            Map<?, ?> map = KVP2Map.toMap( request );
333            String user = (String) map.get( "USER" );
334            String password = (String) map.get( "PASSWORD" );
335            String message = null;
336            if ( getInitParameter( "USER" ) != null && getInitParameter( "PASSWORD" ) != null
337                 && getInitParameter( "USER" ).equals( user ) && getInitParameter( "PASSWORD" ).equals( password ) ) {
338                initServices( getServletContext() );
339                ctDestroyed();
340                message = Messages.getString( "OGCServletController.reloadsuccess" );
341            } else {
342                message = Messages.getString( "OGCServletController.reloadfailed" );
343            }
344            PrintWriter pw = response.getWriter();
345            pw.print( message );
346            pw.flush();
347            pw.close();
348        }
349    
350        /*
351         * (non-Javadoc)
352         *
353         * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
354         * javax.servlet.http.HttpServletResponse)
355         */
356        @Override
357        protected void doPost( HttpServletRequest request, HttpServletResponse response )
358                                throws ServletException, IOException {
359            this.doService( request, response );
360        }
361    
362        private static String spaces( int i ) {
363            if ( i <= 0 ) {
364                return "";
365            }
366    
367            StringBuffer sb = new StringBuffer( i );
368            for ( int j = 0; j < i; ++j ) {
369                sb.append( " " );
370            }
371            return sb.toString();
372        }
373    
374        private static void logIfThere( String param ) {
375            String val = getProperty( param );
376            if ( val != null ) {
377                LOG.logInfo( "- " + param + spaces( 15 - param.length() ) + ": " + val );
378            }
379        }
380    
381        /**
382         * @see javax.servlet.GenericServlet#init()
383         */
384        @Override
385        public void init()
386                                throws ServletException {
387    
388            synchronized ( OGCServletController.class ) {
389                if ( LOG == null ) {
390                    // hack to figure out and set the context path name
391                    // for a laugh, see http://marc.info/?l=tomcat-user&m=109215904113904&w=2 and the related thread
392                    // http://marc.info/?t=109215871400004&r=1&w=2
393                    String path = getServletContext().getRealPath( "" );
394                    String[] ps = path.split( "[/\\\\]" );
395                    path = ps[ps.length - 1];
396                    // heuristics are always a charm (and work best for tomcat in this case)
397                    if ( isDigit( path.charAt( 0 ) ) && path.indexOf( "-" ) != -1 ) {
398                        path = path.split( "-", 2 )[1];
399                    }
400                    // note that setting this changes it on a JVM GLOBAL BASIS, so it WILL GET OVERWRITTEN in subsequent
401                    // deegree startups! (However, since the log4j.properties will only be read on startup, this hack is
402                    // useful anyway)
403                    setProperty( "context.name", path );
404    
405                    LOG = getLogger( OGCServletController.class );
406                }
407            }
408    
409            super.init();
410            LOG.logDebug( "Logger for " + this.getClass().getName() + " initialized." );
411    
412            SERVICE_FACTORIES_MAPPINGS.put( CSWHandler.class, "org.deegree.ogcwebservices.csw.CSWFactory" );
413            SERVICE_FACTORIES_MAPPINGS.put( WFSHandler.class, "org.deegree.ogcwebservices.wfs.WFServiceFactory" );
414            SERVICE_FACTORIES_MAPPINGS.put( WCSHandler.class, "org.deegree.ogcwebservices.wcs.WCServiceFactory" );
415            SERVICE_FACTORIES_MAPPINGS.put( WMSHandler.class, "org.deegree.ogcwebservices.wms.WMServiceFactory" );
416            SERVICE_FACTORIES_MAPPINGS.put( SOSHandler.class, "org.deegree.ogcwebservices.sos.SOServiceFactory" );
417            SERVICE_FACTORIES_MAPPINGS.put( WPVSHandler.class, "org.deegree.ogcwebservices.wpvs.WPVServiceFactory" );
418            SERVICE_FACTORIES_MAPPINGS.put( WMPSHandler.class, "org.deegree.ogcwebservices.wmps.WMPServiceFactory" );
419            SERVICE_FACTORIES_MAPPINGS.put( WPSHandler.class, "org.deegree.ogcwebservices.wps.WPServiceFactory" );
420            SERVICE_FACTORIES_MAPPINGS.put( WASSHandler.class, "org.deegree.ogcwebservices.wass.common.WASServiceFactory" );
421            SERVICE_FACTORIES_MAPPINGS.put( WCTSHandler.class, "org.deegree.ogcwebservices.wcts.WCTServiceFactory" );
422    
423            LOG.logInfo( "-------------------------------------------------------------------------------" );
424            LOG.logInfo( "Starting deegree version " + Version.getVersion() );
425            LOG.logInfo( "- context        : " + this.getServletContext().getServletContextName() );
426            LOG.logInfo( "- real path      : " + this.getServletContext().getRealPath( "/" ) );
427            LOG.logInfo( "- java version   : " + System.getProperty( "java.version" ) + "" );
428            LOG.logInfo( "- dom builder    : " + DocumentBuilderFactory.newInstance().getClass().getName() + "" );
429            LOG.logInfo( "- xslt builder   : " + TransformerFactory.newInstance().getClass().getName() + "" );
430            LOG.logInfo( "- system charset : " + CharsetUtils.getSystemCharset() );
431            LOG.logInfo( "- default charset: " + Charset.defaultCharset() );
432            LOG.logInfo( "- server info    : " + this.getServletContext().getServerInfo() );
433            logIfThere( "proxyHost" );
434            logIfThere( "proxyPort" );
435            logIfThere( "noProxyHosts" );
436            logIfThere( "nonProxyHosts" );
437            logIfThere( "http.proxyHost" );
438            logIfThere( "http.proxyPort" );
439            logIfThere( "http.noProxyHosts" );
440            logIfThere( "http.nonProxyHosts" );
441            logIfThere( "ftp.proxyHost" );
442            logIfThere( "ftp.proxyPort" );
443            logIfThere( "ftp.noProxyHosts" );
444            logIfThere( "ftp.nonProxyHosts" );
445            logIfThere( "https.proxyHost" );
446            logIfThere( "https.proxyPort" );
447            logIfThere( "https.noProxyHosts" );
448            logIfThere( "https.nonProxyHosts" );
449            try {
450                LOG.logInfo( "- ip             : " + InetAddress.getLocalHost().getHostAddress() );
451                LOG.logInfo( "- host name      : " + InetAddress.getLocalHost().getHostName() );
452                LOG.logInfo( "- domain name    : " + InetAddress.getLocalHost().getCanonicalHostName() );
453            } catch ( Exception e ) {
454                LOG.logError( e.getMessage(), e );
455            }
456            LOG.logInfo( "-------------------------------------------------------------------------------" );
457            this.initServices( getServletContext() );
458            checkServerCompatibility();
459            LOG.logInfo( "-------------------------------------------------------------------------------" );
460            String tmpServiceList = this.getServiceList();
461            if ( tmpServiceList != null && !( "".equals( tmpServiceList.trim() ) ) ) {
462                LOG.logInfo( "Initialized successfully (context '" + this.getServletContext().getServletContextName()
463                             + "'):" );
464                String[] tmpServices = tmpServiceList.split( "," );
465                for ( String service : tmpServices ) {
466                    // Added a check for the alternative service name, because it should not be outputed twice for the csw.
467                    if ( !OGCRequestFactory.CSW_SERVICE_NAME_EBRIM.toUpperCase().equals( service ) ) {
468                        LOG.logInfo( "- " + service );
469                    }
470                }
471            } else {
472                LOG.logError( "An Error occured while initializing context '"
473                              + this.getServletContext().getServletContextName() + "', no services are available." );
474            }
475    
476            LOG.logInfo( "-------------------------------------------------------------------------------" );
477            // Sets the attributes for tomcat -> application.getAttribute(); in jsp sites
478            this.getServletContext().setAttribute( "deegree_ogc_services", this.getServiceList() );
479        }
480    
481        private void checkServerCompatibility() {
482            String serverInfo = getServletContext().getServerInfo();
483            if ( "Apache Tomcat/5.5.26".equals( serverInfo ) || "Apache Tomcat/6.0.16".equals( serverInfo ) ) {
484                LOG.logWarning( "*******************************************************************************" );
485                LOG.logWarning( "YOU ARE RUNNING DEEGREE ON A TOMCAT RELEASE (" + serverInfo
486                                + ") THAT IS KNOWN TO HAVE A SERIOUS ISSUE WITH LARGE POST REQUESTS." );
487                LOG.logWarning( "PLEASE CONSIDER THE CORRESPONDING DEEGREE WIKI PAGE AT  https://wiki.deegree.org/deegreeWiki/ApacheTomcat "
488                                + "FOR DETAILS AND SWITCH TO A DIFFERENT TOMCAT VERSION." );
489                LOG.logWarning( "*******************************************************************************" );
490            }
491        }
492    
493        private void initServices( ServletContext context )
494                                throws ServletException {
495    
496            // get list of OGC services
497            String serviceList = this.getRequiredInitParameter( SERVICE );
498    
499            String[] serviceNames = StringTools.toArray( serviceList, ",", false );
500    
501            ServiceLookup lookup = ServiceLookup.getInstance();
502            for ( int i = 0; i < serviceNames.length; i++ ) {
503                LOG.logInfo( StringTools.concat( 100, "---- Initializing ", serviceNames[i].toUpperCase(), " ----" ) );
504                try {
505                    String className = this.getRequiredInitParameter( serviceNames[i] + HANDLER_CLASS );
506                    Class<?> handlerClzz = Class.forName( className );
507    
508                    // initialize each service factory
509                    String s = this.getRequiredInitParameter( serviceNames[i] + HANDLER_CONF );
510                    URL serviceConfigurationURL = WebappResourceResolver.resolveFileLocation( s, context, LOG );
511    
512                    // set configuration
513                    LOG.logInfo( StringTools.concat( 300, "Reading configuration for ", serviceNames[i].toUpperCase(),
514                                                     " from URL: '", serviceConfigurationURL, "'." ) );
515    
516                    String factoryClassName = SERVICE_FACTORIES_MAPPINGS.get( handlerClzz );
517    
518                    Class<?> factory = Class.forName( factoryClassName );
519                    Method method = factory.getMethod( "setConfiguration", new Class[] { URL.class } );
520                    method.invoke( factory, new Object[] { serviceConfigurationURL } );
521    
522                    // The csw-ebrim profile adds an alternative service name, it too is registred with the CSW handler.
523                    if ( "CSW".equals( serviceNames[i].toUpperCase() ) ) {
524                        lookup.addService( OGCRequestFactory.CSW_SERVICE_NAME_EBRIM.toUpperCase(), handlerClzz );
525                    }
526                    // put handler to available service list
527                    lookup.addService( serviceNames[i].toUpperCase(), handlerClzz );
528    
529                    LOG.logInfo( StringTools.concat( 300, serviceNames[i].toUpperCase(), " successfully initialized." ) );
530                } catch ( ServletException e ) {
531                    LOG.logError( e.getMessage(), e );
532                } catch ( InvocationTargetException e ) {
533                    e.getTargetException().printStackTrace();
534                    LOG.logError( this.produceMessage( ERR_MSG, new Object[] { serviceNames[i] } ), e );
535                } catch ( Exception e ) {
536                    LOG.logError( "Can't initialize OGC service:" + serviceNames[i], e );
537                }
538            }
539        }
540    
541        private String getRequiredInitParameter( String name )
542                                throws ServletException {
543            String paramValue = getInitParameter( name );
544            if ( paramValue == null ) {
545    
546                String msg = "Required init parameter '" + name + "' missing in web.xml";
547                LOG.logError( msg );
548                throw new ServletException( msg );
549            }
550            return paramValue;
551        }
552    
553        /**
554         * @return the services, separated by ","
555         */
556        private String getServiceList() {
557    
558            StringBuffer buf = new StringBuffer();
559            ServiceLookup lookup = ServiceLookup.getInstance();
560            for ( Iterator<?> iter = lookup.getIterator(); iter.hasNext(); ) {
561                String serviceName = (String) iter.next();
562                buf.append( serviceName );
563                if ( iter.hasNext() ) {
564                    buf.append( ',' );
565                }
566            }
567            return buf.toString();
568        }
569    
570        /**
571         * Formats the provided string and the args array into a String using MessageFormat.
572         *
573         * @param pattern
574         * @param args
575         * @return the message to present the client.
576         */
577        private String produceMessage( String pattern, Object[] args ) {
578            return new MessageFormat( pattern ).format( args );
579        }
580    
581        /**
582         * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
583         */
584        public void ctDestroyed() {
585            LOG.logInfo( "Stopping context: " );
586    
587            WMSConfigurationDocument.resetCapabilitiesCache();
588            WMSConfigurationDocument_1_3_0.resetCapabilitiesCache();
589            WMPSConfigurationDocument.resetCapabilitiesCache();
590    
591            ServiceLookup lookup = ServiceLookup.getInstance();
592            for ( Iterator<?> iter = lookup.getIterator(); iter.hasNext(); ) {
593                String serviceName = (String) iter.next();
594                LOG.logInfo( "Stopping service " + serviceName );
595    
596                try {
597                    String s = SERVICE_FACTORIES_MAPPINGS.get( lookup.getService( serviceName ) );
598                    Class<?> clzz = Class.forName( s );
599                    // TODO stop and reset all service instances
600                    Method[] methods = clzz.getMethods();
601                    for ( int j = 0; j < methods.length; j++ ) {
602                        if ( methods[j].getName().equals( "reset" ) ) {
603                            Object[] args = new Object[0];
604                            methods[j].invoke( clzz.newInstance(), args );
605                        }
606                    }
607                } catch ( Exception e ) {
608                    LOG.logError( e.getMessage(), e );
609                }
610            }
611        }
612    
613        @Override
614        public void destroy() {
615            super.destroy();
616            Enumeration<Driver> e = DriverManager.getDrivers();
617            while ( e.hasMoreElements() ) {
618                Driver driver = e.nextElement();
619                try {
620                    if ( driver.getClass().getClassLoader() == getClass().getClassLoader() )
621                        DriverManager.deregisterDriver( driver );
622                } catch ( SQLException e1 ) {
623                    LOG.logError( "Cannot unload driver: " + driver );
624                }
625            }
626            LogFactory.releaseAll();
627            LogManager.shutdown();
628            // SLF4JLogFactory.releaseAll(); // should be the same as the LogFactory.releaseAll call
629            Iterator<Class<?>> i = IIORegistry.getDefaultInstance().getCategories();
630            while ( i.hasNext() ) {
631                Class<?> c = i.next();
632                Iterator<?> k = IIORegistry.getDefaultInstance().getServiceProviders( c, false );
633                while ( k.hasNext() ) {
634                    Object o = k.next();
635                    if ( o.getClass().getClassLoader() == getClass().getClassLoader() ) {
636                        IIORegistry.getDefaultInstance().deregisterServiceProvider( o );
637                        LOG.logDebug( "Deregistering JAI driver ", o.getClass() );
638                    }
639                }
640            }
641            Introspector.flushCaches();
642            // just clear the configurations for now, it does not hurt
643            CRSConfiguration.DEFINED_CONFIGURATIONS.clear();
644        }
645    
646    }