@Override
 public void sessionDestroyed(HttpSessionEvent se) {
   // Close all Comet connections associated with this session
   Request[] reqs = (Request[]) se.getSession().getAttribute(cometRequestsAttribute);
   if (reqs != null) {
     for (int i = 0; i < reqs.length; i++) {
       Request req = reqs[i];
       try {
         CometEventImpl event = req.getEvent();
         event.setEventType(CometEvent.EventType.END);
         event.setEventSubType(CometEvent.EventSubType.SESSION_END);
         ((CometProcessor) req.getWrapper().getServlet()).event(event);
         event.close();
       } catch (Exception e) {
         req.getWrapper()
             .getParent()
             .getLogger()
             .warn(sm.getString("cometConnectionManagerValve.listenerEvent"), e);
       }
     }
   }
 }
  /**
   * Handle the HTTP status code (and corresponding message) generated while processing the
   * specified Request to produce the specified Response. Any exceptions that occur during
   * generation of the error report are logged and swallowed.
   *
   * @param request The request being processed
   * @param response The response being generated
   */
  private void status(Request request, Response response) {

    int statusCode = response.getStatus();

    // Handle a custom error page for this status code
    Context context = request.getContext();
    if (context == null) return;

    /* Only look for error pages when isError() is set.
     * isError() is set when response.sendError() is invoked. This
     * allows custom error pages without relying on default from
     * web.xml.
     */
    if (!response.isError()) return;

    ErrorPage errorPage = context.findErrorPage(statusCode);
    if (errorPage == null) {
      // Look for a default error page
      errorPage = context.findErrorPage(0);
    }
    if (errorPage != null && response.setErrorReported()) {
      response.setAppCommitted(false);
      request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, Integer.valueOf(statusCode));

      String message = response.getMessage();
      if (message == null) message = "";
      request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
      request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation());
      request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR);

      Wrapper wrapper = request.getWrapper();
      if (wrapper != null)
        request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName());
      request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
      if (custom(request, response, errorPage)) {
        try {
          response.finishResponse();
        } catch (ClientAbortException e) {
          // Ignore
        } catch (IOException e) {
          container.getLogger().warn("Exception Processing " + errorPage, e);
        }
      }
    }
  }
  /**
   * Handle the specified Throwable encountered while processing the specified Request to produce
   * the specified Response. Any exceptions that occur during generation of the exception report are
   * logged and swallowed.
   *
   * @param request The request being processed
   * @param response The response being generated
   * @param throwable The exception that occurred (which possibly wraps a root cause exception
   */
  protected void throwable(Request request, Response response, Throwable throwable) {
    Context context = request.getContext();
    if (context == null) return;

    Throwable realError = throwable;

    if (realError instanceof ServletException) {
      realError = ((ServletException) realError).getRootCause();
      if (realError == null) {
        realError = throwable;
      }
    }

    // If this is an aborted request from a client just log it and return
    if (realError instanceof ClientAbortException) {
      if (log.isDebugEnabled()) {
        log.debug(sm.getString("standardHost.clientAbort", realError.getCause().getMessage()));
      }
      return;
    }

    ErrorPage errorPage = findErrorPage(context, throwable);
    if ((errorPage == null) && (realError != throwable)) {
      errorPage = findErrorPage(context, realError);
    }

    if (errorPage != null) {
      if (response.setErrorReported()) {
        response.setAppCommitted(false);
        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation());
        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR);
        request.setAttribute(
            RequestDispatcher.ERROR_STATUS_CODE,
            new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        request.setAttribute(RequestDispatcher.ERROR_MESSAGE, throwable.getMessage());
        request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, realError);
        Wrapper wrapper = request.getWrapper();
        if (wrapper != null)
          request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName());
        request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
        request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, realError.getClass());
        if (custom(request, response, errorPage)) {
          try {
            response.finishResponse();
          } catch (IOException e) {
            container.getLogger().warn("Exception Processing " + errorPage, e);
          }
        }
      }
    } else {
      // A custom error-page has not been defined for the exception
      // that was thrown during request processing. Check if an
      // error-page for error code 500 was specified and if so,
      // send that page back as the response.
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      // The response is an error
      response.setError();

      status(request, response);
    }
  }