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 2017/09/06 15:58:14 UTC

[2/2] httpcomponents-client git commit: Redesign of classic and asynchronous connection manager APIs

Redesign of classic and asynchronous connection manager APIs


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/d2b3385b
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/d2b3385b
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/d2b3385b

Branch: refs/heads/master
Commit: d2b3385ba2b655d9942263964aad78bcca391bda
Parents: a65c8e9
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Tue Sep 5 22:02:10 2017 +0200
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Wed Sep 6 17:44:36 2017 +0200

----------------------------------------------------------------------
 .../testing/sync/TestConnectionManagement.java  |  24 ++-
 .../http/examples/ClientConfiguration.java      |   5 +-
 .../http/impl/classic/ExecRuntimeImpl.java      |   9 +-
 .../io/BasicHttpClientConnectionManager.java    |   7 +-
 .../io/DefaultHttpClientConnectionOperator.java |   2 +
 .../io/DefaultManagedHttpClientConnection.java  |   3 +-
 .../io/PoolingHttpClientConnectionManager.java  | 138 ++++++++------
 ...olingHttpClientConnectionManagerBuilder.java |  17 +-
 .../impl/nio/AsyncClientConnectionOperator.java | 167 ----------------
 .../DefaultAsyncClientConnectionOperator.java   | 178 +++++++++++++++++
 .../DefaultManagedAsyncClientConnection.java    | 189 +++++++++++++++++++
 .../impl/nio/ManagedAsyncClientConnection.java  | 179 ------------------
 .../PoolingAsyncClientConnectionManager.java    |  94 ++++++++-
 ...lingAsyncClientConnectionManagerBuilder.java |  46 +++--
 .../http/io/HttpClientConnectionManager.java    |   5 +-
 .../http/io/HttpClientConnectionOperator.java   |   2 +
 .../http/io/ManagedHttpClientConnection.java    |   2 +
 .../http/nio/AsyncClientConnectionManager.java  |   4 +-
 .../http/nio/AsyncClientConnectionOperator.java |  55 ++++++
 .../http/nio/ManagedAsyncClientConnection.java  |  42 +++++
 .../http/impl/classic/TestExecRuntimeImpl.java  |  21 ++-
 .../TestPoolingHttpClientConnectionManager.java |   2 +-
 22 files changed, 723 insertions(+), 468 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java
index f67f96c..bf76397 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java
@@ -27,7 +27,6 @@
 
 package org.apache.hc.client5.testing.sync;
 
-import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -35,10 +34,14 @@ import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
 import org.apache.hc.client5.http.io.ConnectionEndpoint;
 import org.apache.hc.client5.http.io.LeaseRequest;
+import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
+import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
+import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
 import org.apache.hc.core5.http.protocol.BasicHttpContext;
@@ -48,6 +51,8 @@ import org.apache.hc.core5.http.protocol.HttpProcessor;
 import org.apache.hc.core5.http.protocol.RequestConnControl;
 import org.apache.hc.core5.http.protocol.RequestContent;
 import org.apache.hc.core5.http.protocol.RequestTargetHost;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
+import org.apache.hc.core5.pool.PoolReusePolicy;
 import org.apache.hc.core5.util.TimeValue;
 import org.junit.Assert;
 import org.junit.Test;
@@ -220,21 +225,18 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
         this.connManager.connect(endpoint1, TimeValue.NEG_ONE_MILLISECONDS, context);
 
-        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
         Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
         Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
 
         this.connManager.release(endpoint1, null, TimeValue.ofMillis(100));
 
         // Released, still active.
-        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
         Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
         Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
         this.connManager.closeExpired();
 
         // Time has not expired yet.
-        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
         Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
         Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
@@ -243,7 +245,6 @@ public class TestConnectionManagement extends LocalServerTestBase {
         this.connManager.closeExpired();
 
         // Time expired now, connections are destroyed.
-        Assert.assertEquals(Collections.emptySet(), this.connManager.getRoutes());
         Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
         Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
 
@@ -253,7 +254,14 @@ public class TestConnectionManagement extends LocalServerTestBase {
     @Test
     public void testCloseExpiredTTLConnections() throws Exception {
 
-        this.connManager = new PoolingHttpClientConnectionManager(TimeValue.ofMillis(100));
+        this.connManager = new PoolingHttpClientConnectionManager(
+                RegistryBuilder.<ConnectionSocketFactory>create()
+                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
+                        .register("https", SSLConnectionSocketFactory.getSocketFactory())
+                        .build(),
+                PoolConcurrencyPolicy.STRICT,
+                PoolReusePolicy.LIFO,
+                TimeValue.ofMillis(100));
         this.clientBuilder.setConnectionManager(this.connManager);
 
         this.connManager.setMaxTotal(1);
@@ -266,21 +274,18 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
         this.connManager.connect(endpoint1, TimeValue.NEG_ONE_MILLISECONDS, context);
 
-        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
         Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
         Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
         // Release, let remain idle for forever
         this.connManager.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECONDS);
 
         // Released, still active.
-        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
         Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
         Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
         this.connManager.closeExpired();
 
         // Time has not expired yet.
-        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
         Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
         Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
@@ -289,7 +294,6 @@ public class TestConnectionManagement extends LocalServerTestBase {
         this.connManager.closeExpired();
 
         // TTL expired now, connections are destroyed.
-        Assert.assertEquals(Collections.emptySet(), this.connManager.getRoutes());
         Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
         Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientConfiguration.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientConfiguration.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientConfiguration.java
index 8fcd996..1868ac4 100644
--- a/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientConfiguration.java
+++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientConfiguration.java
@@ -78,6 +78,8 @@ import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.BasicLineParser;
 import org.apache.hc.core5.http.message.LineParser;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
+import org.apache.hc.core5.pool.PoolReusePolicy;
 import org.apache.hc.core5.ssl.SSLContexts;
 import org.apache.hc.core5.util.CharArrayBuffer;
 import org.apache.hc.core5.util.TimeValue;
@@ -166,7 +168,8 @@ public class ClientConfiguration {
 
         // Create a connection manager with custom configuration.
         final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
-                socketFactoryRegistry, connFactory, dnsResolver);
+                socketFactoryRegistry, PoolConcurrencyPolicy.STRICT, PoolReusePolicy.LIFO, TimeValue.ofMinutes(5),
+                null, dnsResolver, null);
 
         // Create socket configuration
         final SocketConfig socketConfig = SocketConfig.custom()

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ExecRuntimeImpl.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ExecRuntimeImpl.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ExecRuntimeImpl.java
index b9a0666..75e876e 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ExecRuntimeImpl.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ExecRuntimeImpl.java
@@ -49,6 +49,7 @@ import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
 import org.apache.hc.core5.io.ShutdownType;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 import org.apache.logging.log4j.Logger;
 
 class ExecRuntimeImpl implements ExecRuntime, Cancellable {
@@ -92,7 +93,9 @@ class ExecRuntimeImpl implements ExecRuntime, Cancellable {
     public void acquireConnection(final HttpRoute route, final Object object, final HttpClientContext context) throws IOException {
         Args.notNull(route, "Route");
         if (endpointRef.get() == null) {
-            final LeaseRequest connRequest = manager.lease(route, object);
+            final RequestConfig requestConfig = context.getRequestConfig();
+            final Timeout requestTimeout = requestConfig.getConnectionRequestTimeout();
+            final LeaseRequest connRequest = manager.lease(route, requestTimeout, object);
             state = object;
             if (cancellableAware != null) {
                 if (cancellableAware.isCancelled()) {
@@ -102,9 +105,7 @@ class ExecRuntimeImpl implements ExecRuntime, Cancellable {
                 cancellableAware.setCancellable(connRequest);
             }
             try {
-                final RequestConfig requestConfig = context.getRequestConfig();
-                final TimeValue timeout = requestConfig.getConnectionRequestTimeout();
-                final ConnectionEndpoint connectionEndpoint = connRequest.get(timeout.getDuration(), timeout.getTimeUnit());
+                final ConnectionEndpoint connectionEndpoint = connRequest.get(requestTimeout.getDuration(), requestTimeout.getTimeUnit());
                 endpointRef.set(connectionEndpoint);
                 reusable = connectionEndpoint.isConnected();
                 if (cancellableAware != null) {

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
index 8d61e41..ecde0f2 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
@@ -65,6 +65,7 @@ import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.Asserts;
 import org.apache.hc.core5.util.LangUtils;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -181,8 +182,12 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         this.socketConfig = socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
     }
 
-    @Override
     public LeaseRequest lease(final HttpRoute route, final Object state) {
+        return lease(route, Timeout.DISABLED, state);
+    }
+
+    @Override
+    public LeaseRequest lease(final HttpRoute route, final Timeout requestTimeout, final Object state) {
         return new LeaseRequest() {
 
             @Override

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java
index cee5af7..0a38018 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultHttpClientConnectionOperator.java
@@ -47,6 +47,7 @@ import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
 import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.http.HttpHost;
@@ -65,6 +66,7 @@ import org.apache.logging.log4j.Logger;
  *
  * @since 4.4
  */
+@Internal
 @Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
 public class DefaultHttpClientConnectionOperator implements HttpClientConnectionOperator {
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultManagedHttpClientConnection.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultManagedHttpClientConnection.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultManagedHttpClientConnection.java
index 52dea86..dafa8e2 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultManagedHttpClientConnection.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/DefaultManagedHttpClientConnection.java
@@ -56,9 +56,10 @@ import org.apache.logging.log4j.Logger;
 
 /**
  * Default {@link ManagedHttpClientConnection} implementation.
+ *
  * @since 4.3
  */
-public class DefaultManagedHttpClientConnection
+final class DefaultManagedHttpClientConnection
         extends DefaultBHttpClientConnection implements ManagedHttpClientConnection, Identifiable {
 
     private final Logger log = LogManager.getLogger(DefaultManagedHttpClientConnection.class);

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
index ecb237e..e517ef8 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java
@@ -27,7 +27,6 @@
 package org.apache.hc.client5.http.impl.io;
 
 import java.io.IOException;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -49,13 +48,12 @@ import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
 import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
 import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
 import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.function.Callback;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.config.Lookup;
 import org.apache.hc.core5.http.config.Registry;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.config.SocketConfig;
@@ -64,6 +62,9 @@ import org.apache.hc.core5.http.io.HttpConnectionFactory;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.io.ShutdownType;
 import org.apache.hc.core5.pool.ConnPoolControl;
+import org.apache.hc.core5.pool.LaxConnPool;
+import org.apache.hc.core5.pool.ManagedConnPool;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
 import org.apache.hc.core5.pool.PoolEntry;
 import org.apache.hc.core5.pool.PoolReusePolicy;
 import org.apache.hc.core5.pool.PoolStats;
@@ -71,6 +72,7 @@ import org.apache.hc.core5.pool.StrictConnPool;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.Asserts;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -107,95 +109,113 @@ public class PoolingHttpClientConnectionManager
     public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 25;
     public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
 
-    private final StrictConnPool<HttpRoute, ManagedHttpClientConnection> pool;
-    private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
     private final HttpClientConnectionOperator connectionOperator;
+    private final ManagedConnPool<HttpRoute, ManagedHttpClientConnection> pool;
+    private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
     private final AtomicBoolean closed;
 
     private volatile SocketConfig defaultSocketConfig;
     private volatile TimeValue validateAfterInactivity;
 
-    private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
-        return RegistryBuilder.<ConnectionSocketFactory>create()
+    public PoolingHttpClientConnectionManager() {
+        this(RegistryBuilder.<ConnectionSocketFactory>create()
                 .register("http", PlainConnectionSocketFactory.getSocketFactory())
                 .register("https", SSLConnectionSocketFactory.getSocketFactory())
-                .build();
-    }
-
-    public PoolingHttpClientConnectionManager() {
-        this(getDefaultRegistry());
-    }
-
-    public PoolingHttpClientConnectionManager(final TimeValue timeToLive) {
-        this(getDefaultRegistry(), null, null ,null, PoolReusePolicy.LIFO, timeToLive);
+                .build());
     }
 
     public PoolingHttpClientConnectionManager(
             final Registry<ConnectionSocketFactory> socketFactoryRegistry) {
-        this(socketFactoryRegistry, null, null);
+        this(socketFactoryRegistry, null);
     }
 
     public PoolingHttpClientConnectionManager(
             final Registry<ConnectionSocketFactory> socketFactoryRegistry,
-            final DnsResolver dnsResolver) {
-        this(socketFactoryRegistry, null, dnsResolver);
+            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
+        this(socketFactoryRegistry, PoolConcurrencyPolicy.STRICT, TimeValue.NEG_ONE_MILLISECONDS, connFactory);
     }
 
     public PoolingHttpClientConnectionManager(
             final Registry<ConnectionSocketFactory> socketFactoryRegistry,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final TimeValue timeToLive,
             final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
-        this(socketFactoryRegistry, connFactory, null);
+        this(socketFactoryRegistry, poolConcurrencyPolicy, PoolReusePolicy.LIFO, timeToLive, connFactory);
     }
 
     public PoolingHttpClientConnectionManager(
-            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
-        this(getDefaultRegistry(), connFactory, null);
+            final Registry<ConnectionSocketFactory> socketFactoryRegistry,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final PoolReusePolicy poolReusePolicy,
+            final TimeValue timeToLive) {
+        this(socketFactoryRegistry, poolConcurrencyPolicy, poolReusePolicy, timeToLive, null);
     }
 
     public PoolingHttpClientConnectionManager(
             final Registry<ConnectionSocketFactory> socketFactoryRegistry,
-            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
-            final DnsResolver dnsResolver) {
-        this(socketFactoryRegistry, connFactory, null, dnsResolver, PoolReusePolicy.LIFO, TimeValue.NEG_ONE_MILLISECONDS);
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final PoolReusePolicy poolReusePolicy,
+            final TimeValue timeToLive,
+            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
+        this(socketFactoryRegistry, poolConcurrencyPolicy, poolReusePolicy, timeToLive, null, null, connFactory);
     }
 
     public PoolingHttpClientConnectionManager(
             final Registry<ConnectionSocketFactory> socketFactoryRegistry,
-            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final PoolReusePolicy poolReusePolicy,
+            final TimeValue timeToLive,
             final SchemePortResolver schemePortResolver,
             final DnsResolver dnsResolver,
-            final PoolReusePolicy poolReusePolicy,
-            final TimeValue timeToLive) {
+            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
         this(new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
-            connFactory, poolReusePolicy, timeToLive);
+                poolConcurrencyPolicy,
+                poolReusePolicy,
+                timeToLive,
+                connFactory);
     }
 
-    public PoolingHttpClientConnectionManager(
+    @Internal
+    protected PoolingHttpClientConnectionManager(
             final HttpClientConnectionOperator httpClientConnectionOperator,
-            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
             final PoolReusePolicy poolReusePolicy,
-            final TimeValue timeToLive) {
+            final TimeValue timeToLive,
+            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
         super();
         this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
+        switch (poolConcurrencyPolicy != null ? poolConcurrencyPolicy : PoolConcurrencyPolicy.STRICT) {
+            case STRICT:
+                this.pool = new StrictConnPool<>(
+                        DEFAULT_MAX_CONNECTIONS_PER_ROUTE,
+                        DEFAULT_MAX_TOTAL_CONNECTIONS,
+                        timeToLive,
+                        poolReusePolicy,
+                        null);
+                break;
+            case LAX:
+                this.pool = new LaxConnPool<>(
+                        DEFAULT_MAX_CONNECTIONS_PER_ROUTE,
+                        timeToLive,
+                        poolReusePolicy,
+                        null);
+                break;
+            default:
+                throw new IllegalArgumentException("Unexpected PoolConcurrencyPolicy value: " + poolConcurrencyPolicy);
+        }
         this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
-        this.pool = new StrictConnPool<>(DEFAULT_MAX_CONNECTIONS_PER_ROUTE, DEFAULT_MAX_TOTAL_CONNECTIONS, timeToLive,
-                poolReusePolicy, null);
         this.closed = new AtomicBoolean(false);
     }
 
-    /**
-     * Visible for test.
-     */
-    PoolingHttpClientConnectionManager(
-            final StrictConnPool<HttpRoute, ManagedHttpClientConnection> pool,
-            final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
-            final SchemePortResolver schemePortResolver,
-            final DnsResolver dnsResolver) {
+    @Internal
+    protected PoolingHttpClientConnectionManager(
+            final HttpClientConnectionOperator httpClientConnectionOperator,
+            final ManagedConnPool<HttpRoute, ManagedHttpClientConnection> pool,
+            final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
         super();
-        this.connectionOperator = new DefaultHttpClientConnectionOperator(
-                socketFactoryRegistry, schemePortResolver, dnsResolver);
-        this.connFactory = ManagedHttpClientConnectionFactory.INSTANCE;
-        this.pool = pool;
+        this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
+        this.pool = Args.notNull(pool, "Connection pool");
+        this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
         this.closed = new AtomicBoolean(false);
     }
 
@@ -225,15 +245,24 @@ public class PoolingHttpClientConnectionManager
         }
     }
 
+    public LeaseRequest lease(final HttpRoute route, final Object state) {
+        return lease(route, Timeout.DISABLED, state);
+    }
+
     @Override
     public LeaseRequest lease(
             final HttpRoute route,
+            final Timeout requestTimeout,
             final Object state) {
         Args.notNull(route, "HTTP route");
         if (this.log.isDebugEnabled()) {
             this.log.debug("Connection request: " + ConnPoolSupport.formatStats(null, route, state, this.pool));
         }
-        final Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> leaseFuture = this.pool.lease(route, state, null);
+        //TODO: fix me.
+        if (log.isWarnEnabled() && Timeout.isPositive(requestTimeout)) {
+            log.warn("Connection request timeout is not supported");
+        }
+        final Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> leaseFuture = this.pool.lease(route, state, /** requestTimeout, */ null);
         return new LeaseRequest() {
 
             private volatile ConnectionEndpoint endpoint;
@@ -391,14 +420,6 @@ public class PoolingHttpClientConnectionManager
         this.pool.closeExpired();
     }
 
-    protected void enumAvailable(final Callback<PoolEntry<HttpRoute, ManagedHttpClientConnection>> callback) {
-        this.pool.enumAvailable(callback);
-    }
-
-    protected void enumLeased(final Callback<PoolEntry<HttpRoute, ManagedHttpClientConnection>> callback) {
-        this.pool.enumLeased(callback);
-    }
-
     @Override
     public int getMaxTotal() {
         return this.pool.getMaxTotal();
@@ -439,13 +460,6 @@ public class PoolingHttpClientConnectionManager
         return this.pool.getStats(route);
     }
 
-    /**
-     * @since 4.4
-     */
-    public Set<HttpRoute> getRoutes() {
-        return this.pool.getRoutes();
-    }
-
     public SocketConfig getDefaultSocketConfig() {
         return this.defaultSocketConfig;
     }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
index 0e3b553..037c733 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
@@ -37,6 +37,7 @@ import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.config.SocketConfig;
 import org.apache.hc.core5.http.io.HttpConnectionFactory;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
 import org.apache.hc.core5.pool.PoolReusePolicy;
 import org.apache.hc.core5.util.TimeValue;
 
@@ -72,6 +73,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
     private LayeredConnectionSocketFactory sslSocketFactory;
     private SchemePortResolver schemePortResolver;
     private DnsResolver dnsResolver;
+    private PoolConcurrencyPolicy poolConcurrencyPolicy;
     private PoolReusePolicy poolReusePolicy;
     private SocketConfig defaultSocketConfig;
 
@@ -126,6 +128,14 @@ public class PoolingHttpClientConnectionManagerBuilder {
     }
 
     /**
+     * Assigns {@link PoolConcurrencyPolicy} value.
+     */
+    public final PoolingHttpClientConnectionManagerBuilder setPoolConcurrencyPolicy(final PoolConcurrencyPolicy poolConcurrencyPolicy) {
+        this.poolConcurrencyPolicy = poolConcurrencyPolicy;
+        return this;
+    }
+
+    /**
      * Assigns {@link PoolReusePolicy} value.
      */
     public final PoolingHttpClientConnectionManagerBuilder setConnPoolPolicy(final PoolReusePolicy poolReusePolicy) {
@@ -195,11 +205,12 @@ public class PoolingHttpClientConnectionManagerBuilder {
                                         SSLConnectionSocketFactory.getSystemSocketFactory() :
                                         SSLConnectionSocketFactory.getSocketFactory()))
                         .build(),
-                connectionFactory,
+                poolConcurrencyPolicy,
+                poolReusePolicy,
+                timeToLive != null ? timeToLive : TimeValue.NEG_ONE_MILLISECONDS,
                 schemePortResolver,
                 dnsResolver,
-                poolReusePolicy,
-                timeToLive != null ? timeToLive : TimeValue.NEG_ONE_MILLISECONDS);
+                connectionFactory);
         poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity);
         if (defaultSocketConfig != null) {
             poolingmgr.setDefaultSocketConfig(defaultSocketConfig);

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/AsyncClientConnectionOperator.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/AsyncClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/AsyncClientConnectionOperator.java
deleted file mode 100644
index 04c07e2..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/AsyncClientConnectionOperator.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http.impl.nio;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.net.UnknownHostException;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.hc.client5.http.DnsResolver;
-import org.apache.hc.client5.http.HttpHostConnectException;
-import org.apache.hc.client5.http.SchemePortResolver;
-import org.apache.hc.client5.http.SystemDefaultDnsResolver;
-import org.apache.hc.client5.http.UnsupportedSchemeException;
-import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
-import org.apache.hc.core5.concurrent.ComplexFuture;
-import org.apache.hc.core5.concurrent.FutureCallback;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.config.Lookup;
-import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
-import org.apache.hc.core5.reactor.ConnectionInitiator;
-import org.apache.hc.core5.reactor.IOSession;
-import org.apache.hc.core5.util.Args;
-import org.apache.hc.core5.util.TimeValue;
-
-final class AsyncClientConnectionOperator {
-
-    private final SchemePortResolver schemePortResolver;
-    private final DnsResolver dnsResolver;
-    private final Lookup<TlsStrategy> tlsStrategyLookup;
-
-    AsyncClientConnectionOperator(
-            final SchemePortResolver schemePortResolver,
-            final DnsResolver dnsResolver,
-            final Lookup<TlsStrategy> tlsStrategyLookup) {
-        this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
-        this.dnsResolver = dnsResolver != null ? dnsResolver : SystemDefaultDnsResolver.INSTANCE;
-        this.tlsStrategyLookup = tlsStrategyLookup;
-    }
-
-    public Future<ManagedAsyncClientConnection> connect(
-            final ConnectionInitiator connectionInitiator,
-            final HttpHost host,
-            final SocketAddress localAddress,
-            final TimeValue connectTimeout,
-            final Object attachment,
-            final FutureCallback<ManagedAsyncClientConnection> callback) {
-        Args.notNull(connectionInitiator, "Connection initiator");
-        Args.notNull(host, "Host");
-        final ComplexFuture<ManagedAsyncClientConnection> future = new ComplexFuture<>(callback);
-        final InetAddress[] remoteAddresses;
-        try {
-            remoteAddresses = dnsResolver.resolve(host.getHostName());
-        } catch (final UnknownHostException ex) {
-            future.failed(ex);
-            return future;
-        }
-        final int port;
-        try {
-            port = schemePortResolver.resolve(host);
-        } catch (final UnsupportedSchemeException ex) {
-            future.failed(ex);
-            return future;
-        }
-        final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
-        final Runnable runnable = new Runnable() {
-
-            private final AtomicInteger attempt = new AtomicInteger(0);
-
-            void executeNext() {
-                final int index = attempt.getAndIncrement();
-                final InetSocketAddress remoteAddress = new InetSocketAddress(remoteAddresses[index], port);
-                final Future<IOSession> sessionFuture = connectionInitiator.connect(
-                        host,
-                        remoteAddress,
-                        localAddress,
-                        connectTimeout,
-                        attachment,
-                        new FutureCallback<IOSession>() {
-
-                            @Override
-                            public void completed(final IOSession session) {
-                                final ManagedAsyncClientConnection connection = new ManagedAsyncClientConnection(session);
-                                if (tlsStrategy != null) {
-                                    tlsStrategy.upgrade(
-                                            connection,
-                                            host,
-                                            session.getLocalAddress(),
-                                            session.getRemoteAddress(),
-                                            attachment);
-                                }
-                                future.completed(connection);
-                            }
-
-                            @Override
-                            public void failed(final Exception cause) {
-                                if (attempt.get() >= remoteAddresses.length) {
-                                    if (cause instanceof IOException) {
-                                        future.failed(new HttpHostConnectException((IOException) cause, host, remoteAddresses));
-                                    } else {
-                                        future.failed(cause);
-                                    }
-                                } else {
-                                    executeNext();
-                                }
-                            }
-
-                            @Override
-                            public void cancelled() {
-                                future.cancel();
-                            }
-
-                        });
-                future.setDependency(sessionFuture);
-            }
-
-            @Override
-            public void run() {
-                executeNext();
-            }
-
-        };
-        runnable.run();
-        return future;
-    }
-
-    public void upgrade(final ManagedAsyncClientConnection connection, final HttpHost host, final Object attachment) {
-        final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
-        if (tlsStrategy != null) {
-            tlsStrategy.upgrade(
-                    connection,
-                    host,
-                    connection.getLocalAddress(),
-                    connection.getRemoteAddress(),
-                    attachment);
-        }
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
new file mode 100644
index 0000000..c5af9a2
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
@@ -0,0 +1,178 @@
+/*
+ * ====================================================================
+ * 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.hc.client5.http.impl.nio;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.hc.client5.http.DnsResolver;
+import org.apache.hc.client5.http.HttpHostConnectException;
+import org.apache.hc.client5.http.SchemePortResolver;
+import org.apache.hc.client5.http.SystemDefaultDnsResolver;
+import org.apache.hc.client5.http.UnsupportedSchemeException;
+import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
+import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
+import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.concurrent.ComplexFuture;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.config.Lookup;
+import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
+import org.apache.hc.core5.reactor.ConnectionInitiator;
+import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.TimeValue;
+
+/**
+ * Default {@link AsyncClientConnectionOperator} implementation.
+ *
+ * @since 5.0
+ */
+@Internal
+final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectionOperator {
+
+    private final SchemePortResolver schemePortResolver;
+    private final DnsResolver dnsResolver;
+    private final Lookup<TlsStrategy> tlsStrategyLookup;
+
+    DefaultAsyncClientConnectionOperator(
+            final Lookup<TlsStrategy> tlsStrategyLookup,
+            final SchemePortResolver schemePortResolver,
+            final DnsResolver dnsResolver) {
+        this.tlsStrategyLookup = Args.notNull(tlsStrategyLookup, "TLS strategy lookup");
+        this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
+        this.dnsResolver = dnsResolver != null ? dnsResolver : SystemDefaultDnsResolver.INSTANCE;
+    }
+
+    @Override
+    public Future<ManagedAsyncClientConnection> connect(
+            final ConnectionInitiator connectionInitiator,
+            final HttpHost host,
+            final SocketAddress localAddress,
+            final TimeValue connectTimeout,
+            final Object attachment,
+            final FutureCallback<ManagedAsyncClientConnection> callback) {
+        Args.notNull(connectionInitiator, "Connection initiator");
+        Args.notNull(host, "Host");
+        final ComplexFuture<ManagedAsyncClientConnection> future = new ComplexFuture<>(callback);
+        final InetAddress[] remoteAddresses;
+        try {
+            remoteAddresses = dnsResolver.resolve(host.getHostName());
+        } catch (final UnknownHostException ex) {
+            future.failed(ex);
+            return future;
+        }
+        final int port;
+        try {
+            port = schemePortResolver.resolve(host);
+        } catch (final UnsupportedSchemeException ex) {
+            future.failed(ex);
+            return future;
+        }
+        final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
+        final Runnable runnable = new Runnable() {
+
+            private final AtomicInteger attempt = new AtomicInteger(0);
+
+            void executeNext() {
+                final int index = attempt.getAndIncrement();
+                final InetSocketAddress remoteAddress = new InetSocketAddress(remoteAddresses[index], port);
+                final Future<IOSession> sessionFuture = connectionInitiator.connect(
+                        host,
+                        remoteAddress,
+                        localAddress,
+                        connectTimeout,
+                        attachment,
+                        new FutureCallback<IOSession>() {
+
+                            @Override
+                            public void completed(final IOSession session) {
+                                final DefaultManagedAsyncClientConnection connection = new DefaultManagedAsyncClientConnection(session);
+                                if (tlsStrategy != null) {
+                                    tlsStrategy.upgrade(
+                                            connection,
+                                            host,
+                                            session.getLocalAddress(),
+                                            session.getRemoteAddress(),
+                                            attachment);
+                                }
+                                future.completed(connection);
+                            }
+
+                            @Override
+                            public void failed(final Exception cause) {
+                                if (attempt.get() >= remoteAddresses.length) {
+                                    if (cause instanceof IOException) {
+                                        future.failed(new HttpHostConnectException((IOException) cause, host, remoteAddresses));
+                                    } else {
+                                        future.failed(cause);
+                                    }
+                                } else {
+                                    executeNext();
+                                }
+                            }
+
+                            @Override
+                            public void cancelled() {
+                                future.cancel();
+                            }
+
+                        });
+                future.setDependency(sessionFuture);
+            }
+
+            @Override
+            public void run() {
+                executeNext();
+            }
+
+        };
+        runnable.run();
+        return future;
+    }
+
+    @Override
+    public void upgrade(final ManagedAsyncClientConnection connection, final HttpHost host, final Object attachment) {
+        final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
+        if (tlsStrategy != null) {
+            tlsStrategy.upgrade(
+                    connection,
+                    host,
+                    connection.getLocalAddress(),
+                    connection.getRemoteAddress(),
+                    attachment);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultManagedAsyncClientConnection.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultManagedAsyncClientConnection.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultManagedAsyncClientConnection.java
new file mode 100644
index 0000000..1132ffe
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultManagedAsyncClientConnection.java
@@ -0,0 +1,189 @@
+/*
+ * ====================================================================
+ * 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.hc.client5.http.impl.nio;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+
+import org.apache.hc.client5.http.impl.ConnPoolSupport;
+import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.http.EndpointDetails;
+import org.apache.hc.core5.http.HttpConnection;
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.nio.command.ShutdownCommand;
+import org.apache.hc.core5.io.ShutdownType;
+import org.apache.hc.core5.reactor.Command;
+import org.apache.hc.core5.reactor.IOEventHandler;
+import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.reactor.ssl.SSLBufferManagement;
+import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
+import org.apache.hc.core5.reactor.ssl.SSLSessionVerifier;
+import org.apache.hc.core5.reactor.ssl.TlsDetails;
+import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
+import org.apache.hc.core5.util.Identifiable;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * Default {@link ManagedAsyncClientConnection} implementation.
+ *
+ * @since 5.0
+ */
+@Internal
+final class DefaultManagedAsyncClientConnection implements ManagedAsyncClientConnection, Identifiable {
+
+    private final Logger log = LogManager.getLogger(getClass());
+
+    private final IOSession ioSession;
+    private final AtomicBoolean closed;
+
+    public DefaultManagedAsyncClientConnection(final IOSession ioSession) {
+        this.ioSession = ioSession;
+        this.closed = new AtomicBoolean();
+    }
+
+    @Override
+    public String getId() {
+        return ConnPoolSupport.getId(ioSession);
+    }
+
+    @Override
+    public void shutdown(final ShutdownType shutdownType) {
+        if (this.closed.compareAndSet(false, true)) {
+            if (log.isDebugEnabled()) {
+                log.debug(getId() + ": Shutdown connection " + shutdownType);
+            }
+            ioSession.shutdown(shutdownType);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (this.closed.compareAndSet(false, true)) {
+            if (log.isDebugEnabled()) {
+                log.debug(getId() + ": Close connection");
+            }
+            ioSession.addFirst(new ShutdownCommand(ShutdownType.GRACEFUL));
+        }
+    }
+
+    @Override
+    public boolean isOpen() {
+        return !ioSession.isClosed();
+    }
+
+    @Override
+    public void setSocketTimeout(final int timeout) {
+        ioSession.setSocketTimeout(timeout);
+    }
+
+    @Override
+    public int getSocketTimeout() {
+        return ioSession.getSocketTimeout();
+    }
+
+    @Override
+    public SocketAddress getRemoteAddress() {
+        return ioSession.getRemoteAddress();
+    }
+
+    @Override
+    public SocketAddress getLocalAddress() {
+        return ioSession.getLocalAddress();
+    }
+
+    @Override
+    public EndpointDetails getEndpointDetails() {
+        final IOEventHandler handler = ioSession.getHandler();
+        if (handler instanceof HttpConnection) {
+            return ((HttpConnection) handler).getEndpointDetails();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ProtocolVersion getProtocolVersion() {
+        final IOEventHandler handler = ioSession.getHandler();
+        if (handler instanceof HttpConnection) {
+            return ((HttpConnection) handler).getProtocolVersion();
+        } else {
+            return HttpVersion.DEFAULT;
+        }
+    }
+
+    @Override
+    public void startTls(
+            final SSLContext sslContext,
+            final SSLBufferManagement sslBufferManagement,
+            final SSLSessionInitializer initializer,
+            final SSLSessionVerifier verifier) throws UnsupportedOperationException {
+        if (log.isDebugEnabled()) {
+            log.debug(getId() + ": start TLS");
+        }
+        if (ioSession instanceof TransportSecurityLayer) {
+            ((TransportSecurityLayer) ioSession).startTls(sslContext, sslBufferManagement, initializer, verifier);
+        } else {
+            throw new UnsupportedOperationException("TLS upgrade not supported");
+        }
+    }
+
+    @Override
+    public TlsDetails getTlsDetails() {
+        return ioSession instanceof TransportSecurityLayer ? ((TransportSecurityLayer) ioSession).getTlsDetails() : null;
+    }
+
+    @Override
+    public SSLSession getSSLSession() {
+        final TlsDetails tlsDetails = getTlsDetails();
+        return tlsDetails != null ? tlsDetails.getSSLSession() : null;
+    }
+
+    @Override
+    public void submitPriorityCommand(final Command command) {
+        if (log.isDebugEnabled()) {
+            log.debug(getId() + ": priority command " + command);
+        }
+        ioSession.addFirst(command);
+    }
+
+    @Override
+    public void submitCommand(final Command command) {
+        if (log.isDebugEnabled()) {
+            log.debug(getId() + ": command " + command);
+        }
+        ioSession.addLast(command);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/ManagedAsyncClientConnection.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/ManagedAsyncClientConnection.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/ManagedAsyncClientConnection.java
deleted file mode 100644
index ef8beba..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/ManagedAsyncClientConnection.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * ====================================================================
- * 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.hc.client5.http.impl.nio;
-
-import java.io.IOException;
-import java.net.SocketAddress;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-
-import org.apache.hc.client5.http.impl.ConnPoolSupport;
-import org.apache.hc.core5.http.EndpointDetails;
-import org.apache.hc.core5.http.HttpConnection;
-import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolVersion;
-import org.apache.hc.core5.http.nio.command.ShutdownCommand;
-import org.apache.hc.core5.io.ShutdownType;
-import org.apache.hc.core5.reactor.Command;
-import org.apache.hc.core5.reactor.IOEventHandler;
-import org.apache.hc.core5.reactor.IOSession;
-import org.apache.hc.core5.reactor.ssl.SSLBufferManagement;
-import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
-import org.apache.hc.core5.reactor.ssl.SSLSessionVerifier;
-import org.apache.hc.core5.reactor.ssl.TlsDetails;
-import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
-import org.apache.hc.core5.util.Identifiable;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-final class ManagedAsyncClientConnection implements Identifiable, HttpConnection, TransportSecurityLayer {
-
-    private final Logger log = LogManager.getLogger(getClass());
-
-    private final IOSession ioSession;
-    private final AtomicBoolean closed;
-
-    public ManagedAsyncClientConnection(final IOSession ioSession) {
-        this.ioSession = ioSession;
-        this.closed = new AtomicBoolean();
-    }
-
-    @Override
-    public String getId() {
-        return ConnPoolSupport.getId(ioSession);
-    }
-
-    @Override
-    public void shutdown(final ShutdownType shutdownType) {
-        if (this.closed.compareAndSet(false, true)) {
-            if (log.isDebugEnabled()) {
-                log.debug(getId() + ": Shutdown connection " + shutdownType);
-            }
-            ioSession.shutdown(shutdownType);
-        }
-    }
-
-    @Override
-    public void close() throws IOException {
-        if (this.closed.compareAndSet(false, true)) {
-            if (log.isDebugEnabled()) {
-                log.debug(getId() + ": Close connection");
-            }
-            ioSession.addFirst(new ShutdownCommand(ShutdownType.GRACEFUL));
-        }
-    }
-
-    @Override
-    public boolean isOpen() {
-        return !ioSession.isClosed();
-    }
-
-    @Override
-    public void setSocketTimeout(final int timeout) {
-        ioSession.setSocketTimeout(timeout);
-    }
-
-    @Override
-    public int getSocketTimeout() {
-        return ioSession.getSocketTimeout();
-    }
-
-    @Override
-    public SocketAddress getRemoteAddress() {
-        return ioSession.getRemoteAddress();
-    }
-
-    @Override
-    public SocketAddress getLocalAddress() {
-        return ioSession.getLocalAddress();
-    }
-
-    @Override
-    public EndpointDetails getEndpointDetails() {
-        final IOEventHandler handler = ioSession.getHandler();
-        if (handler instanceof HttpConnection) {
-            return ((HttpConnection) handler).getEndpointDetails();
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public ProtocolVersion getProtocolVersion() {
-        final IOEventHandler handler = ioSession.getHandler();
-        if (handler instanceof HttpConnection) {
-            return ((HttpConnection) handler).getProtocolVersion();
-        } else {
-            return HttpVersion.DEFAULT;
-        }
-    }
-
-    @Override
-    public void startTls(
-            final SSLContext sslContext,
-            final SSLBufferManagement sslBufferManagement,
-            final SSLSessionInitializer initializer,
-            final SSLSessionVerifier verifier) throws UnsupportedOperationException {
-        if (log.isDebugEnabled()) {
-            log.debug(getId() + ": start TLS");
-        }
-        if (ioSession instanceof TransportSecurityLayer) {
-            ((TransportSecurityLayer) ioSession).startTls(sslContext, sslBufferManagement, initializer, verifier);
-        } else {
-            throw new UnsupportedOperationException("TLS upgrade not supported");
-        }
-    }
-
-    @Override
-    public TlsDetails getTlsDetails() {
-        return ioSession instanceof TransportSecurityLayer ? ((TransportSecurityLayer) ioSession).getTlsDetails() : null;
-    }
-
-    @Override
-    public SSLSession getSSLSession() {
-        final TlsDetails tlsDetails = getTlsDetails();
-        return tlsDetails != null ? tlsDetails.getSSLSession() : null;
-    }
-
-    public void submitPriorityCommand(final Command command) {
-        if (log.isDebugEnabled()) {
-            log.debug(getId() + ": priority command " + command);
-        }
-        ioSession.addFirst(command);
-    }
-
-    public void submitCommand(final Command command) {
-        if (log.isDebugEnabled()) {
-            log.debug(getId() + ": command " + command);
-        }
-        ioSession.addLast(command);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
index 93ce8eb..8dbfc8a 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java
@@ -40,8 +40,12 @@ import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.impl.ConnPoolSupport;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
+import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
 import org.apache.hc.client5.http.nio.AsyncConnectionEndpoint;
+import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
+import org.apache.hc.client5.http.ssl.H2TlsStrategy;
 import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.concurrent.ComplexFuture;
 import org.apache.hc.core5.concurrent.FutureCallback;
@@ -50,6 +54,7 @@ import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.config.Lookup;
+import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
 import org.apache.hc.core5.http.nio.command.ExecutionCommand;
 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
@@ -58,6 +63,9 @@ import org.apache.hc.core5.http2.nio.command.PingCommand;
 import org.apache.hc.core5.http2.nio.support.BasicPingHandler;
 import org.apache.hc.core5.io.ShutdownType;
 import org.apache.hc.core5.pool.ConnPoolControl;
+import org.apache.hc.core5.pool.LaxConnPool;
+import org.apache.hc.core5.pool.ManagedConnPool;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
 import org.apache.hc.core5.pool.PoolEntry;
 import org.apache.hc.core5.pool.PoolReusePolicy;
 import org.apache.hc.core5.pool.PoolStats;
@@ -94,20 +102,86 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
 
     private final Logger log = LogManager.getLogger(getClass());
 
+    public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 25;
+    public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
+
+    private final ManagedConnPool<HttpRoute, ManagedAsyncClientConnection> pool;
     private final AsyncClientConnectionOperator connectionOperator;
-    private final StrictConnPool<HttpRoute, ManagedAsyncClientConnection> pool;
     private final AtomicBoolean closed;
 
     private volatile TimeValue validateAfterInactivity;
 
+    public PoolingAsyncClientConnectionManager() {
+        this(RegistryBuilder.<TlsStrategy>create()
+                .register("https", H2TlsStrategy.getDefault())
+                .build());
+    }
+
+    public PoolingAsyncClientConnectionManager(final Lookup<TlsStrategy> tlsStrategyLookup) {
+        this(tlsStrategyLookup, PoolConcurrencyPolicy.STRICT, TimeValue.NEG_ONE_MILLISECONDS);
+    }
+
     public PoolingAsyncClientConnectionManager(
             final Lookup<TlsStrategy> tlsStrategyLookup,
-            final SchemePortResolver schemePortResolver,
-            final DnsResolver dnsResolver,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final TimeValue timeToLive) {
+        this(tlsStrategyLookup, poolConcurrencyPolicy, PoolReusePolicy.LIFO, timeToLive);
+    }
+
+    public PoolingAsyncClientConnectionManager(
+            final Lookup<TlsStrategy> tlsStrategyLookup,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final PoolReusePolicy poolReusePolicy,
+            final TimeValue timeToLive) {
+        this(tlsStrategyLookup, poolConcurrencyPolicy, poolReusePolicy, timeToLive, null, null);
+    }
+
+    public PoolingAsyncClientConnectionManager(
+            final Lookup<TlsStrategy> tlsStrategyLookup,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final PoolReusePolicy poolReusePolicy,
             final TimeValue timeToLive,
-            final PoolReusePolicy poolReusePolicy) {
-        this.connectionOperator = new AsyncClientConnectionOperator(schemePortResolver, dnsResolver, tlsStrategyLookup);
-        this.pool = new StrictConnPool<>(20, 50, timeToLive, poolReusePolicy != null ? poolReusePolicy : PoolReusePolicy.LIFO, null);
+            final SchemePortResolver schemePortResolver,
+            final DnsResolver dnsResolver) {
+        this(new DefaultAsyncClientConnectionOperator(tlsStrategyLookup, schemePortResolver, dnsResolver),
+                poolConcurrencyPolicy, poolReusePolicy, timeToLive);
+    }
+
+    @Internal
+    protected PoolingAsyncClientConnectionManager(
+            final AsyncClientConnectionOperator connectionOperator,
+            final PoolConcurrencyPolicy poolConcurrencyPolicy,
+            final PoolReusePolicy poolReusePolicy,
+            final TimeValue timeToLive) {
+        this.connectionOperator = Args.notNull(connectionOperator, "Connection operator");
+        switch (poolConcurrencyPolicy != null ? poolConcurrencyPolicy : PoolConcurrencyPolicy.STRICT) {
+            case STRICT:
+                this.pool = new StrictConnPool<>(
+                        DEFAULT_MAX_CONNECTIONS_PER_ROUTE,
+                        DEFAULT_MAX_TOTAL_CONNECTIONS,
+                        timeToLive,
+                        poolReusePolicy,
+                        null);
+                break;
+            case LAX:
+                this.pool = new LaxConnPool<>(
+                        DEFAULT_MAX_CONNECTIONS_PER_ROUTE,
+                        timeToLive,
+                        poolReusePolicy,
+                        null);
+                break;
+            default:
+                throw new IllegalArgumentException("Unexpected PoolConcurrencyPolicy value: " + poolConcurrencyPolicy);
+        }
+        this.closed = new AtomicBoolean(false);
+    }
+
+    @Internal
+    protected PoolingAsyncClientConnectionManager(
+            final ManagedConnPool<HttpRoute, ManagedAsyncClientConnection> pool,
+            final AsyncClientConnectionOperator connectionOperator) {
+        this.connectionOperator = Args.notNull(connectionOperator, "Connection operator");
+        this.pool = Args.notNull(pool, "Connection pool");
         this.closed = new AtomicBoolean(false);
     }
 
@@ -141,14 +215,18 @@ public class PoolingAsyncClientConnectionManager implements AsyncClientConnectio
     public Future<AsyncConnectionEndpoint> lease(
             final HttpRoute route,
             final Object state,
-            final Timeout timeout,
+            final Timeout requestTimeout,
             final FutureCallback<AsyncConnectionEndpoint> callback) {
         if (log.isDebugEnabled()) {
             log.debug("Connection request: " + ConnPoolSupport.formatStats(null, route, state, pool));
         }
         final ComplexFuture<AsyncConnectionEndpoint> resultFuture = new ComplexFuture<>(callback);
+        //TODO: fix me.
+        if (log.isWarnEnabled() && Timeout.isPositive(requestTimeout)) {
+            log.warn("Connection request timeout is not supported");
+        }
         final Future<PoolEntry<HttpRoute, ManagedAsyncClientConnection>> leaseFuture = pool.lease(
-                route, state, timeout, new FutureCallback<PoolEntry<HttpRoute, ManagedAsyncClientConnection>>() {
+                route, state, /** requestTimeout, **/ new FutureCallback<PoolEntry<HttpRoute, ManagedAsyncClientConnection>>() {
 
                     void leaseCompleted(final PoolEntry<HttpRoute, ManagedAsyncClientConnection> poolEntry) {
                         if (log.isDebugEnabled()) {

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
index ed2e42d..63d1d00 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
@@ -35,6 +35,7 @@ import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.ssl.H2TlsStrategy;
 import org.apache.hc.core5.http.config.RegistryBuilder;
 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
 import org.apache.hc.core5.pool.PoolReusePolicy;
 import org.apache.hc.core5.util.TimeValue;
 
@@ -69,6 +70,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
     private TlsStrategy tlsStrategy;
     private SchemePortResolver schemePortResolver;
     private DnsResolver dnsResolver;
+    private PoolConcurrencyPolicy poolConcurrencyPolicy;
     private PoolReusePolicy poolReusePolicy;
 
     private boolean systemProperties;
@@ -113,6 +115,14 @@ public class PoolingAsyncClientConnectionManagerBuilder {
     }
 
     /**
+     * Assigns {@link PoolConcurrencyPolicy} value.
+     */
+    public final PoolingAsyncClientConnectionManagerBuilder setPoolConcurrencyPolicy(final PoolConcurrencyPolicy poolConcurrencyPolicy) {
+        this.poolConcurrencyPolicy = poolConcurrencyPolicy;
+        return this;
+    }
+
+    /**
      * Assigns {@link PoolReusePolicy} value.
      */
     public final PoolingAsyncClientConnectionManagerBuilder setConnPoolPolicy(final PoolReusePolicy connPoolPolicy) {
@@ -165,15 +175,29 @@ public class PoolingAsyncClientConnectionManagerBuilder {
     }
 
     public PoolingAsyncClientConnectionManager build() {
+        final TlsStrategy tlsStrategyCopy;
+        if (tlsStrategy != null) {
+            tlsStrategyCopy = tlsStrategy;
+        } else if (systemProperties) {
+            tlsStrategyCopy = AccessController.doPrivileged(new PrivilegedAction<TlsStrategy>() {
+                @Override
+                public TlsStrategy run() {
+                    return H2TlsStrategy.getSystemDefault();
+                }
+            });
+        } else {
+            tlsStrategyCopy = H2TlsStrategy.getDefault();
+        }
         @SuppressWarnings("resource")
         final PoolingAsyncClientConnectionManager poolingmgr = new PoolingAsyncClientConnectionManager(
                 RegistryBuilder.<TlsStrategy>create()
-                        .register("https", getTlsStrategy())
+                        .register("https", tlsStrategyCopy)
                         .build(),
-                schemePortResolver,
-                dnsResolver,
+                poolConcurrencyPolicy,
+                poolReusePolicy,
                 timeToLive,
-                poolReusePolicy);
+                schemePortResolver,
+                dnsResolver);
         poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity);
         if (maxConnTotal > 0) {
             poolingmgr.setMaxTotal(maxConnTotal);
@@ -184,18 +208,4 @@ public class PoolingAsyncClientConnectionManagerBuilder {
         return poolingmgr;
     }
 
-    private TlsStrategy getTlsStrategy() {
-        if (tlsStrategy != null) {
-            return tlsStrategy;
-        } else if (systemProperties) {
-            return AccessController.doPrivileged(new PrivilegedAction<TlsStrategy>() {
-                @Override
-                public TlsStrategy run() {
-                    return H2TlsStrategy.getSystemDefault();
-                }
-            });
-        } else {
-            return H2TlsStrategy.getDefault();
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionManager.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionManager.java
index 41bff4a..f689101 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionManager.java
@@ -32,6 +32,7 @@ import java.io.IOException;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
 
 /**
  * Represents a manager of persistent client connections.
@@ -64,10 +65,12 @@ public interface HttpClientConnectionManager extends Closeable {
      * executed a {@code CONNECT} method to all intermediate proxy hops.
      *
      * @param route HTTP route of the requested connection.
+     * @param requestTimeout lease request timeout.
      * @param state expected state of the connection or {@code null}
      *              if the connection is not expected to carry any state.
+     * @since 5.0
      */
-    LeaseRequest lease(HttpRoute route, Object state);
+    LeaseRequest lease(HttpRoute route, Timeout requestTimeout, Object state);
 
     /**
      * Releases the endpoint back to the manager making it potentially

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java
index ed239ba..c472a95 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/io/HttpClientConnectionOperator.java
@@ -30,6 +30,7 @@ package org.apache.hc.client5.http.io;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 
+import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.config.SocketConfig;
 import org.apache.hc.core5.http.protocol.HttpContext;
@@ -44,6 +45,7 @@ import org.apache.hc.core5.util.TimeValue;
  *
  * @since 4.4
  */
+@Internal
 public interface HttpClientConnectionOperator {
 
     void connect(

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/io/ManagedHttpClientConnection.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/io/ManagedHttpClientConnection.java b/httpclient5/src/main/java/org/apache/hc/client5/http/io/ManagedHttpClientConnection.java
index af23aef..fa0e92d 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/io/ManagedHttpClientConnection.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/io/ManagedHttpClientConnection.java
@@ -32,6 +32,7 @@ import java.net.Socket;
 
 import javax.net.ssl.SSLSession;
 
+import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.http.io.HttpClientConnection;
 
 /**
@@ -42,6 +43,7 @@ import org.apache.hc.core5.http.io.HttpClientConnection;
  *
  * @since 4.3
  */
+@Internal
 public interface ManagedHttpClientConnection extends HttpClientConnection {
 
     /**

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionManager.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionManager.java
index 1b119bf..55b878b 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionManager.java
@@ -71,13 +71,13 @@ public interface AsyncClientConnectionManager extends Closeable {
      * @param route HTTP route of the requested connection.
      * @param state expected state of the connection or {@code null}
      *              if the connection is not expected to carry any state.
-     * @param timeout lease request timeout.
+     * @param requestTimeout lease request timeout.
      * @param callback result callback.
      */
     Future<AsyncConnectionEndpoint> lease(
             HttpRoute route,
             Object state,
-            Timeout timeout,
+            Timeout requestTimeout,
             FutureCallback<AsyncConnectionEndpoint> callback);
 
     /**

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java
new file mode 100644
index 0000000..4bea69c
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/AsyncClientConnectionOperator.java
@@ -0,0 +1,55 @@
+/*
+ * ====================================================================
+ * 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.hc.client5.http.nio;
+
+import java.net.SocketAddress;
+import java.util.concurrent.Future;
+
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.reactor.ConnectionInitiator;
+import org.apache.hc.core5.util.TimeValue;
+
+/**
+ * @since 5.0
+ */
+@Internal
+public interface AsyncClientConnectionOperator {
+
+    Future<ManagedAsyncClientConnection> connect(
+            ConnectionInitiator connectionInitiator,
+            HttpHost host,
+            SocketAddress localAddress,
+            TimeValue connectTimeout,
+            Object attachment,
+            FutureCallback<ManagedAsyncClientConnection> callback);
+
+    void upgrade(ManagedAsyncClientConnection connection, HttpHost host, Object attachment);
+
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/d2b3385b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/ManagedAsyncClientConnection.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/nio/ManagedAsyncClientConnection.java b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/ManagedAsyncClientConnection.java
new file mode 100644
index 0000000..6726660
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/nio/ManagedAsyncClientConnection.java
@@ -0,0 +1,42 @@
+/*
+ * ====================================================================
+ * 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.hc.client5.http.nio;
+
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.http.HttpConnection;
+import org.apache.hc.core5.reactor.Command;
+import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
+
+@Internal
+public interface ManagedAsyncClientConnection extends HttpConnection, TransportSecurityLayer {
+
+    void submitPriorityCommand(Command command);
+
+    void submitCommand(Command command);
+
+}