001    //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/enterprise/servlet/OGCServletController.java $
002    // $Id: OGCServletController.java 29966 2011-03-09 14:19:04Z apoth $
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: apoth $
101     *
102     * @version $Revision: 29966 $, $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!" );
136            }
137    
138            long startTime = System.currentTimeMillis();
139            address = request.getRequestURL().toString();
140    
141            String service = null;
142            try {
143                OGCWebServiceRequest ogcRequest = OGCRequestFactory.create( request );
144    
145                LOG.logInfo( StringTools.concat( 500, "Handling request '", ogcRequest.getId(), "' from '",
146                                                 request.getRemoteAddr(), "' to service: '", ogcRequest.getServiceName(),
147                                                 "'" ) );
148    
149                // get service from request
150                service = ogcRequest.getServiceName().toUpperCase();
151    
152                // get handler instance
153                ServiceDispatcher handler = ServiceLookup.getInstance().getHandler( service, request.getRemoteAddr() );
154                // dispatch request to specific handler
155                handler.perform( ogcRequest, response );
156            } catch ( OGCWebServiceException e ) {
157                LOG.logError( e.getMessage(), e );
158                sendException( response, e, request, service );
159            } catch ( ServiceException e ) {
160                if ( e.getNestedException() instanceof OGCWebServiceException ) {
161                    sendException( response, (OGCWebServiceException) e.getNestedException(), request, service );
162                } else {
163                    sendException( response, new OGCWebServiceException( this.getClass().getName(), e.getMessage() ),
164                                   request, service );
165                }
166                LOG.logError( e.getMessage(), e );
167            } catch ( Exception e ) {
168                sendException( response, new OGCWebServiceException( this.getClass().getName(), e.getMessage() ), request,
169                               service );
170                LOG.logError( e.getMessage(), e );
171            }
172            if ( LOG.isDebug() ) {
173                LOG.logDebug( "OGCServletController: request performed in "
174                              + Long.toString( System.currentTimeMillis() - startTime ) + " milliseconds." );
175            }
176        }
177    
178        /**
179         * Sends the passed <code>OGCWebServiceException</code> to the calling client.
180         *
181         * @param response
182         * @param e
183         * @param request
184         * @param service
185         *            the service name, if known
186         */
187        private static void sendException( HttpServletResponse response, OGCWebServiceException e,
188                                           HttpServletRequest request, String service ) {
189            LOG.logInfo( "Sending OGCWebServiceException to client." );
190    
191            Map<?, ?> pmap = request.getParameterMap();
192            Map<String, String> map = new HashMap<String, String>( pmap.size() );
193            for ( Object o : pmap.keySet() ) {
194                String[] tmp = (String[]) pmap.get( o );
195                for ( int i = 0; i < tmp.length; i++ ) {
196                    tmp[i] = tmp[i].trim();
197                }
198                map.put( ( (String) o ).toLowerCase(), arrayToString( tmp, ',' ) );
199            }
200    
201            boolean isWMS130 = false, isCSW = false, isWCTS = false, isWFS = false, isWFS100 = false;
202    
203            if ( service == null ) {
204                service = map.get( "service" );
205            }
206    
207            String version = map.get( "version" );
208    
209            if ( service != null ) {
210                if ( "wms".equalsIgnoreCase( service ) ) {
211                    isWMS130 = version != null && version.equals( "1.3.0" );
212                }
213                if ( "wfs".equalsIgnoreCase( service ) ) {
214                    isWFS = true;
215                    isWFS100 = version != null && version.equals( "1.0.0" );
216                }
217    
218                isCSW = "csw".equalsIgnoreCase( service );
219                isWCTS = "wcts".equalsIgnoreCase( service );
220                isWFS = "wfs".equalsIgnoreCase( service );
221            } else {
222                try {
223                    XMLFragment doc = new XMLFragment( request.getReader(), XMLFragment.DEFAULT_URL );
224                    service = OGCRequestFactory.getTargetService( "", "", doc.getRootElement().getOwnerDocument() );
225                    isCSW = "csw".equalsIgnoreCase( service );
226                    isWCTS = "wcts".equalsIgnoreCase( service );
227                    isWFS = "wfs".equalsIgnoreCase( service );
228                    isWFS100 = isWFS && doc.getRootElement().getAttribute( "version" ) != null
229                               && doc.getRootElement().getAttribute( "version" ).equals( "1.0.0" );
230                } catch ( SAXException e1 ) {
231                    // ignore
232                } catch ( IOException e1 ) {
233                    // ignore
234                } catch ( IllegalStateException e1 ) {
235                    // ignore, that happens in some tomcats
236                }
237            }
238    
239            try {
240                XMLFragment doc;
241                String contentType = "text/xml";
242    
243                if ( !( isWMS130 || isCSW || isWCTS || isWFS ) ) {
244                    // apply the simplest of heuristics...
245                    String req = request.getRequestURI().toLowerCase();
246                    if ( req.indexOf( "csw" ) != -1 ) {
247                        isCSW = true;
248                    } else if ( req.indexOf( "wcts" ) != -1 ) {
249                        isWCTS = true;
250                    } else if ( req.indexOf( "wfs" ) != -1 ) {
251                        isWFS = true;
252                    }
253    
254                    if ( isWFS ) {
255                        isWFS100 = req.indexOf( "1.0.0" ) != -1;
256                    }
257    
258                    if ( !( isWMS130 || isCSW || isWCTS || isWFS || isWFS100 ) ) {
259                        isWMS130 = version != null && version.equals( "1.3.0" );
260                    }
261                }
262    
263                // send exception format INIMAGE etc. for WMS
264                if ( service != null && service.equalsIgnoreCase( "wms" ) ) {
265                    ServiceDispatcher handler = getInstance().getHandler( service, request.getRemoteAddr() );
266                    if ( handler instanceof WMSHandler ) {
267                        WMSHandler h = (WMSHandler) handler;
268                        String format = map.get( "format" );
269                        String eFormat = map.get( "exceptions" );
270                        try {
271                            h.determineExceptionFormat( eFormat, format, version, response );
272                            h.writeServiceExceptionReport( e );
273                            return;
274                        } catch ( Exception ex ) {
275                            LOG.logDebug( "Error while sending the exception in special format."
276                                          + " Continuing in default mode.", ex );
277                        }
278                    }
279                }
280    
281                if ( isWMS130 || "wcs".equalsIgnoreCase( e.getLocator() ) ) {
282                    doc = XMLFactory.exportNS( new ExceptionReport( new OGCWebServiceException[] { e } ) );
283                } else if ( isCSW ) {
284                    doc = XMLFactory.exportExceptionReport( new ExceptionReport( new OGCWebServiceException[] { e } ) );
285                } else if ( isWCTS ) {
286                    doc = org.deegree.owscommon_1_1_0.XMLFactory.exportException( e );
287                } else if ( isWFS100 ) {
288                    doc = XMLFactory.exportExceptionReportWFS100( e );
289                } else if ( isWFS ) {
290                    doc = XMLFactory.exportExceptionReportWFS( e );
291                } else {
292                    contentType = "application/vnd.ogc.se_xml";
293                    doc = XMLFactory.export( new ExceptionReport( new OGCWebServiceException[] { e } ) );
294                }
295    
296                response.setContentType( contentType );
297                OutputStream os = response.getOutputStream();
298                doc.write( os );
299                os.close();
300            } catch ( Exception ex ) {
301                LOG.logError( "ERROR: " + ex.getMessage(), ex );
302            }
303        }
304    
305        /**
306         *
307         * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
308         *      javax.servlet.http.HttpServletResponse)
309         */
310        @Override
311        protected void doGet( HttpServletRequest request, HttpServletResponse response )
312                                throws ServletException, IOException {
313    
314            LOG.logDebug( "query string ", request.getQueryString() );
315            if ( request.getParameter( "RELOADDEEGREE" ) != null ) {
316                reloadServices( request, response );
317            } else {
318                this.doService( request, response );
319            }
320        }
321    
322        /**
323         *
324         * @param request
325         * @param response
326         * @throws ServletException
327         * @throws IOException
328         */
329        private void reloadServices( HttpServletRequest request, HttpServletResponse response )
330                                throws ServletException, IOException {
331            Map<?, ?> map = KVP2Map.toMap( request );
332            String user = (String) map.get( "USER" );
333            String password = (String) map.get( "PASSWORD" );
334            String message = null;
335            if ( getInitParameter( "USER" ) != null && getInitParameter( "PASSWORD" ) != null
336                 && getInitParameter( "USER" ).equals( user ) && getInitParameter( "PASSWORD" ).equals( password ) ) {
337                initServices( getServletContext() );
338                ctDestroyed();
339                message = Messages.getString( "OGCServletController.reloadsuccess" );
340            } else {
341                message = Messages.getString( "OGCServletController.reloadfailed" );
342            }
343            PrintWriter pw = response.getWriter();
344            pw.print( message );
345            pw.flush();
346            pw.close();
347        }
348    
349        /*
350         * (non-Javadoc)
351         *
352         * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
353         * javax.servlet.http.HttpServletResponse)
354         */
355        @Override
356        protected void doPost( HttpServletRequest request, HttpServletResponse response )
357                                throws ServletException, IOException {
358            this.doService( request, response );
359        }
360    
361        private static String spaces( int i ) {
362            if ( i <= 0 ) {
363                return "";
364            }
365    
366            StringBuffer sb = new StringBuffer( i );
367            for ( int j = 0; j < i; ++j ) {
368                sb.append( " " );
369            }
370            return sb.toString();
371        }
372    
373        private static void logIfThere( String param ) {
374            String val = getProperty( param );
375            if ( val != null ) {
376                LOG.logInfo( "- " + param + spaces( 15 - param.length() ) + ": " + val );
377            }
378        }
379    
380        /**
381         * @see javax.servlet.GenericServlet#init()
382         */
383        @Override
384        public void init()
385                                throws ServletException {
386    
387            synchronized ( OGCServletController.class ) {
388                if ( LOG == null ) {
389                    // hack to figure out and set the context path name
390                    // for a laugh, see http://marc.info/?l=tomcat-user&m=109215904113904&w=2 and the related thread
391                    // http://marc.info/?t=109215871400004&r=1&w=2
392                    String path = getServletContext().getRealPath( "" );
393                    String[] ps = path.split( "[/\\\\]" );
394                    path = ps[ps.length - 1];
395                    // heuristics are always a charm (and work best for tomcat in this case)
396                    if ( isDigit( path.charAt( 0 ) ) && path.indexOf( "-" ) != -1 ) {
397                        path = path.split( "-", 2 )[1];
398                    }
399                    // note that setting this changes it on a JVM GLOBAL BASIS, so it WILL GET OVERWRITTEN in subsequent
400                    // deegree startups! (However, since the log4j.properties will only be read on startup, this hack is
401                    // useful anyway)
402                    setProperty( "context.name", path );
403    
404                    LOG = getLogger( OGCServletController.class );
405                }
406            }
407    
408            super.init();
409            LOG.logDebug( "Logger for " + this.getClass().getName() + " initialized." );
410    
411            SERVICE_FACTORIES_MAPPINGS.put( CSWHandler.class, "org.deegree.ogcwebservices.csw.CSWFactory" );
412            SERVICE_FACTORIES_MAPPINGS.put( WFSHandler.class, "org.deegree.ogcwebservices.wfs.WFServiceFactory" );
413            SERVICE_FACTORIES_MAPPINGS.put( WCSHandler.class, "org.deegree.ogcwebservices.wcs.WCServiceFactory" );
414            SERVICE_FACTORIES_MAPPINGS.put( WMSHandler.class, "org.deegree.ogcwebservices.wms.WMServiceFactory" );
415            SERVICE_FACTORIES_MAPPINGS.put( WPVSHandler.class, "org.deegree.ogcwebservices.wpvs.WPVServiceFactory" );
416            SERVICE_FACTORIES_MAPPINGS.put( WMPSHandler.class, "org.deegree.ogcwebservices.wmps.WMPServiceFactory" );
417            SERVICE_FACTORIES_MAPPINGS.put( WPSHandler.class, "org.deegree.ogcwebservices.wps.WPServiceFactory" );
418            SERVICE_FACTORIES_MAPPINGS.put( WASSHandler.class, "org.deegree.ogcwebservices.wass.common.WASServiceFactory" );
419            SERVICE_FACTORIES_MAPPINGS.put( WCTSHandler.class, "org.deegree.ogcwebservices.wcts.WCTServiceFactory" );
420    
421            LOG.logInfo( "-------------------------------------------------------------------------------" );
422            LOG.logInfo( "Starting deegree version " + Version.getVersion() );
423            LOG.logInfo( "- context        : " + this.getServletContext().getServletContextName() );
424            LOG.logInfo( "- real path      : " + this.getServletContext().getRealPath( "/" ) );
425            LOG.logInfo( "- java version   : " + System.getProperty( "java.version" ) + "" );
426            LOG.logInfo( "- dom builder    : " + DocumentBuilderFactory.newInstance().getClass().getName() + "" );
427            LOG.logInfo( "- xslt builder   : " + TransformerFactory.newInstance().getClass().getName() + "" );
428            LOG.logInfo( "- system charset : " + CharsetUtils.getSystemCharset() );
429            LOG.logInfo( "- default charset: " + Charset.defaultCharset() );
430            LOG.logInfo( "- server info    : " + this.getServletContext().getServerInfo() );
431            logIfThere( "proxyHost" );
432            logIfThere( "proxyPort" );
433            logIfThere( "noProxyHosts" );
434            logIfThere( "nonProxyHosts" );
435            logIfThere( "http.proxyHost" );
436            logIfThere( "http.proxyPort" );
437            logIfThere( "http.noProxyHosts" );
438            logIfThere( "http.nonProxyHosts" );
439            logIfThere( "ftp.proxyHost" );
440            logIfThere( "ftp.proxyPort" );
441            logIfThere( "ftp.noProxyHosts" );
442            logIfThere( "ftp.nonProxyHosts" );
443            logIfThere( "https.proxyHost" );
444            logIfThere( "https.proxyPort" );
445            logIfThere( "https.noProxyHosts" );
446            logIfThere( "https.nonProxyHosts" );
447            try {
448                LOG.logInfo( "- ip             : " + InetAddress.getLocalHost().getHostAddress() );
449                LOG.logInfo( "- host name      : " + InetAddress.getLocalHost().getHostName() );
450                LOG.logInfo( "- domain name    : " + InetAddress.getLocalHost().getCanonicalHostName() );
451            } catch ( Exception e ) {
452                LOG.logError( e.getMessage(), e );
453            }
454            LOG.logInfo( "-------------------------------------------------------------------------------" );
455            this.initServices( getServletContext() );
456            checkServerCompatibility();
457            LOG.logInfo( "-------------------------------------------------------------------------------" );
458            String tmpServiceList = this.getServiceList();
459            if ( tmpServiceList != null && !( "".equals( tmpServiceList.trim() ) ) ) {
460                LOG.logInfo( "Initialized successfully (context '" + this.getServletContext().getServletContextName()
461                             + "'):" );
462                String[] tmpServices = tmpServiceList.split( "," );
463                for ( String service : tmpServices ) {
464                    // Added a check for the alternative service name, because it should not be outputed twice for the csw.
465                    if ( !OGCRequestFactory.CSW_SERVICE_NAME_EBRIM.toUpperCase().equals( service ) ) {
466                        LOG.logInfo( "- " + service );
467                    }
468                }
469            } else {
470                LOG.logError( "An Error occured while initializing context '"
471                              + this.getServletContext().getServletContextName() + "', no services are available." );
472            }
473    
474            LOG.logInfo( "-------------------------------------------------------------------------------" );
475            // Sets the attributes for tomcat -> application.getAttribute(); in jsp sites
476            this.getServletContext().setAttribute( "deegree_ogc_services", this.getServiceList() );
477        }
478    
479        private void checkServerCompatibility() {
480            String serverInfo = getServletContext().getServerInfo();
481            if ( "Apache Tomcat/5.5.26".equals( serverInfo ) || "Apache Tomcat/6.0.16".equals( serverInfo ) ) {
482                LOG.logWarning( "*******************************************************************************" );
483                LOG.logWarning( "YOU ARE RUNNING DEEGREE ON A TOMCAT RELEASE (" + serverInfo
484                                + ") THAT IS KNOWN TO HAVE A SERIOUS ISSUE WITH LARGE POST REQUESTS." );
485                LOG.logWarning( "PLEASE CONSIDER THE CORRESPONDING DEEGREE WIKI PAGE AT  https://wiki.deegree.org/deegreeWiki/ApacheTomcat "
486                                + "FOR DETAILS AND SWITCH TO A DIFFERENT TOMCAT VERSION." );
487                LOG.logWarning( "*******************************************************************************" );
488            }
489        }
490    
491        private void initServices( ServletContext context )
492                                throws ServletException {
493    
494            // get list of OGC services
495            String serviceList = this.getRequiredInitParameter( SERVICE );
496    
497            String[] serviceNames = StringTools.toArray( serviceList, ",", false );
498    
499            ServiceLookup lookup = ServiceLookup.getInstance();
500            for ( int i = 0; i < serviceNames.length; i++ ) {
501                LOG.logInfo( StringTools.concat( 100, "---- Initializing ", serviceNames[i].toUpperCase(), " ----" ) );
502                try {
503                    String className = this.getRequiredInitParameter( serviceNames[i] + HANDLER_CLASS );
504                    Class<?> handlerClzz = Class.forName( className );
505    
506                    // initialize each service factory
507                    String s = this.getRequiredInitParameter( serviceNames[i] + HANDLER_CONF );
508                    URL serviceConfigurationURL = WebappResourceResolver.resolveFileLocation( s, context, LOG );
509    
510                    // set configuration
511                    LOG.logInfo( StringTools.concat( 300, "Reading configuration for ", serviceNames[i].toUpperCase(),
512                                                     " from URL: '", serviceConfigurationURL, "'." ) );
513    
514                    String factoryClassName = SERVICE_FACTORIES_MAPPINGS.get( handlerClzz );
515    
516                    Class<?> factory = Class.forName( factoryClassName );
517                    Method method = factory.getMethod( "setConfiguration", new Class[] { URL.class } );
518                    method.invoke( factory, new Object[] { serviceConfigurationURL } );
519    
520                    // The csw-ebrim profile adds an alternative service name, it too is registred with the CSW handler.
521                    if ( "CSW".equals( serviceNames[i].toUpperCase() ) ) {
522                        lookup.addService( OGCRequestFactory.CSW_SERVICE_NAME_EBRIM.toUpperCase(), handlerClzz );
523                    }
524                    // put handler to available service list
525                    lookup.addService( serviceNames[i].toUpperCase(), handlerClzz );
526    
527                    LOG.logInfo( StringTools.concat( 300, serviceNames[i].toUpperCase(), " successfully initialized." ) );
528                } catch ( ServletException e ) {
529                    LOG.logError( e.getMessage(), e );
530                } catch ( InvocationTargetException e ) {
531                    e.getTargetException().printStackTrace();
532                    LOG.logError( this.produceMessage( ERR_MSG, new Object[] { serviceNames[i] } ), e );
533                } catch ( Exception e ) {
534                    LOG.logError( "Can't initialize OGC service:" + serviceNames[i], e );
535                }
536            }
537        }
538    
539        private String getRequiredInitParameter( String name )
540                                throws ServletException {
541            String paramValue = getInitParameter( name );
542            if ( paramValue == null ) {
543    
544                String msg = "Required init parameter '" + name + "' missing in web.xml";
545                LOG.logError( msg );
546                throw new ServletException( msg );
547            }
548            return paramValue;
549        }
550    
551        /**
552         * @return the services, separated by ","
553         */
554        private String getServiceList() {
555    
556            StringBuffer buf = new StringBuffer();
557            ServiceLookup lookup = ServiceLookup.getInstance();
558            for ( Iterator<?> iter = lookup.getIterator(); iter.hasNext(); ) {
559                String serviceName = (String) iter.next();
560                buf.append( serviceName );
561                if ( iter.hasNext() ) {
562                    buf.append( ',' );
563                }
564            }
565            return buf.toString();
566        }
567    
568        /**
569         * Formats the provided string and the args array into a String using MessageFormat.
570         *
571         * @param pattern
572         * @param args
573         * @return the message to present the client.
574         */
575        private String produceMessage( String pattern, Object[] args ) {
576            return new MessageFormat( pattern ).format( args );
577        }
578    
579        /**
580         * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
581         */
582        public void ctDestroyed() {
583            LOG.logInfo( "Stopping context: " );
584    
585            WMSConfigurationDocument.resetCapabilitiesCache();
586            WMSConfigurationDocument_1_3_0.resetCapabilitiesCache();
587            WMPSConfigurationDocument.resetCapabilitiesCache();
588    
589            ServiceLookup lookup = ServiceLookup.getInstance();
590            for ( Iterator<?> iter = lookup.getIterator(); iter.hasNext(); ) {
591                String serviceName = (String) iter.next();
592                LOG.logInfo( "Stopping service " + serviceName );
593    
594                try {
595                    String s = SERVICE_FACTORIES_MAPPINGS.get( lookup.getService( serviceName ) );
596                    Class<?> clzz = Class.forName( s );
597                    // TODO stop and reset all service instances
598                    Method[] methods = clzz.getMethods();
599                    for ( int j = 0; j < methods.length; j++ ) {
600                        if ( methods[j].getName().equals( "reset" ) ) {
601                            Object[] args = new Object[0];
602                            methods[j].invoke( clzz.newInstance(), args );
603                        }
604                    }
605                } catch ( Exception e ) {
606                    LOG.logError( e.getMessage(), e );
607                }
608            }
609        }
610    
611        @Override
612        public void destroy() {
613            super.destroy();
614            Enumeration<Driver> e = DriverManager.getDrivers();
615            while ( e.hasMoreElements() ) {
616                Driver driver = e.nextElement();
617                try {
618                    if ( driver.getClass().getClassLoader() == getClass().getClassLoader() )
619                        DriverManager.deregisterDriver( driver );
620                } catch ( SQLException e1 ) {
621                    LOG.logError( "Cannot unload driver: " + driver );
622                }
623            }
624            LogFactory.releaseAll();
625            LogManager.shutdown();
626            // SLF4JLogFactory.releaseAll(); // should be the same as the LogFactory.releaseAll call
627            Iterator<Class<?>> i = IIORegistry.getDefaultInstance().getCategories();
628            while ( i.hasNext() ) {
629                Class<?> c = i.next();
630                Iterator<?> k = IIORegistry.getDefaultInstance().getServiceProviders( c, false );
631                while ( k.hasNext() ) {
632                    Object o = k.next();
633                    if ( o.getClass().getClassLoader() == getClass().getClassLoader() ) {
634                        IIORegistry.getDefaultInstance().deregisterServiceProvider( o );
635                        LOG.logDebug( "Deregistering JAI driver ", o.getClass() );
636                    }
637                }
638            }
639            Introspector.flushCaches();
640            // just clear the configurations for now, it does not hurt
641            CRSConfiguration.DEFINED_CONFIGURATIONS.clear();
642        }
643    
644    }