/**
   * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
   */
  public void ctDestroyed() {
    LOG.logInfo("Stopping context: ");

    WMSConfigurationDocument.resetCapabilitiesCache();
    WMSConfigurationDocument_1_3_0.resetCapabilitiesCache();
    WMPSConfigurationDocument.resetCapabilitiesCache();

    ServiceLookup lookup = ServiceLookup.getInstance();
    for (Iterator<?> iter = lookup.getIterator(); iter.hasNext(); ) {
      String serviceName = (String) iter.next();
      LOG.logInfo("Stopping service " + serviceName);

      try {
        String s = SERVICE_FACTORIES_MAPPINGS.get(lookup.getService(serviceName));
        Class<?> clzz = Class.forName(s);
        // TODO stop and reset all service instances
        Method[] methods = clzz.getMethods();
        for (int j = 0; j < methods.length; j++) {
          if (methods[j].getName().equals("reset")) {
            Object[] args = new Object[0];
            methods[j].invoke(clzz.newInstance(), args);
          }
        }
      } catch (Exception e) {
        LOG.logError(e.getMessage(), e);
      }
    }
  }
  private void initServices(ServletContext context) throws ServletException {

    // get list of OGC services
    String serviceList = this.getRequiredInitParameter(SERVICE);

    String[] serviceNames = StringTools.toArray(serviceList, ",", false);

    ServiceLookup lookup = ServiceLookup.getInstance();
    for (int i = 0; i < serviceNames.length; i++) {
      LOG.logInfo(
          StringTools.concat(100, "---- Initializing ", serviceNames[i].toUpperCase(), " ----"));
      try {
        String className = this.getRequiredInitParameter(serviceNames[i] + HANDLER_CLASS);
        Class<?> handlerClzz = Class.forName(className);

        // initialize each service factory
        String s = this.getRequiredInitParameter(serviceNames[i] + HANDLER_CONF);
        URL serviceConfigurationURL = WebappResourceResolver.resolveFileLocation(s, context, LOG);

        // set configuration
        LOG.logInfo(
            StringTools.concat(
                300,
                "Reading configuration for ",
                serviceNames[i].toUpperCase(),
                " from URL: '",
                serviceConfigurationURL,
                "'."));

        String factoryClassName = SERVICE_FACTORIES_MAPPINGS.get(handlerClzz);

        Class<?> factory = Class.forName(factoryClassName);
        Method method = factory.getMethod("setConfiguration", new Class[] {URL.class});
        method.invoke(factory, new Object[] {serviceConfigurationURL});

        // The csw-ebrim profile adds an alternative service name, it too is registred with the CSW
        // handler.
        if ("CSW".equals(serviceNames[i].toUpperCase())) {
          lookup.addService(OGCRequestFactory.CSW_SERVICE_NAME_EBRIM.toUpperCase(), handlerClzz);
        }
        // put handler to available service list
        lookup.addService(serviceNames[i].toUpperCase(), handlerClzz);

        LOG.logInfo(
            StringTools.concat(300, serviceNames[i].toUpperCase(), " successfully initialized."));
      } catch (ServletException e) {
        LOG.logError(e.getMessage(), e);
      } catch (InvocationTargetException e) {
        e.getTargetException().printStackTrace();
        LOG.logError(this.produceMessage(ERR_MSG, new Object[] {serviceNames[i]}), e);
      } catch (Exception e) {
        LOG.logError("Can't initialize OGC service:" + serviceNames[i], e);
      }
    }
  }
  /** @return the services, separated by "," */
  private String getServiceList() {

    StringBuffer buf = new StringBuffer();
    ServiceLookup lookup = ServiceLookup.getInstance();
    for (Iterator<?> iter = lookup.getIterator(); iter.hasNext(); ) {
      String serviceName = (String) iter.next();
      buf.append(serviceName);
      if (iter.hasNext()) {
        buf.append(',');
      }
    }
    return buf.toString();
  }
  /**
   * @param request
   * @param response @TODO refactor and optimize code for initializing handler
   */
  public void doService(HttpServletRequest request, HttpServletResponse response) {
    if (response.isCommitted()) {
      LOG.logWarning("The response object is already committed!");
    }

    long startTime = System.currentTimeMillis();
    address = request.getRequestURL().toString();

    String service = null;
    try {
      OGCWebServiceRequest ogcRequest = OGCRequestFactory.create(request);

      LOG.logInfo(
          StringTools.concat(
              500,
              "Handling request '",
              ogcRequest.getId(),
              "' from '",
              request.getRemoteAddr(),
              "' to service: '",
              ogcRequest.getServiceName(),
              "'"));

      // get service from request
      service = ogcRequest.getServiceName().toUpperCase();

      // get handler instance
      ServiceDispatcher handler =
          ServiceLookup.getInstance().getHandler(service, request.getRemoteAddr());
      // dispatch request to specific handler
      handler.perform(ogcRequest, response);
    } catch (OGCWebServiceException e) {
      LOG.logError(e.getMessage(), e);
      sendException(response, e, request, service);
    } catch (ServiceException e) {
      if (e.getNestedException() instanceof OGCWebServiceException) {
        sendException(response, (OGCWebServiceException) e.getNestedException(), request, service);
      } else {
        sendException(
            response,
            new OGCWebServiceException(this.getClass().getName(), e.getMessage()),
            request,
            service);
      }
      LOG.logError(e.getMessage(), e);
    } catch (Exception e) {
      sendException(
          response,
          new OGCWebServiceException(this.getClass().getName(), e.getMessage()),
          request,
          service);
      LOG.logError(e.getMessage(), e);
    }
    if (LOG.isDebug()) {
      LOG.logDebug(
          "OGCServletController: request performed in "
              + Long.toString(System.currentTimeMillis() - startTime)
              + " milliseconds.");
    }
  }