/**
   * Invokes the next filter in the chain or the final servlet at the end of the chain.
   *
   * @param request the servlet request
   * @param response the servlet response
   * @since Servlet 2.3
   */
  @Override
  public void doFilter(ServletRequest request, ServletResponse response)
      throws ServletException, IOException {
    Thread thread = Thread.currentThread();
    ClassLoader oldLoader = thread.getContextClassLoader();

    WebApp webApp = _webApp;

    UserTransactionImpl ut = null;
    if (_isTop) ut = _utm.getUserTransaction();

    try {
      thread.setContextClassLoader(webApp.getClassLoader());

      if (!webApp.enterWebApp() && webApp.getConfigException() == null) {
        if (response instanceof HttpServletResponse) {
          HttpServletResponse res = (HttpServletResponse) response;

          res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
        }

        return;
      }

      _next.doFilter(request, response);
    } catch (Throwable e) {
      _errorPageManager.sendServletError(e, request, response);
    } finally {
      webApp.exitWebApp();

      // put finish() before access log so the session isn't tied up while
      // logging

      // needed for things like closing the session
      if (request instanceof HttpServletRequestImpl)
        ((HttpServletRequestImpl) request).finishInvocation();

      // server/1ld5
      if (_isTop) {
        ((CauchoResponse) response).close();

        try {
          if (ut != null) ut.abortTransaction();
        } catch (Throwable e) {
          log.log(Level.WARNING, e.toString(), e);
        }
      }

      thread.setContextClassLoader(oldLoader);
    }
  }
  /** Finds the pool item joined to this one. return null. */
  ManagedPoolItem findJoin(UserTransactionImpl uTrans, ManagedPoolItem item) {
    if (!uTrans.isActive()) return null;

    ArrayList<ManagedXAResource> poolItems = uTrans.getXaResources();
    int length = poolItems.size();

    for (int i = 0; i < length; i++) {
      ManagedXAResource resource = poolItems.get(i);

      if (resource instanceof ManagedPoolItem) {
        ManagedPoolItem poolItem = (ManagedPoolItem) resource;

        if (poolItem.isJoin(item)) return poolItem;
      }
    }

    return null;
  }
  /** Allocates a resource matching the parameters. If none matches, return null. */
  private UserPoolItem allocateShared(
      UserTransactionImpl transaction,
      ManagedConnectionFactory mcf,
      Subject subject,
      ConnectionRequestInfo info) {
    if (!transaction.isActive()) return null;

    ArrayList<ManagedXAResource> poolItems = transaction.getXaResources();
    int length = poolItems.size();

    for (int i = 0; i < length; i++) {
      ManagedXAResource xaResource = poolItems.get(i);

      if (xaResource instanceof ManagedPoolItem) {
        ManagedPoolItem poolItem = (ManagedPoolItem) xaResource;

        UserPoolItem item = poolItem.allocateXA(mcf, subject, info);

        if (item != null) return item;
      }
    }

    return null;
  }