You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2011/09/13 10:35:03 UTC

svn commit: r1170086 - in /httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src: main/java/org/apache/http/impl/nio/client/ main/java/org/apache/http/impl/nio/conn/ main/java/org/apache/http/nio/client/methods/ test/...

Author: olegk
Date: Tue Sep 13 08:35:03 2011
New Revision: 1170086

URL: http://svn.apache.org/viewvc?rev=1170086&view=rev
Log:
Added support for stateful connections to DefaultHttpAsyncClient

Added:
    httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java   (with props)
Modified:
    httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractHttpAsyncClient.java
    httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/DefaultAsyncRequestDirector.java
    httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/ManagedClientConnectionImpl.java
    httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/nio/client/methods/ZeroCopyConsumer.java
    httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/nio/client/methods/TestAsyncConsumers.java

Modified: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractHttpAsyncClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractHttpAsyncClient.java?rev=1170086&r1=1170085&r2=1170086&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractHttpAsyncClient.java (original)
+++ httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractHttpAsyncClient.java Tue Sep 13 08:35:03 2011
@@ -46,6 +46,7 @@ import org.apache.http.client.ClientProt
 import org.apache.http.client.CookieStore;
 import org.apache.http.client.CredentialsProvider;
 import org.apache.http.client.RedirectStrategy;
+import org.apache.http.client.UserTokenHandler;
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.client.params.AuthPolicy;
 import org.apache.http.client.params.CookiePolicy;
@@ -67,6 +68,7 @@ import org.apache.http.impl.client.Defau
 import org.apache.http.impl.client.DefaultProxyAuthenticationHandler;
 import org.apache.http.impl.client.DefaultRedirectStrategy;
 import org.apache.http.impl.client.DefaultTargetAuthenticationHandler;
+import org.apache.http.impl.client.DefaultUserTokenHandler;
 import org.apache.http.impl.cookie.BestMatchSpecFactory;
 import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
 import org.apache.http.impl.cookie.IgnoreSpecFactory;
@@ -114,6 +116,7 @@ public abstract class AbstractHttpAsyncC
     private AuthenticationHandler proxyAuthHandler;
     private CredentialsProvider credsProvider;
     private HttpRoutePlanner routePlanner;
+    private UserTokenHandler userTokenHandler;
     private HttpParams params;
 
     private volatile boolean terminated;
@@ -224,6 +227,10 @@ public abstract class AbstractHttpAsyncC
         return new DefaultHttpAsyncRoutePlanner(getConnectionManager().getSchemeRegistry());
     }
 
+    protected UserTokenHandler createUserTokenHandler() {
+        return new DefaultUserTokenHandler();
+    }
+
     public synchronized final HttpParams getParams() {
         if (this.params == null) {
             this.params = createHttpParams();
@@ -351,6 +358,18 @@ public abstract class AbstractHttpAsyncC
         this.routePlanner = routePlanner;
     }
 
+    public synchronized final UserTokenHandler getUserTokenHandler() {
+        if (this.userTokenHandler == null) {
+            this.userTokenHandler = createUserTokenHandler();
+        }
+        return this.userTokenHandler;
+    }
+
+
+    public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
+        this.userTokenHandler = userTokenHandler;
+    }
+
     protected synchronized final BasicHttpProcessor getHttpProcessor() {
         if (this.mutableProcessor == null) {
             this.mutableProcessor = createHttpProcessor();
@@ -510,6 +529,7 @@ public abstract class AbstractHttpAsyncC
                     getRedirectStrategy(),
                     getTargetAuthenticationHandler(),
                     getProxyAuthenticationHandler(),
+                    getUserTokenHandler(),
                     getParams());
         }
         this.queue.add(httpexchange);

Modified: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/DefaultAsyncRequestDirector.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/DefaultAsyncRequestDirector.java?rev=1170086&r1=1170085&r2=1170086&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/DefaultAsyncRequestDirector.java (original)
+++ httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/DefaultAsyncRequestDirector.java Tue Sep 13 08:35:03 2011
@@ -57,6 +57,7 @@ import org.apache.http.client.Credential
 import org.apache.http.client.NonRepeatableRequestException;
 import org.apache.http.client.RedirectException;
 import org.apache.http.client.RedirectStrategy;
+import org.apache.http.client.UserTokenHandler;
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.client.params.ClientPNames;
 import org.apache.http.client.params.HttpClientParams;
@@ -107,6 +108,7 @@ class DefaultAsyncRequestDirector<T> imp
     private final RedirectStrategy redirectStrategy;
     private final AuthenticationHandler targetAuthHandler;
     private final AuthenticationHandler proxyAuthHandler;
+    private final UserTokenHandler userTokenHandler;
     private final AuthState targetAuthState;
     private final AuthState proxyAuthState;
     private final HttpParams clientParams;
@@ -140,6 +142,7 @@ class DefaultAsyncRequestDirector<T> imp
             final RedirectStrategy redirectStrategy,
             final AuthenticationHandler targetAuthHandler,
             final AuthenticationHandler proxyAuthHandler,
+            final UserTokenHandler userTokenHandler,
             final HttpParams clientParams) {
         super();
         this.log = log;
@@ -156,6 +159,7 @@ class DefaultAsyncRequestDirector<T> imp
         this.routeDirector = new BasicRouteDirector();
         this.targetAuthHandler = targetAuthHandler;
         this.proxyAuthHandler = proxyAuthHandler;
+        this.userTokenHandler = userTokenHandler;
         this.targetAuthState = new AuthState();
         this.proxyAuthState = new AuthState();
         this.clientParams = clientParams;
@@ -304,6 +308,15 @@ class DefaultAsyncRequestDirector<T> imp
             if (this.followup == null) {
                 this.finalResponse = response;
             }
+
+            Object userToken = this.localContext.getAttribute(ClientContext.USER_TOKEN);
+            if (managedConn != null && userToken == null) {
+                userToken = userTokenHandler.getUserToken(this.localContext);
+                if (userToken != null) {
+                    this.localContext.setAttribute(ClientContext.USER_TOKEN, userToken);
+                    managedConn.setState(userToken);
+                }
+            }
         }
         if (this.finalResponse != null) {
             this.responseConsumer.responseReceived(response);
@@ -383,8 +396,6 @@ class DefaultAsyncRequestDirector<T> imp
                 }
                 this.managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
             } else {
-                this.managedConn.unmarkReusable();
-                releaseConnection();
                 invalidateAuthIfSuccessful(this.proxyAuthState);
                 invalidateAuthIfSuccessful(this.targetAuthState);
             }
@@ -392,6 +403,7 @@ class DefaultAsyncRequestDirector<T> imp
             if (this.finalResponse != null) {
                 this.responseConsumer.responseCompleted(this.localContext);
                 this.log.debug("Response processed");
+                releaseConnection();
                 T result = this.responseConsumer.getResult();
                 Exception ex = this.responseConsumer.getException();
                 if (ex == null) {
@@ -399,7 +411,6 @@ class DefaultAsyncRequestDirector<T> imp
                 } else {
                     this.resultCallback.failed(ex, this);
                 }
-                releaseConnection();
             } else {
                 if (this.followup != null) {
                     HttpRoute actualRoute = this.mainRequest.getRoute();
@@ -409,6 +420,9 @@ class DefaultAsyncRequestDirector<T> imp
                     }
                     this.mainRequest = this.followup;
                 }
+                if (this.managedConn != null && !this.managedConn.isOpen()) {
+                    releaseConnection();
+                }
                 if (this.managedConn != null) {
                     this.managedConn.requestOutput();
                 } else {

Modified: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/ManagedClientConnectionImpl.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/ManagedClientConnectionImpl.java?rev=1170086&r1=1170085&r2=1170086&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/ManagedClientConnectionImpl.java (original)
+++ httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/ManagedClientConnectionImpl.java Tue Sep 13 08:35:03 2011
@@ -404,4 +404,13 @@ class ManagedClientConnectionImpl implem
         this.poolEntry = null;
     }
 
+    @Override
+    public synchronized String toString() {
+        if (this.poolEntry != null) {
+            return this.poolEntry.toString();
+        } else {
+            return "released";
+        }
+    }
+
 }

Modified: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/nio/client/methods/ZeroCopyConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/nio/client/methods/ZeroCopyConsumer.java?rev=1170086&r1=1170085&r2=1170086&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/nio/client/methods/ZeroCopyConsumer.java (original)
+++ httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/main/java/org/apache/http/nio/client/methods/ZeroCopyConsumer.java Tue Sep 13 08:35:03 2011
@@ -39,6 +39,7 @@ import org.apache.http.nio.FileContentDe
 import org.apache.http.nio.IOControl;
 import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
 import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
 
 public abstract class ZeroCopyConsumer<T> extends AbstractAsyncResponseConsumer<T> {
 
@@ -89,7 +90,7 @@ public abstract class ZeroCopyConsumer<T
     protected abstract T process(final HttpResponse response, final File file) throws Exception;
 
     @Override
-    protected T buildResult() throws Exception {
+    protected T buildResult(final HttpContext context) throws Exception {
         FileEntity entity = new FileEntity(this.file);
         entity.setContentType(this.response.getFirstHeader(HTTP.CONTENT_TYPE));
         this.response.setEntity(entity);

Added: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java?rev=1170086&view=auto
==============================================================================
--- httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java (added)
+++ httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java Tue Sep 13 08:35:03 2011
@@ -0,0 +1,338 @@
+/*
+ * ====================================================================
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.http.impl.nio.client;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Future;
+
+import org.apache.http.HttpAsyncTestBase;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.nio.DefaultNHttpServerConnectionFactory;
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.NHttpConnectionFactory;
+import org.apache.http.nio.NHttpServerIOTarget;
+import org.apache.http.nio.client.HttpAsyncClient;
+import org.apache.http.nio.conn.ManagedClientConnection;
+import org.apache.http.nio.entity.NStringEntity;
+import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
+import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
+import org.apache.http.nio.protocol.BufferingAsyncRequestHandler;
+import org.apache.http.nio.protocol.HttpAsyncExpectationVerifier;
+import org.apache.http.nio.protocol.HttpAsyncRequestHandlerRegistry;
+import org.apache.http.nio.protocol.HttpAsyncRequestHandlerResolver;
+import org.apache.http.nio.protocol.HttpAsyncServiceHandler;
+import org.apache.http.nio.reactor.IOReactorStatus;
+import org.apache.http.nio.reactor.ListenerEndpoint;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.SyncBasicHttpContext;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestStatefulConnManagement extends HttpAsyncTestBase {
+
+    @Before
+    public void setUp() throws Exception {
+        initServer();
+        initClient();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        shutDownClient();
+        shutDownServer();
+    }
+
+    @Override
+    protected NHttpConnectionFactory<NHttpServerIOTarget> createServerConnectionFactory(
+            final HttpParams params) throws Exception {
+        return new DefaultNHttpServerConnectionFactory(params);
+    }
+
+    @Override
+    protected String getSchemeName() {
+        return "http";
+    }
+
+    private HttpHost start(
+            final HttpAsyncRequestHandlerResolver requestHandlerResolver,
+            final HttpAsyncExpectationVerifier expectationVerifier) throws Exception {
+        HttpAsyncServiceHandler serviceHandler = new HttpAsyncServiceHandler(
+                requestHandlerResolver,
+                expectationVerifier,
+                this.serverHttpProc,
+                new DefaultConnectionReuseStrategy(),
+                this.serverParams);
+        this.server.start(serviceHandler);
+        this.httpclient.start();
+
+        ListenerEndpoint endpoint = this.server.getListenerEndpoint();
+        endpoint.waitFor();
+
+        Assert.assertEquals("Test server status", IOReactorStatus.ACTIVE, this.server.getStatus());
+        InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
+        HttpHost target = new HttpHost("localhost", address.getPort(), getSchemeName());
+        return target;
+    }
+
+    static class SimpleService implements HttpRequestHandler {
+
+        public SimpleService() {
+            super();
+        }
+
+        public void handle(
+                final HttpRequest request,
+                final HttpResponse response,
+                final HttpContext context) throws HttpException, IOException {
+            response.setStatusCode(HttpStatus.SC_OK);
+            NStringEntity entity = new NStringEntity("Whatever");
+            response.setEntity(entity);
+        }
+    }
+
+    @Test
+    public void testStatefulConnections() throws Exception {
+        this.httpclient.setUserTokenHandler(new UserTokenHandler() {
+
+            public Object getUserToken(final HttpContext context) {
+                Integer id = (Integer) context.getAttribute("user");
+                return id;
+            }
+
+        });
+
+        HttpAsyncRequestHandlerRegistry registry = new HttpAsyncRequestHandlerRegistry();
+        registry.register("*", new BufferingAsyncRequestHandler(new SimpleService()));
+
+        HttpHost target = start(registry, null);
+
+        int workerCount = 2;
+        int requestCount = 5;
+
+        HttpParams params = new BasicHttpParams();
+        HttpConnectionParams.setConnectionTimeout(params, 10);
+
+        HttpContext[] contexts = new HttpContext[workerCount];
+        HttpWorker[] workers = new HttpWorker[workerCount];
+        for (int i = 0; i < contexts.length; i++) {
+            HttpContext context = new SyncBasicHttpContext();
+            Object token = Integer.valueOf(i);
+            context.setAttribute("user", token);
+            contexts[i] = context;
+            workers[i] = new HttpWorker(context, requestCount, target, this.httpclient);
+        }
+
+        for (int i = 0; i < workers.length; i++) {
+            workers[i].start();
+        }
+        for (int i = 0; i < workers.length; i++) {
+            workers[i].join(10000);
+        }
+        for (int i = 0; i < workers.length; i++) {
+            Exception ex = workers[i].getException();
+            if (ex != null) {
+                throw ex;
+            }
+            Assert.assertEquals(requestCount, workers[i].getCount());
+        }
+
+        for (int i = 0; i < contexts.length; i++) {
+            HttpContext context = contexts[i];
+            Integer id = (Integer) context.getAttribute("user");
+
+            for (int r = 0; r < requestCount; r++) {
+                Integer state = (Integer) context.getAttribute("r" + r);
+                Assert.assertEquals(id, state);
+            }
+        }
+
+    }
+
+    static class HttpWorker extends Thread {
+
+        private final HttpContext context;
+        private final int requestCount;
+        private final HttpHost target;
+        private final HttpAsyncClient httpclient;
+
+        private volatile Exception exception;
+        private volatile int count;
+
+        public HttpWorker(
+                final HttpContext context,
+                int requestCount,
+                final HttpHost target,
+                final HttpAsyncClient httpclient) {
+            super();
+            this.context = context;
+            this.requestCount = requestCount;
+            this.target = target;
+            this.httpclient = httpclient;
+            this.count = 0;
+        }
+
+        public int getCount() {
+            return this.count;
+        }
+
+        public Exception getException() {
+            return this.exception;
+        }
+
+        @Override
+        public void run() {
+            try {
+                for (int r = 0; r < this.requestCount; r++) {
+                    HttpGet httpget = new HttpGet("/");
+                    Future<Object> future = this.httpclient.execute(
+                            new BasicAsyncRequestProducer(this.target, httpget),
+                            new AbstractAsyncResponseConsumer<Object>() {
+
+                                @Override
+                                protected void onResponseReceived(final HttpResponse response) {
+                                }
+
+                                @Override
+                                protected void onContentReceived(
+                                        final ContentDecoder decoder,
+                                        final IOControl ioctrl) throws IOException {
+                                    ByteBuffer buf = ByteBuffer.allocate(2048);
+                                    decoder.read(buf);
+                                }
+
+                                @Override
+                                protected Object buildResult(final HttpContext context) throws Exception {
+                                    ManagedClientConnection conn = (ManagedClientConnection) context.getAttribute(
+                                            ExecutionContext.HTTP_CONNECTION);
+                                    return conn.getState();
+                                }
+
+                                @Override
+                                protected void releaseResources() {
+                                }
+
+                            },
+                            this.context,
+                            null);
+                    this.count++;
+                    Object state = future.get();
+                    this.context.setAttribute("r" + r, state);
+                }
+
+            } catch (Exception ex) {
+                this.exception = ex;
+            }
+        }
+
+    }
+
+    @Test
+    public void testRouteSpecificPoolRecylcing() throws Exception {
+        // This tests what happens when a maxed connection pool needs
+        // to kill the last idle connection to a route to build a new
+        // one to the same route.
+        this.httpclient.setUserTokenHandler(new UserTokenHandler() {
+
+            public Object getUserToken(final HttpContext context) {
+                return context.getAttribute("user");
+            }
+
+        });
+
+        int maxConn = 2;
+        // We build a client with 2 max active // connections, and 2 max per route.
+        this.connMgr.setMaxTotal(maxConn);
+        this.connMgr.setDefaultMaxPerRoute(maxConn);
+
+        HttpAsyncRequestHandlerRegistry registry = new HttpAsyncRequestHandlerRegistry();
+        registry.register("*", new BufferingAsyncRequestHandler(new SimpleService()));
+
+        HttpHost target = start(registry, null);
+
+        // Bottom of the pool : a *keep alive* connection to Route 1.
+        HttpContext context1 = new SyncBasicHttpContext();
+        context1.setAttribute("user", "stuff");
+
+        Future<HttpResponse> future1 = this.httpclient.execute(
+                target, new HttpGet("/"), context1, null);
+        HttpResponse response1 = future1.get();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getStatusLine().getStatusCode());
+
+        // The ConnPoolByRoute now has 1 free connection, out of 2 max
+        // The ConnPoolByRoute has one RouteSpcfcPool, that has one free connection
+        // for [localhost][stuff]
+
+        Thread.sleep(100);
+
+        // Send a very simple HTTP get (it MUST be simple, no auth, no proxy, no 302, no 401, ...)
+        // Send it to another route. Must be a keepalive.
+        HttpContext context2 = new SyncBasicHttpContext();
+
+        Future<HttpResponse> future2 = this.httpclient.execute(
+                new HttpHost("127.0.0.1", target.getPort(), target.getSchemeName()),
+                new HttpGet("/"), context2, null);
+        HttpResponse response2 = future2.get();
+        Assert.assertNotNull(response2);
+        Assert.assertEquals(200, response2.getStatusLine().getStatusCode());
+
+        // ConnPoolByRoute now has 2 free connexions, out of its 2 max.
+        // The [localhost][stuff] RouteSpcfcPool is the same as earlier
+        // And there is a [127.0.0.1][null] pool with 1 free connection
+
+        Thread.sleep(100);
+
+        // This will put the ConnPoolByRoute to the targeted state :
+        // [localhost][stuff] will not get reused because this call is [localhost][null]
+        // So the ConnPoolByRoute will need to kill one connection (it is maxed out globally).
+        // The killed conn is the oldest, which means the first HTTPGet ([localhost][stuff]).
+        // When this happens, the RouteSpecificPool becomes empty.
+        HttpContext context3 = new SyncBasicHttpContext();
+        Future<HttpResponse> future3 = this.httpclient.execute(
+                target, new HttpGet("/"), context3, null);
+        HttpResponse response3 = future3.get();
+        Assert.assertNotNull(response3);
+        Assert.assertEquals(200, response3.getStatusLine().getStatusCode());
+    }
+
+}

Propchange: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/impl/nio/client/TestStatefulConnManagement.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/nio/client/methods/TestAsyncConsumers.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/nio/client/methods/TestAsyncConsumers.java?rev=1170086&r1=1170085&r2=1170086&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/nio/client/methods/TestAsyncConsumers.java (original)
+++ httpcomponents/httpasyncclient/branches/protocol-handler-refactoring/httpasyncclient/src/test/java/org/apache/http/nio/client/methods/TestAsyncConsumers.java Tue Sep 13 08:35:03 2011
@@ -139,7 +139,7 @@ public class TestAsyncConsumers extends 
         }
 
         @Override
-        protected Long buildResult() throws Exception {
+        protected Long buildResult(final HttpContext context) throws Exception {
             return count.get();
         }
 
@@ -199,7 +199,7 @@ public class TestAsyncConsumers extends 
         }
 
         @Override
-        protected String buildResult() throws Exception {
+        protected String buildResult(final HttpContext context) throws Exception {
             return this.sb.toString();
         }
 
@@ -265,7 +265,7 @@ public class TestAsyncConsumers extends 
         String result = future.get();
         Assert.assertEquals(s, result);
         Mockito.verify(consumer).responseCompleted(Mockito.any(HttpContext.class));
-        Mockito.verify(consumer).buildResult();
+        Mockito.verify(consumer).buildResult(Mockito.any(HttpContext.class));
         Mockito.verify(consumer).releaseResources();
     }
 
@@ -300,7 +300,7 @@ public class TestAsyncConsumers extends 
                 target.toURI() + "/echo/stuff", "stuff",
                 ContentType.create("text/plain", HTTP.ASCII));
         BufferingCharConsumer consumer = Mockito.spy(new BufferingCharConsumer());
-        Mockito.doThrow(new HttpException("Kaboom")).when(consumer).buildResult();
+        Mockito.doThrow(new HttpException("Kaboom")).when(consumer).buildResult(Mockito.any(HttpContext.class));
 
         Future<String> future = this.httpclient.execute(httppost, consumer, null);
         try {