public void releaseConnection(NHttpClientConnection conn) {
   if (conn == null) {
     return;
   }
   if (this.shutdown) {
     return;
   }
   synchronized (this.lock) {
     if (this.allConns.contains(conn)) {
       if (conn.isOpen()) {
         conn.setSocketTimeout(0);
         AsyncConnectionRequest request = this.pendingRequests.poll();
         if (request != null) {
           System.out.println("Re-using persistent connection");
           request.setConnection(conn);
         } else {
           this.availableConns.add(conn);
         }
       } else {
         this.allConns.remove(conn);
         processRequests();
       }
     }
   }
 }
 public AsyncConnectionRequest requestConnection() {
   if (this.shutdown) {
     throw new IllegalStateException("Connection manager has been shut down");
   }
   AsyncConnectionRequest request = new AsyncConnectionRequest();
   synchronized (this.lock) {
     while (!this.availableConns.isEmpty()) {
       NHttpClientConnection conn = this.availableConns.remove();
       if (conn.isOpen()) {
         System.out.println("Re-using persistent connection");
         request.setConnection(conn);
         break;
       } else {
         this.allConns.remove(conn);
       }
     }
     if (!request.isCompleted()) {
       this.pendingRequests.add(request);
       processRequests();
     }
   }
   return request;
 }
  public static void main(String[] args) throws Exception {
    HttpParams params = new BasicHttpParams();
    params
        .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
        .setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000)
        .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
        .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
        .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
        .setParameter(CoreProtocolPNames.USER_AGENT, "HttpComponents/1.1");

    BasicHttpProcessor httpproc = new BasicHttpProcessor();
    httpproc.addInterceptor(new RequestContent());
    httpproc.addInterceptor(new RequestTargetHost());
    httpproc.addInterceptor(new RequestConnControl());
    httpproc.addInterceptor(new RequestUserAgent());
    httpproc.addInterceptor(new RequestExpectContinue());

    // Set up protocol handler
    BufferingHttpClientHandler protocolHandler =
        new BufferingHttpClientHandler(
            httpproc,
            new MyHttpRequestExecutionHandler(),
            new DefaultConnectionReuseStrategy(),
            params);
    protocolHandler.setEventListener(new EventLogger());

    // Limit the total maximum of concurrent connections to 5
    int maxTotalConnections = 5;

    // Use the connection manager to maintain a pool of connections to localhost:8080
    final AsyncConnectionManager connMgr =
        new AsyncConnectionManager(
            new HttpHost("localhost", 8080), maxTotalConnections, protocolHandler, params);

    // Start the I/O reactor in a separate thread
    Thread t =
        new Thread(
            new Runnable() {

              public void run() {
                try {
                  connMgr.execute(); // The connection manager wraps the I/O reactor.
                } catch (InterruptedIOException ex) {
                  System.err.println("Interrupted");
                } catch (IOException e) {
                  System.err.println("I/O error: " + e.getMessage());
                }
                System.out.println("I/O reactor terminated");
              }
            });
    t.start();

    // Submit 50 requests using maximum 5 concurrent connections
    Queue<RequestHandle> queue = new LinkedList<RequestHandle>();
    for (int i = 0; i < 50; i++) {
      AsyncConnectionRequest connRequest =
          connMgr.requestConnection(); // Get a working connection from the connection manager.
      connRequest
          .waitFor(); // Wait for the connection request to be completed to the target authority.
      NHttpClientConnection conn =
          connRequest.getConnection(); // Get the real connection from the connection request.
      if (conn == null) {
        System.err.println("Failed to obtain connection");
        break;
      }

      HttpContext context = conn.getContext();
      BasicHttpRequest httpget = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
      RequestHandle handle = new RequestHandle(connMgr, conn);

      context.setAttribute("request", httpget);
      context.setAttribute("request-handle", handle);

      queue.add(handle);
      conn.requestOutput();
    }

    // Wait until all requests have been completed
    while (!queue.isEmpty()) {
      RequestHandle handle = queue.remove();
      handle.waitFor();
    }

    // Give the I/O reactor 10 sec to shut down
    connMgr.shutdown(10000);
    System.out.println("Done");
  }
  /**
   * Send the request message asynchronously to the given EPR
   *
   * @param epr the destination EPR for the message
   * @param msgContext the message being sent
   * @throws AxisFault on error
   */
  private void sendAsyncRequest(EndpointReference epr, MessageContext msgContext) throws AxisFault {
    try {
      URL url = new URL(epr.getAddress());
      String scheme = url.getProtocol() != null ? url.getProtocol() : "http";
      String hostname = url.getHost();
      int port = url.getPort();
      if (port == -1) {
        // use default
        if ("http".equals(scheme)) {
          port = 80;
        } else if ("https".equals(scheme)) {
          port = 443;
        }
      }
      HttpHost target = new HttpHost(hostname, port, scheme);
      boolean secure = "https".equalsIgnoreCase(target.getSchemeName());

      HttpHost proxy = proxyConfig.selectProxy(target);

      HttpRoute route;
      if (proxy != null) {
        route = new HttpRoute(target, null, proxy, secure);
      } else {
        route = new HttpRoute(target, null, secure);
      }
      Axis2HttpRequest axis2Req = new Axis2HttpRequest(epr, route, msgContext);
      Object timeout = msgContext.getProperty(NhttpConstants.SEND_TIMEOUT);
      if (timeout != null && timeout instanceof Long) {
        axis2Req.setTimeout((int) ((Long) timeout).longValue());
      }

      NHttpClientConnection conn = connpool.getConnection(route);

      // Ensure MessageContext has a ClientConnectionDebug attached before we start streaming
      ServerConnectionDebug scd =
          (ServerConnectionDebug) msgContext.getProperty(ServerHandler.SERVER_CONNECTION_DEBUG);

      ClientConnectionDebug ccd;
      if (scd != null) {
        ccd = scd.getClientConnectionDebug();
        if (ccd == null) {
          ccd = new ClientConnectionDebug(scd);
          scd.setClientConnectionDebug(ccd);
        }
        ccd.recordRequestStartTime(conn, axis2Req);
        msgContext.setProperty(ClientHandler.CLIENT_CONNECTION_DEBUG, ccd);
      }

      if (conn == null) {
        HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
        ioReactor.connect(
            new InetSocketAddress(host.getHostName(), host.getPort()),
            null,
            axis2Req,
            sessionRequestCallback);
        if (log.isDebugEnabled()) {
          log.debug("A new connection established to : " + route);
        }
      } else {
        conn.setSocketTimeout(socketTimeout); // reinitialize timeouts for the pooled connection
        try {
          handler.submitRequest(conn, axis2Req);
          if (log.isDebugEnabled()) {
            log.debug("An existing connection reused to : " + hostname + ":" + port);
          }
        } catch (ConnectionClosedException e) {
          ioReactor.connect(
              new InetSocketAddress(hostname, port), null, axis2Req, sessionRequestCallback);
          if (log.isDebugEnabled()) {
            log.debug("A new connection established to : " + hostname + ":" + port);
          }
        }
      }
      try {
        axis2Req.streamMessageContents();
      } catch (AxisFault af) {
        throw af;
      }

    } catch (MalformedURLException e) {
      handleException("Malformed destination EPR : " + epr.getAddress(), e);
    }
  }