Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 53F64200C24 for ; Thu, 23 Feb 2017 15:32:29 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 5252E160B50; Thu, 23 Feb 2017 14:32:29 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 2616F160B78 for ; Thu, 23 Feb 2017 15:32:26 +0100 (CET) Received: (qmail 70795 invoked by uid 500); 23 Feb 2017 14:32:26 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 70647 invoked by uid 99); 23 Feb 2017 14:32:26 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 23 Feb 2017 14:32:26 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 1EFEB3A0870 for ; Thu, 23 Feb 2017 14:32:25 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1784138 [2/5] - in /httpcomponents/httpclient/trunk: httpclient5-osgi/src/main/java/org/apache/hc/client5/http/osgi/impl/ httpclient5-osgi/src/test/java/org/apache/hc/client5/http/osgi/impl/ httpclient5/src/examples/org/apache/hc/client5/h... Date: Thu, 23 Feb 2017 14:32:24 -0000 To: commits@hc.apache.org From: olegk@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20170223143225.1EFEB3A0870@svn01-us-west.apache.org> archived-at: Thu, 23 Feb 2017 14:32:29 -0000 Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java Thu Feb 23 14:32:24 2017 @@ -26,9 +26,7 @@ */ package org.apache.hc.client5.http.impl.io; -import java.io.Closeable; import java.io.IOException; -import java.net.InetSocketAddress; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -37,15 +35,17 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; -import org.apache.hc.client5.http.ConnectionPoolTimeoutException; import org.apache.hc.client5.http.DnsResolver; -import org.apache.hc.client5.http.HttpConnectionFactory; import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.SchemePortResolver; -import org.apache.hc.client5.http.io.ConnectionRequest; +import org.apache.hc.client5.http.impl.ConnPoolSupport; +import org.apache.hc.client5.http.impl.ConnectionShutdownException; +import org.apache.hc.client5.http.io.ConnectionEndpoint; import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.client5.http.io.HttpClientConnectionOperator; +import org.apache.hc.client5.http.io.LeaseRequest; import org.apache.hc.client5.http.io.ManagedHttpClientConnection; import org.apache.hc.client5.http.socket.ConnectionSocketFactory; import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; @@ -53,70 +53,68 @@ import org.apache.hc.client5.http.ssl.SS import org.apache.hc.core5.annotation.Contract; 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.ConnectionConfig; 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; +import org.apache.hc.core5.http.impl.io.HttpRequestExecutor; import org.apache.hc.core5.http.io.HttpClientConnection; +import org.apache.hc.core5.http.io.HttpConnectionFactory; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.pool.ConnPoolControl; +import org.apache.hc.core5.pool.ConnPoolListener; import org.apache.hc.core5.pool.ConnPoolPolicy; import org.apache.hc.core5.pool.PoolEntry; import org.apache.hc.core5.pool.PoolStats; import org.apache.hc.core5.pool.StrictConnPool; import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.Asserts; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * {@code ClientConnectionPoolManager} maintains a pool of - * {@link HttpClientConnection}s and is able to service connection requests + * {@link ManagedHttpClientConnection}s and is able to service connection requests * from multiple execution threads. Connections are pooled on a per route * basis. A request for a route which already the manager has persistent * connections for available in the pool will be services by leasing - * a connection from the pool rather than creating a brand new connection. + * a connection from the pool rather than creating a new connection. *

* {@code ClientConnectionPoolManager} maintains a maximum limit of connection - * on a per route basis and in total. Per default this implementation will - * create no more than than 2 concurrent connections per given route - * and no more 20 connections in total. For many real-world applications - * these limits may prove too constraining, especially if they use HTTP - * as a transport protocol for their services. Connection limits, however, - * can be adjusted using {@link ConnPoolControl} methods. - *

+ * on a per route basis and in total. Connection limits, however, can be adjusted + * using {@link ConnPoolControl} methods. *

* Total time to live (TTL) set at construction time defines maximum life span * of persistent connections regardless of their expiration setting. No persistent * connection will be re-used past its TTL value. - *

*

* The handling of stale connections was changed in version 4.4. * Previously, the code would check every connection by default before re-using it. * The code now only checks the connection if the elapsed time since * the last use of the connection exceeds the timeout that has been set. - * The default timeout is set to 5000ms - see - * {@link #PoolingHttpClientConnectionManager(HttpClientConnectionOperator, HttpConnectionFactory, long, TimeUnit)} - *

+ * The default timeout is set to 5000ms. * * @since 4.3 */ @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL) public class PoolingHttpClientConnectionManager - implements HttpClientConnectionManager, ConnPoolControl, Closeable { + implements HttpClientConnectionManager, ConnPoolControl { 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 ConfigData configData; private final StrictConnPool pool; - private final HttpConnectionFactory connFactory; + private final HttpConnectionFactory connFactory; private final HttpClientConnectionOperator connectionOperator; - private final AtomicBoolean isShutDown; + private final AtomicBoolean closed; + private volatile SocketConfig defaultSocketConfig; private volatile int validateAfterInactivity; private static Registry getDefaultRegistry() { @@ -130,8 +128,9 @@ public class PoolingHttpClientConnection this(getDefaultRegistry()); } - public PoolingHttpClientConnectionManager(final long timeToLive, final TimeUnit tunit) { - this(getDefaultRegistry(), null, null ,null, timeToLive, tunit); + public PoolingHttpClientConnectionManager( + final long timeToLive, final TimeUnit tunit) { + this(getDefaultRegistry(), null, null ,null, ConnPoolPolicy.LIFO, null, timeToLive, tunit); } public PoolingHttpClientConnectionManager( @@ -147,49 +146,46 @@ public class PoolingHttpClientConnection public PoolingHttpClientConnectionManager( final Registry socketFactoryRegistry, - final HttpConnectionFactory connFactory) { + final HttpConnectionFactory connFactory) { this(socketFactoryRegistry, connFactory, null); } public PoolingHttpClientConnectionManager( - final HttpConnectionFactory connFactory) { + final HttpConnectionFactory connFactory) { this(getDefaultRegistry(), connFactory, null); } public PoolingHttpClientConnectionManager( final Registry socketFactoryRegistry, - final HttpConnectionFactory connFactory, + final HttpConnectionFactory connFactory, final DnsResolver dnsResolver) { - this(socketFactoryRegistry, connFactory, null, dnsResolver, -1, TimeUnit.MILLISECONDS); + this(socketFactoryRegistry, connFactory, null, dnsResolver, ConnPoolPolicy.LIFO, null, -1, TimeUnit.MILLISECONDS); } public PoolingHttpClientConnectionManager( final Registry socketFactoryRegistry, - final HttpConnectionFactory connFactory, + final HttpConnectionFactory connFactory, final SchemePortResolver schemePortResolver, final DnsResolver dnsResolver, + final ConnPoolPolicy connPoolPolicy, + final ConnPoolListener connPoolListener, final long timeToLive, final TimeUnit tunit) { - this( - new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver), - connFactory, - timeToLive, tunit - ); + this(new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver), + connFactory, connPoolPolicy, connPoolListener, timeToLive, tunit); } - /** - * @since 4.4 - */ public PoolingHttpClientConnectionManager( final HttpClientConnectionOperator httpClientConnectionOperator, - final HttpConnectionFactory connFactory, + final HttpConnectionFactory connFactory, + final ConnPoolPolicy connPoolPolicy, + final ConnPoolListener connPoolListener, final long timeToLive, final TimeUnit tunit) { super(); this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator"); this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE; - this.configData = new ConfigData(); this.pool = new StrictConnPool<>( - DEFAULT_MAX_CONNECTIONS_PER_ROUTE, DEFAULT_MAX_TOTAL_CONNECTIONS, timeToLive, tunit, ConnPoolPolicy.LIFO, null); - this.isShutDown = new AtomicBoolean(false); + DEFAULT_MAX_CONNECTIONS_PER_ROUTE, DEFAULT_MAX_TOTAL_CONNECTIONS, timeToLive, tunit, connPoolPolicy, connPoolListener); + this.closed = new AtomicBoolean(false); } /** @@ -204,15 +200,14 @@ public class PoolingHttpClientConnection this.connectionOperator = new DefaultHttpClientConnectionOperator( socketFactoryRegistry, schemePortResolver, dnsResolver); this.connFactory = ManagedHttpClientConnectionFactory.INSTANCE; - this.configData = new ConfigData(); this.pool = pool; - this.isShutDown = new AtomicBoolean(false); + this.closed = new AtomicBoolean(false); } @Override protected void finalize() throws Throwable { try { - shutdown(); + close(); } finally { super.finalize(); } @@ -220,227 +215,176 @@ public class PoolingHttpClientConnection @Override public void close() { - shutdown(); - } - - private String format(final HttpRoute route, final Object state) { - final StringBuilder buf = new StringBuilder(); - buf.append("[route: ").append(route).append("]"); - if (state != null) { - buf.append("[state: ").append(state).append("]"); + if (this.closed.compareAndSet(false, true)) { + this.log.debug("Connection manager is shutting down"); + this.pool.shutdown(); + this.log.debug("Connection manager shut down"); } - return buf.toString(); } - private String formatStats(final HttpRoute route) { - final StringBuilder buf = new StringBuilder(); - final PoolStats totals = this.pool.getTotalStats(); - final PoolStats stats = this.pool.getStats(route); - buf.append("[total kept alive: ").append(totals.getAvailable()).append("; "); - buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable()); - buf.append(" of ").append(stats.getMax()).append("; "); - buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable()); - buf.append(" of ").append(totals.getMax()).append("]"); - return buf.toString(); - } - - private String format(final PoolEntry entry) { - final StringBuilder buf = new StringBuilder(); - final ManagedHttpClientConnection conn = entry.getConnection(); - buf.append("[id: ").append(conn != null ? conn.getId() : "unknown").append("]"); - buf.append("[route: ").append(entry.getRoute()).append("]"); - final Object state = entry.getState(); - if (state != null) { - buf.append("[state: ").append(state).append("]"); + private InternalConnectionEndpoint cast(final ConnectionEndpoint endpoint) { + if (endpoint instanceof InternalConnectionEndpoint) { + return (InternalConnectionEndpoint) endpoint; + } else { + throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass()); } - return buf.toString(); } @Override - public ConnectionRequest requestConnection( + public LeaseRequest lease( final HttpRoute route, final Object state) { Args.notNull(route, "HTTP route"); if (this.log.isDebugEnabled()) { - this.log.debug("Connection request: " + format(route, state) + formatStats(route)); + this.log.debug("Connection request: " + ConnPoolSupport.formatStats(null, route, state, this.pool)); } - final Future> future = this.pool.lease(route, state, null); - return new ConnectionRequest() { + final Future> leaseFuture = this.pool.lease(route, state, null); + return new LeaseRequest() { - @Override - public boolean cancel() { - return future.cancel(true); - } + private volatile ConnectionEndpoint endpoint; @Override - public HttpClientConnection get( + public synchronized ConnectionEndpoint get( final long timeout, - final TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException { - return leaseConnection(future, timeout, tunit); - } - - }; - - } - - protected HttpClientConnection leaseConnection( - final Future> future, - final long timeout, - final TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException { - final PoolEntry entry; - try { - entry = future.get(timeout, tunit); - if (entry == null || future.isCancelled()) { - throw new InterruptedException(); - } - } catch (final TimeoutException ex) { - future.cancel(true); - throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool"); - } - if (this.validateAfterInactivity > 0) { - final ManagedHttpClientConnection connection = entry.getConnection(); - if (connection != null - && entry.getUpdated() + this.validateAfterInactivity <= System.currentTimeMillis()) { - boolean stale; + final TimeUnit tunit) throws InterruptedException, ExecutionException, TimeoutException { + if (this.endpoint != null) { + return this.endpoint; + } + final PoolEntry poolEntry; try { - stale = connection.isStale(); - } catch (IOException ignore) { - stale = true; + poolEntry = leaseFuture.get(timeout, tunit); + if (poolEntry == null || leaseFuture.isCancelled()) { + throw new InterruptedException(); + } + } catch (final TimeoutException ex) { + leaseFuture.cancel(true); + throw ex; } - if (stale) { - entry.discardConnection(); + try { + if (validateAfterInactivity > 0) { + final ManagedHttpClientConnection conn = poolEntry.getConnection(); + if (conn != null + && poolEntry.getUpdated() + validateAfterInactivity <= System.currentTimeMillis()) { + boolean stale; + try { + stale = conn.isStale(); + } catch (IOException ignore) { + stale = true; + } + if (stale) { + if (log.isDebugEnabled()) { + log.debug("Connection " + ConnPoolSupport.getId(conn) + " is stale"); + } + poolEntry.discardConnection(); + } + } + } + if (!poolEntry.hasConnection()) { + poolEntry.assignConnection(connFactory.createConnection(null)); + } + if (log.isDebugEnabled()) { + log.debug("Connection leased: " + ConnPoolSupport.formatStats( + poolEntry.getConnection(), route, state, pool)); + } + if (leaseFuture.isCancelled()) { + pool.release(poolEntry, false); + } else { + this.endpoint = new InternalConnectionEndpoint(poolEntry); + } + return this.endpoint; + } catch (Exception ex) { + pool.release(poolEntry, false); + throw new ExecutionException(ex.getMessage(), ex); } } - } - final HttpRoute route = entry.getRoute(); - final CPoolProxy poolProxy = new CPoolProxy(entry); - if (entry.hasConnection()) { - poolProxy.markRouteComplete(); - } else { - ConnectionConfig config = null; - if (route.getProxyHost() != null) { - config = this.configData.getConnectionConfig(route.getProxyHost()); - } - if (config == null) { - config = this.configData.getConnectionConfig(route.getTargetHost()); - } - if (config == null) { - config = this.configData.getDefaultConnectionConfig(); - } - if (config == null) { - config = ConnectionConfig.DEFAULT; + + @Override + public boolean cancel() { + return leaseFuture.cancel(true); } - entry.assignConnection(this.connFactory.create(route, config)); - } - if (this.log.isDebugEnabled()) { - this.log.debug("Connection leased: " + format(entry) + formatStats(route)); - } - return poolProxy; + + }; + } @Override - public void releaseConnection( - final HttpClientConnection managedConn, + public void release( + final ConnectionEndpoint endpoint, final Object state, final long keepAlive, final TimeUnit timeUnit) { - Args.notNull(managedConn, "Managed connection"); - synchronized (managedConn) { - final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn); - if (poolProxy.isDetached()) { - return; - } - final PoolEntry entry = poolProxy.detach(); - try { - final ManagedHttpClientConnection conn = entry.getConnection(); - if (conn.isOpen()) { - final TimeUnit effectiveUnit = timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS; - entry.updateConnection(keepAlive, effectiveUnit, state); - if (this.log.isDebugEnabled()) { - final String s; - if (keepAlive > 0) { - s = "for " + (double) effectiveUnit.toMillis(keepAlive) / 1000 + " seconds"; - } else { - s = "indefinitely"; - } - this.log.debug("Connection " + format(entry) + " can be kept alive " + s); - } - } - } finally { - final ManagedHttpClientConnection conn = entry.getConnection(); - this.pool.release(entry, conn.isOpen() && poolProxy.isRouteComplete()); + Args.notNull(endpoint, "Managed endpoint"); + final PoolEntry entry = cast(endpoint).detach(); + if (entry == null) { + return; + } + final ManagedHttpClientConnection conn = entry.getConnection(); + boolean reusable = conn != null && conn.isOpen(); + try { + if (reusable) { + final TimeUnit effectiveUnit = timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS; + entry.updateConnection(keepAlive, effectiveUnit, state); if (this.log.isDebugEnabled()) { - this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute())); + final String s; + if (keepAlive > 0) { + s = "for " + (double) effectiveUnit.toMillis(keepAlive) / 1000 + " seconds"; + } else { + s = "indefinitely"; + } + this.log.debug("Connection " + ConnPoolSupport.getId(conn) + " can be kept alive " + s); } } + } catch (RuntimeException ex) { + reusable = false; + throw ex; + } finally { + this.pool.release(entry, reusable); + if (this.log.isDebugEnabled()) { + this.log.debug("Connection released: " + ConnPoolSupport.formatStats( + conn, entry.getRoute(), entry.getState(), pool)); + } } } @Override public void connect( - final HttpClientConnection managedConn, - final HttpRoute route, - final int connectTimeout, + final ConnectionEndpoint endpoint, + final long connectTimeout, + final TimeUnit timeUnit, final HttpContext context) throws IOException { - Args.notNull(managedConn, "Managed Connection"); - Args.notNull(route, "HTTP route"); - final ManagedHttpClientConnection conn; - synchronized (managedConn) { - final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn); - conn = poolProxy.getConnection(); + Args.notNull(endpoint, "Managed endpoint"); + final InternalConnectionEndpoint internalEndpoint = cast(endpoint); + if (internalEndpoint.isConnected()) { + return; + } + final PoolEntry poolEntry = internalEndpoint.getPoolEntry(); + if (!poolEntry.hasConnection()) { + poolEntry.assignConnection(connFactory.createConnection(null)); } + final HttpRoute route = poolEntry.getRoute(); final HttpHost host; if (route.getProxyHost() != null) { host = route.getProxyHost(); } else { host = route.getTargetHost(); } - final InetSocketAddress localAddress = route.getLocalSocketAddress(); - SocketConfig socketConfig = this.configData.getSocketConfig(host); - if (socketConfig == null) { - socketConfig = this.configData.getDefaultSocketConfig(); - } - if (socketConfig == null) { - socketConfig = SocketConfig.DEFAULT; - } this.connectionOperator.connect( - conn, host, localAddress, connectTimeout, socketConfig, context); + poolEntry.getConnection(), + host, + route.getLocalSocketAddress(), + (int) (timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS).toMillis(connectTimeout), + this.defaultSocketConfig != null ? this.defaultSocketConfig : SocketConfig.DEFAULT, + context); } @Override public void upgrade( - final HttpClientConnection managedConn, - final HttpRoute route, - final HttpContext context) throws IOException { - Args.notNull(managedConn, "Managed Connection"); - Args.notNull(route, "HTTP route"); - final ManagedHttpClientConnection conn; - synchronized (managedConn) { - final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn); - conn = poolProxy.getConnection(); - } - this.connectionOperator.upgrade(conn, route.getTargetHost(), context); - } - - @Override - public void routeComplete( - final HttpClientConnection managedConn, - final HttpRoute route, + final ConnectionEndpoint endpoint, final HttpContext context) throws IOException { - Args.notNull(managedConn, "Managed Connection"); - Args.notNull(route, "HTTP route"); - synchronized (managedConn) { - final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn); - poolProxy.markRouteComplete(); - } - } - - @Override - public void shutdown() { - if (this.isShutDown.compareAndSet(false, true)) { - this.log.debug("Connection manager is shutting down"); - this.pool.shutdown(); - this.log.debug("Connection manager shut down"); - } + Args.notNull(endpoint, "Managed endpoint"); + final InternalConnectionEndpoint internalEndpoint = cast(endpoint); + final PoolEntry poolEntry = internalEndpoint.getValidatedPoolEntry(); + final HttpRoute route = poolEntry.getRoute(); + this.connectionOperator.upgrade(poolEntry.getConnection(), route.getTargetHost(), context); } @Override @@ -513,35 +457,11 @@ public class PoolingHttpClientConnection } public SocketConfig getDefaultSocketConfig() { - return this.configData.getDefaultSocketConfig(); + return this.defaultSocketConfig; } public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) { - this.configData.setDefaultSocketConfig(defaultSocketConfig); - } - - public ConnectionConfig getDefaultConnectionConfig() { - return this.configData.getDefaultConnectionConfig(); - } - - public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) { - this.configData.setDefaultConnectionConfig(defaultConnectionConfig); - } - - public SocketConfig getSocketConfig(final HttpHost host) { - return this.configData.getSocketConfig(host); - } - - public void setSocketConfig(final HttpHost host, final SocketConfig socketConfig) { - this.configData.setSocketConfig(host, socketConfig); - } - - public ConnectionConfig getConnectionConfig(final HttpHost host) { - return this.configData.getConnectionConfig(host); - } - - public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) { - this.configData.setConnectionConfig(host, connectionConfig); + this.defaultSocketConfig = defaultSocketConfig; } /** @@ -555,12 +475,11 @@ public class PoolingHttpClientConnection /** * Defines period of inactivity in milliseconds after which persistent connections must - * be re-validated prior to being {@link #leaseConnection(java.util.concurrent.Future, - * long, java.util.concurrent.TimeUnit) leased} to the consumer. Non-positive value passed - * to this method disables connection validation. This check helps detect connections - * that have become stale (half-closed) while kept inactive in the pool. + * be re-validated prior to being {@link #lease(HttpRoute, Object)} leased} to the consumer. + * Non-positive value passed to this method disables connection validation. This check helps + * detect connections that have become stale (half-closed) while kept inactive in the pool. * - * @see #leaseConnection(java.util.concurrent.Future, long, java.util.concurrent.TimeUnit) + * @see #lease(HttpRoute, Object) * * @since 4.4 */ @@ -571,14 +490,11 @@ public class PoolingHttpClientConnection static class ConfigData { private final Map socketConfigMap; - private final Map connectionConfigMap; private volatile SocketConfig defaultSocketConfig; - private volatile ConnectionConfig defaultConnectionConfig; ConfigData() { super(); this.socketConfigMap = new ConcurrentHashMap<>(); - this.connectionConfigMap = new ConcurrentHashMap<>(); } public SocketConfig getDefaultSocketConfig() { @@ -589,14 +505,6 @@ public class PoolingHttpClientConnection this.defaultSocketConfig = defaultSocketConfig; } - public ConnectionConfig getDefaultConnectionConfig() { - return this.defaultConnectionConfig; - } - - public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) { - this.defaultConnectionConfig = defaultConnectionConfig; - } - public SocketConfig getSocketConfig(final HttpHost host) { return this.socketConfigMap.get(host); } @@ -605,12 +513,76 @@ public class PoolingHttpClientConnection this.socketConfigMap.put(host, socketConfig); } - public ConnectionConfig getConnectionConfig(final HttpHost host) { - return this.connectionConfigMap.get(host); + } + + class InternalConnectionEndpoint extends ConnectionEndpoint { + + private final AtomicReference> poolEntryRef; + + InternalConnectionEndpoint( + final PoolEntry poolEntry) { + this.poolEntryRef = new AtomicReference<>(poolEntry); + } + + PoolEntry getPoolEntry() { + final PoolEntry poolEntry = poolEntryRef.get(); + if (poolEntry == null) { + throw new ConnectionShutdownException(); + } + return poolEntry; + } + + PoolEntry getValidatedPoolEntry() { + final PoolEntry poolEntry = getPoolEntry(); + final ManagedHttpClientConnection connection = poolEntry.getConnection(); + Asserts.check(connection != null && connection.isOpen(), "Endpoint is not connected"); + return poolEntry; + } + + PoolEntry detach() { + return poolEntryRef.getAndSet(null); + } + + @Override + public void shutdown() throws IOException { + final PoolEntry poolEntry = poolEntryRef.get(); + if (poolEntry != null) { + final HttpClientConnection connection = poolEntry.getConnection(); + poolEntry.discardConnection(); + if (connection != null) { + connection.shutdown(); + } + } + } + + @Override + public void close() throws IOException { + final PoolEntry poolEntry = poolEntryRef.get(); + if (poolEntry != null) { + poolEntry.discardConnection(); + } } - public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) { - this.connectionConfigMap.put(host, connectionConfig); + @Override + public boolean isConnected() { + final PoolEntry poolEntry = getPoolEntry(); + final ManagedHttpClientConnection connection = poolEntry.getConnection(); + return connection != null && connection.isOpen(); + } + + @Override + public void setSocketTimeout(final int timeout) { + getValidatedPoolEntry().getConnection().setSocketTimeout(timeout); + } + + @Override + public ClassicHttpResponse execute( + final ClassicHttpRequest request, + final HttpRequestExecutor requestExecutor, + final HttpContext context) throws IOException, HttpException { + Args.notNull(request, "HTTP request"); + Args.notNull(requestExecutor, "Request executor"); + return requestExecutor.execute(request, getValidatedPoolEntry().getConnection(), context); } } Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java Thu Feb 23 14:32:24 2017 @@ -30,14 +30,18 @@ package org.apache.hc.client5.http.impl. import java.util.concurrent.TimeUnit; import org.apache.hc.client5.http.DnsResolver; +import org.apache.hc.client5.http.HttpRoute; +import org.apache.hc.client5.http.SchemePortResolver; +import org.apache.hc.client5.http.io.ManagedHttpClientConnection; import org.apache.hc.client5.http.socket.ConnectionSocketFactory; import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory; import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.core5.http.config.ConnectionConfig; import org.apache.hc.core5.http.config.RegistryBuilder; import org.apache.hc.core5.http.config.SocketConfig; -import org.apache.hc.core5.util.TextUtils; +import org.apache.hc.core5.http.io.HttpConnectionFactory; +import org.apache.hc.core5.pool.ConnPoolListener; +import org.apache.hc.core5.pool.ConnPoolPolicy; /** * Builder for {@link PoolingHttpClientConnectionManager} instances. @@ -67,11 +71,13 @@ import org.apache.hc.core5.util.TextUtil */ public class PoolingHttpClientConnectionManagerBuilder { + private HttpConnectionFactory connectionFactory; private LayeredConnectionSocketFactory sslSocketFactory; + private SchemePortResolver schemePortResolver; private DnsResolver dnsResolver; - + private ConnPoolPolicy connPoolPolicy; + private ConnPoolListener connPoolListener; private SocketConfig defaultSocketConfig; - private ConnectionConfig defaultConnectionConfig; private boolean systemProperties; @@ -91,7 +97,16 @@ public class PoolingHttpClientConnection } /** - * Assigns {@link LayeredConnectionSocketFactory} instance for SSL connections. + * Assigns {@link HttpConnectionFactory} instance. + */ + public final PoolingHttpClientConnectionManagerBuilder setConnectionFactory( + final HttpConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; + return this; + } + + /** + * Assigns {@link LayeredConnectionSocketFactory} instance. */ public final PoolingHttpClientConnectionManagerBuilder setSSLSocketFactory( final LayeredConnectionSocketFactory sslSocketFactory) { @@ -100,6 +115,38 @@ public class PoolingHttpClientConnection } /** + * Assigns {@link DnsResolver} instance. + */ + public final PoolingHttpClientConnectionManagerBuilder setDnsResolver(final DnsResolver dnsResolver) { + this.dnsResolver = dnsResolver; + return this; + } + + /** + * Assigns {@link SchemePortResolver} instance. + */ + public final PoolingHttpClientConnectionManagerBuilder setSchemePortResolver(final SchemePortResolver schemePortResolver) { + this.schemePortResolver = schemePortResolver; + return this; + } + + /** + * Assigns {@link ConnPoolPolicy} value. + */ + public final PoolingHttpClientConnectionManagerBuilder setConnPoolPolicy(final ConnPoolPolicy connPoolPolicy) { + this.connPoolPolicy = connPoolPolicy; + return this; + } + + /** + * Assigns {@link ConnPoolListener} instance. + */ + public final PoolingHttpClientConnectionManagerBuilder setConnPoolListener(final ConnPoolListener connPoolListener) { + this.connPoolListener = connPoolListener; + return this; + } + + /** * Assigns maximum total connection value. */ public final PoolingHttpClientConnectionManagerBuilder setMaxConnTotal(final int maxConnTotal) { @@ -124,17 +171,7 @@ public class PoolingHttpClientConnection } /** - * Assigns default {@link ConnectionConfig}. - */ - public final PoolingHttpClientConnectionManagerBuilder setDefaultConnectionConfig(final ConnectionConfig config) { - this.defaultConnectionConfig = config; - return this; - } - - /** * Sets maximum time to live for persistent connections - * - * @since 4.4 */ public final PoolingHttpClientConnectionManagerBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) { this.connTimeToLive = connTimeToLive; @@ -154,14 +191,6 @@ public class PoolingHttpClientConnection } /** - * Assigns {@link DnsResolver} instance. - */ - public final PoolingHttpClientConnectionManagerBuilder setDnsResolver(final DnsResolver dnsResolver) { - this.dnsResolver = dnsResolver; - return this; - } - - /** * Use system properties when creating and configuring default * implementations. */ @@ -170,13 +199,6 @@ public class PoolingHttpClientConnection return this; } - private static String[] split(final String s) { - if (TextUtils.isBlank(s)) { - return null; - } - return s.split(" *, *"); - } - public PoolingHttpClientConnectionManager build() { @SuppressWarnings("resource") final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager( @@ -187,18 +209,17 @@ public class PoolingHttpClientConnection SSLConnectionSocketFactory.getSystemSocketFactory() : SSLConnectionSocketFactory.getSocketFactory())) .build(), - null, - null, + connectionFactory, + schemePortResolver, dnsResolver, + connPoolPolicy, + connPoolListener, connTimeToLive, connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS); poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity); if (defaultSocketConfig != null) { poolingmgr.setDefaultSocketConfig(defaultSocketConfig); } - if (defaultConnectionConfig != null) { - poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig); - } if (maxConnTotal > 0) { poolingmgr.setMaxTotal(maxConnTotal); } Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingInputStream.java (from r1784071, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingInputStream.java) URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingInputStream.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingInputStream.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingInputStream.java&r1=1784071&r2=1784138&rev=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingInputStream.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingInputStream.java Thu Feb 23 14:32:24 2017 @@ -25,16 +25,11 @@ * */ -package org.apache.hc.client5.http.impl.io; +package org.apache.hc.client5.http.impl.logging; import java.io.IOException; import java.io.InputStream; -/** - * Internal class. - * - * @since 4.3 - */ class LoggingInputStream extends InputStream { private final InputStream in; Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingInputStream.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingInputStream.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingInputStream.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingOutputStream.java (from r1784071, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingOutputStream.java) URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingOutputStream.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingOutputStream.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingOutputStream.java&r1=1784071&r2=1784138&rev=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingOutputStream.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingOutputStream.java Thu Feb 23 14:32:24 2017 @@ -25,7 +25,7 @@ * */ -package org.apache.hc.client5.http.impl.io; +package org.apache.hc.client5.http.impl.logging; import java.io.IOException; import java.io.OutputStream; @@ -49,6 +49,7 @@ class LoggingOutputStream extends Output @Override public void write(final int b) throws IOException { try { + out.write(b); wire.output(b); } catch (final IOException ex) { wire.output("[write] I/O error: " + ex.getMessage()); Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingOutputStream.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingOutputStream.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingOutputStream.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingSocketHolder.java (from r1784071, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingSocketHolder.java) URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingSocketHolder.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingSocketHolder.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingSocketHolder.java&r1=1784071&r2=1784138&rev=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/LoggingSocketHolder.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingSocketHolder.java Thu Feb 23 14:32:24 2017 @@ -25,7 +25,7 @@ * */ -package org.apache.hc.client5.http.impl.io; +package org.apache.hc.client5.http.impl.logging; import java.io.IOException; import java.io.InputStream; @@ -33,14 +33,15 @@ import java.io.OutputStream; import java.net.Socket; import org.apache.hc.core5.http.impl.io.SocketHolder; +import org.apache.logging.log4j.Logger; -class LoggingSocketHolder extends SocketHolder { +public class LoggingSocketHolder extends SocketHolder { private final Wire wire; - LoggingSocketHolder(final Socket socket, final Wire wire) { + public LoggingSocketHolder(final Socket socket, final String id, final Logger log) { super(socket); - this.wire = wire; + this.wire = new Wire(log, id); } @Override Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingSocketHolder.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingSocketHolder.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/LoggingSocketHolder.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/Wire.java (from r1784071, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/Wire.java) URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/Wire.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/Wire.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/Wire.java&r1=1784071&r2=1784138&rev=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/Wire.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/Wire.java Thu Feb 23 14:32:24 2017 @@ -24,52 +24,36 @@ * . * */ -package org.apache.hc.client5.http.impl.io; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; +package org.apache.hc.client5.http.impl.logging; + +import java.nio.ByteBuffer; -import org.apache.hc.core5.annotation.Contract; -import org.apache.hc.core5.annotation.ThreadingBehavior; import org.apache.hc.core5.util.Args; import org.apache.logging.log4j.Logger; -/** - * Logs data to the wire LOG. - * - * @since 4.0 - */ -@Contract(threading = ThreadingBehavior.IMMUTABLE) class Wire { private final Logger log; private final String id; - /** - * @since 4.3 - */ - public Wire(final Logger log, final String id) { + Wire(final Logger log, final String id) { + super(); this.log = log; this.id = id; } - public Wire(final Logger log) { - this(log, ""); - } - - private void wire(final String header, final InputStream instream) - throws IOException { + private void wire(final String header, final byte[] b, final int pos, final int off) { final StringBuilder buffer = new StringBuilder(); - int ch; - while ((ch = instream.read()) != -1) { + for (int i = 0; i < off; i++) { + final int ch = b[pos + i]; if (ch == 13) { buffer.append("[\\r]"); } else if (ch == 10) { buffer.append("[\\n]\""); buffer.insert(0, "\""); buffer.insert(0, header); - log.debug(id + " " + buffer.toString()); + this.log.debug(this.id + " " + buffer.toString()); buffer.setLength(0); } else if ((ch < 32) || (ch > 127)) { buffer.append("[0x"); @@ -83,70 +67,73 @@ class Wire { buffer.append('\"'); buffer.insert(0, '\"'); buffer.insert(0, header); - log.debug(id + " " + buffer.toString()); + this.log.debug(this.id + " " + buffer.toString()); } } - public boolean enabled() { - return log.isDebugEnabled(); - } - - public void output(final InputStream outstream) - throws IOException { - Args.notNull(outstream, "Output"); - wire(">> ", outstream); - } - - public void input(final InputStream instream) - throws IOException { - Args.notNull(instream, "Input"); - wire("<< ", instream); + public boolean isEnabled() { + return this.log.isDebugEnabled(); } - public void output(final byte[] b, final int off, final int len) - throws IOException { + public void output(final byte[] b, final int pos, final int off) { Args.notNull(b, "Output"); - wire(">> ", new ByteArrayInputStream(b, off, len)); + wire(">> ", b, pos, off); } - public void input(final byte[] b, final int off, final int len) - throws IOException { + public void input(final byte[] b, final int pos, final int off) { Args.notNull(b, "Input"); - wire("<< ", new ByteArrayInputStream(b, off, len)); + wire("<< ", b, pos, off); } - public void output(final byte[] b) - throws IOException { + public void output(final byte[] b) { Args.notNull(b, "Output"); - wire(">> ", new ByteArrayInputStream(b)); + output(b, 0, b.length); } - public void input(final byte[] b) - throws IOException { + public void input(final byte[] b) { Args.notNull(b, "Input"); - wire("<< ", new ByteArrayInputStream(b)); + input(b, 0, b.length); } - public void output(final int b) - throws IOException { + public void output(final int b) { output(new byte[] {(byte) b}); } - public void input(final int b) - throws IOException { + public void input(final int b) { input(new byte[] {(byte) b}); } - public void output(final String s) - throws IOException { + public void output(final String s) { Args.notNull(s, "Output"); output(s.getBytes()); } - public void input(final String s) - throws IOException { + public void input(final String s) { Args.notNull(s, "Input"); input(s.getBytes()); } + + public void output(final ByteBuffer b) { + Args.notNull(b, "Output"); + if (b.hasArray()) { + output(b.array(), b.arrayOffset() + b.position(), b.remaining()); + } else { + final byte[] tmp = new byte[b.remaining()]; + b.get(tmp); + output(tmp); + } + } + + public void input(final ByteBuffer b) { + Args.notNull(b, "Input"); + if (b.hasArray()) { + input(b.array(), b.arrayOffset() + b.position(), b.remaining()); + } else { + final byte[] tmp = new byte[b.remaining()]; + b.get(tmp); + input(tmp); + } + } + } Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/Wire.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/Wire.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/logging/Wire.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultProxyRoutePlanner.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultProxyRoutePlanner.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultProxyRoutePlanner.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultProxyRoutePlanner.java Thu Feb 23 14:32:24 2017 @@ -32,7 +32,6 @@ import org.apache.hc.core5.annotation.Co import org.apache.hc.core5.annotation.ThreadingBehavior; import org.apache.hc.core5.http.HttpException; import org.apache.hc.core5.http.HttpHost; -import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.util.Args; @@ -59,7 +58,6 @@ public class DefaultProxyRoutePlanner ex @Override protected HttpHost determineProxy( final HttpHost target, - final HttpRequest request, final HttpContext context) throws HttpException { return proxy; } Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java Thu Feb 23 14:32:24 2017 @@ -43,7 +43,7 @@ import org.apache.hc.core5.http.HttpHost import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.net.URIAuthority; /** * Default implementation of an {@link HttpRoutePlanner}. It will not make use of @@ -63,11 +63,7 @@ public class DefaultRoutePlanner impleme } @Override - public HttpRoute determineRoute( - final HttpHost host, - final HttpRequest request, - final HttpContext context) throws HttpException { - Args.notNull(request, "Request"); + public HttpRoute determineRoute(final HttpHost host, final HttpContext context) throws HttpException { if (host == null) { throw new ProtocolException("Target host is not specified"); } @@ -76,7 +72,7 @@ public class DefaultRoutePlanner impleme final InetAddress local = config.getLocalAddress(); HttpHost proxy = config.getProxy(); if (proxy == null) { - proxy = determineProxy(host, request, context); + proxy = determineProxy(host, context); } final HttpHost target; @@ -100,6 +96,20 @@ public class DefaultRoutePlanner impleme } } + @Override + public HttpHost determineTargetHost(final HttpRequest request, final HttpContext context) throws HttpException { + final URIAuthority authority = request.getAuthority(); + if (authority != null) { + final String scheme = request.getScheme(); + if (scheme == null) { + throw new ProtocolException("Protocol scheme is not specified"); + } + return new HttpHost(authority, scheme); + } else { + return null; + } + } + /** * This implementation returns null. * @@ -107,7 +117,6 @@ public class DefaultRoutePlanner impleme */ protected HttpHost determineProxy( final HttpHost target, - final HttpRequest request, final HttpContext context) throws HttpException { return null; } Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java Thu Feb 23 14:32:24 2017 @@ -39,7 +39,6 @@ import org.apache.hc.core5.annotation.Co import org.apache.hc.core5.annotation.ThreadingBehavior; import org.apache.hc.core5.http.HttpException; import org.apache.hc.core5.http.HttpHost; -import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.protocol.HttpContext; /** @@ -73,10 +72,7 @@ public class SystemDefaultRoutePlanner e } @Override - protected HttpHost determineProxy( - final HttpHost target, - final HttpRequest request, - final HttpContext context) throws HttpException { + protected HttpHost determineProxy(final HttpHost target, final HttpContext context) throws HttpException { final URI targetURI; try { targetURI = new URI(target.toURI()); Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicResponseHandler.java (from r1784071, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/BasicResponseHandler.java) URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicResponseHandler.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicResponseHandler.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/BasicResponseHandler.java&r1=1784071&r2=1784138&rev=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/BasicResponseHandler.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicResponseHandler.java Thu Feb 23 14:32:24 2017 @@ -25,11 +25,10 @@ * */ -package org.apache.hc.client5.http.impl; +package org.apache.hc.client5.http.impl.sync; import java.io.IOException; -import org.apache.hc.client5.http.impl.sync.AbstractResponseHandler; import org.apache.hc.client5.http.protocol.ClientProtocolException; import org.apache.hc.core5.annotation.Contract; import org.apache.hc.core5.annotation.ThreadingBehavior; @@ -39,13 +38,13 @@ import org.apache.hc.core5.http.ParseExc import org.apache.hc.core5.http.io.entity.EntityUtils; /** - * A {@link org.apache.hc.client5.http.sync.ResponseHandler} that returns the response body as a String + * A {@link org.apache.hc.core5.http.io.ResponseHandler} that returns the response body as a String * for successful (2xx) responses. If the response code was >= 300, the response * body is consumed and an {@link org.apache.hc.client5.http.protocol.HttpResponseException} is thrown. *

* If this is used with * {@link org.apache.hc.client5.http.sync.HttpClient#execute( - * org.apache.hc.core5.http.ClassicHttpRequest, org.apache.hc.client5.http.sync.ResponseHandler)}, + * org.apache.hc.core5.http.ClassicHttpRequest, org.apache.hc.core5.http.io.ResponseHandler)}, * HttpClient may handle redirects (3xx responses) internally. *

* Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicResponseHandler.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicResponseHandler.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicResponseHandler.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/EndpointHolder.java (from r1784071, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ConnectionHolder.java) URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/EndpointHolder.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/EndpointHolder.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ConnectionHolder.java&r1=1784071&r2=1784138&rev=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ConnectionHolder.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/EndpointHolder.java Thu Feb 23 14:32:24 2017 @@ -32,12 +32,11 @@ import java.io.IOException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.hc.client5.http.io.ConnectionReleaseTrigger; +import org.apache.hc.client5.http.io.ConnectionEndpoint; import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.core5.annotation.Contract; import org.apache.hc.core5.annotation.ThreadingBehavior; import org.apache.hc.core5.concurrent.Cancellable; -import org.apache.hc.core5.http.io.HttpClientConnection; import org.apache.logging.log4j.Logger; /** @@ -46,26 +45,25 @@ import org.apache.logging.log4j.Logger; * @since 4.3 */ @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL) -class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeable { +class EndpointHolder implements Cancellable, Closeable { private final Logger log; private final HttpClientConnectionManager manager; - private final HttpClientConnection managedConn; + private final ConnectionEndpoint endpoint; private final AtomicBoolean released; private volatile boolean reusable; private volatile Object state; private volatile long validDuration; - private volatile TimeUnit tunit; - public ConnectionHolder( + public EndpointHolder( final Logger log, final HttpClientConnectionManager manager, - final HttpClientConnection managedConn) { + final ConnectionEndpoint endpoint) { super(); this.log = log; this.manager = manager; - this.managedConn = managedConn; + this.endpoint = endpoint; this.released = new AtomicBoolean(false); } @@ -86,54 +84,46 @@ class ConnectionHolder implements Connec } public void setValidFor(final long duration, final TimeUnit tunit) { - synchronized (this.managedConn) { - this.validDuration = duration; - this.tunit = tunit; - } + this.validDuration = (tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(duration); } private void releaseConnection(final boolean reusable) { if (this.released.compareAndSet(false, true)) { - synchronized (this.managedConn) { + synchronized (this.endpoint) { if (reusable) { - this.manager.releaseConnection(this.managedConn, - this.state, this.validDuration, this.tunit); + this.manager.release(this.endpoint, this.state, this.validDuration, TimeUnit.MILLISECONDS); } else { try { - this.managedConn.close(); + this.endpoint.close(); log.debug("Connection discarded"); } catch (final IOException ex) { if (this.log.isDebugEnabled()) { this.log.debug(ex.getMessage(), ex); } } finally { - this.manager.releaseConnection( - this.managedConn, null, 0, TimeUnit.MILLISECONDS); + this.manager.release(this.endpoint, null, 0, TimeUnit.MILLISECONDS); } } } } } - @Override public void releaseConnection() { releaseConnection(this.reusable); } - @Override public void abortConnection() { if (this.released.compareAndSet(false, true)) { - synchronized (this.managedConn) { + synchronized (this.endpoint) { try { - this.managedConn.shutdown(); + this.endpoint.shutdown(); log.debug("Connection discarded"); } catch (final IOException ex) { if (this.log.isDebugEnabled()) { this.log.debug(ex.getMessage(), ex); } } finally { - this.manager.releaseConnection( - this.managedConn, null, 0, TimeUnit.MILLISECONDS); + this.manager.release(this.endpoint, null, 0, TimeUnit.MILLISECONDS); } } } Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/EndpointHolder.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/EndpointHolder.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/EndpointHolder.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java Thu Feb 23 14:32:24 2017 @@ -99,7 +99,7 @@ import org.apache.hc.core5.http.protocol import org.apache.hc.core5.http.protocol.RequestContent; import org.apache.hc.core5.http.protocol.RequestTargetHost; import org.apache.hc.core5.http.protocol.RequestUserAgent; -import org.apache.hc.core5.util.TextUtils; +import org.apache.hc.core5.pool.ConnPoolControl; import org.apache.hc.core5.util.VersionInfo; /** @@ -547,14 +547,11 @@ public class HttpClientBuilder { * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order * to stop and release the background thread. *

- * Please note this method has no effect if the instance of HttpClient is configuted to + * Please note this method has no effect if the instance of HttpClient is configured to * use a shared connection manager. - *

- * Please note this method may not be used when the instance of HttpClient is created - * inside an EJB container. * * @see #setConnectionManagerShared(boolean) - * @see HttpClientConnectionManager#closeExpired() + * @see ConnPoolControl#closeExpired() * * @since 4.4 */ @@ -570,14 +567,11 @@ public class HttpClientBuilder { * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order * to stop and release the background thread. *

- * Please note this method has no effect if the instance of HttpClient is configuted to + * Please note this method has no effect if the instance of HttpClient is configured to * use a shared connection manager. - *

- * Please note this method may not be used when the instance of HttpClient is created - * inside an EJB container. * * @see #setConnectionManagerShared(boolean) - * @see HttpClientConnectionManager#closeExpired() + * @see ConnPoolControl#closeIdle(long, TimeUnit) * * @param maxIdleTime maximum time persistent connections can stay idle while kept alive * in the connection pool. Connections whose inactivity period exceeds this value will @@ -652,13 +646,6 @@ public class HttpClientBuilder { closeables.add(closeable); } - private static String[] split(final String s) { - if (TextUtils.isBlank(s)) { - return null; - } - return s.split(" *, *"); - } - public CloseableHttpClient build() { // Create main request executor // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version @@ -873,34 +860,26 @@ public class HttpClientBuilder { if (closeablesCopy == null) { closeablesCopy = new ArrayList<>(1); } - final HttpClientConnectionManager cm = connManagerCopy; - if (evictExpiredConnections || evictIdleConnections) { - final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm, - maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS); - closeablesCopy.add(new Closeable() { - - @Override - public void close() throws IOException { - connectionEvictor.shutdown(); - } - - }); - connectionEvictor.start(); - } - closeablesCopy.add(new Closeable() { - - @Override - public void close() throws IOException { - cm.shutdown(); - } + if (connManagerCopy instanceof ConnPoolControl) { + final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl) connManagerCopy, + maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS); + closeablesCopy.add(new Closeable() { - }); + @Override + public void close() throws IOException { + connectionEvictor.shutdown(); + } + + }); + connectionEvictor.start(); + } + } + closeablesCopy.add(connManagerCopy); } return new InternalHttpClient( execChain, - connManagerCopy, routePlannerCopy, cookieSpecRegistryCopy, authSchemeRegistryCopy, Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/IdleConnectionEvictor.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/IdleConnectionEvictor.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/IdleConnectionEvictor.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/IdleConnectionEvictor.java Thu Feb 23 14:32:24 2017 @@ -30,7 +30,8 @@ package org.apache.hc.client5.http.impl. import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; -import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.impl.DefaultThreadFactory; +import org.apache.hc.core5.pool.ConnPoolControl; import org.apache.hc.core5.util.Args; /** @@ -41,7 +42,6 @@ import org.apache.hc.core5.util.Args; */ public final class IdleConnectionEvictor { - private final HttpClientConnectionManager connectionManager; private final ThreadFactory threadFactory; private final Thread thread; private final long sleepTimeMs; @@ -50,12 +50,12 @@ public final class IdleConnectionEvictor private volatile Exception exception; public IdleConnectionEvictor( - final HttpClientConnectionManager connectionManager, + final ConnPoolControl connectionManager, final ThreadFactory threadFactory, final long sleepTime, final TimeUnit sleepTimeUnit, final long maxIdleTime, final TimeUnit maxIdleTimeUnit) { - this.connectionManager = Args.notNull(connectionManager, "Connection manager"); - this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory(); + Args.notNull(connectionManager, "Connection manager"); + this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory("idle-connection-evictor", true); this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime; this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime; this.thread = this.threadFactory.newThread(new Runnable() { @@ -78,14 +78,14 @@ public final class IdleConnectionEvictor } public IdleConnectionEvictor( - final HttpClientConnectionManager connectionManager, + final ConnPoolControl connectionManager, final long sleepTime, final TimeUnit sleepTimeUnit, final long maxIdleTime, final TimeUnit maxIdleTimeUnit) { this(connectionManager, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit); } public IdleConnectionEvictor( - final HttpClientConnectionManager connectionManager, + final ConnPoolControl connectionManager, final long maxIdleTime, final TimeUnit maxIdleTimeUnit) { this(connectionManager, null, maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS, @@ -108,16 +108,4 @@ public final class IdleConnectionEvictor thread.join((tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(time)); } - static class DefaultThreadFactory implements ThreadFactory { - - @Override - public Thread newThread(final Runnable r) { - final Thread t = new Thread(r, "Connection evictor"); - t.setDaemon(true); - return t; - } - - } - - } Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java?rev=1784138&r1=1784137&r2=1784138&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java (original) +++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java Thu Feb 23 14:32:24 2017 @@ -37,7 +37,6 @@ import org.apache.hc.client5.http.auth.C import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.cookie.CookieSpecProvider; import org.apache.hc.client5.http.cookie.CookieStore; -import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.client5.http.methods.Configurable; import org.apache.hc.client5.http.methods.HttpExecutionAware; import org.apache.hc.client5.http.methods.RoutedHttpRequest; @@ -70,7 +69,6 @@ class InternalHttpClient extends Closeab private final Logger log = LogManager.getLogger(getClass()); private final ClientExecChain execChain; - private final HttpClientConnectionManager connManager; private final HttpRoutePlanner routePlanner; private final Lookup cookieSpecRegistry; private final Lookup authSchemeRegistry; @@ -81,7 +79,6 @@ class InternalHttpClient extends Closeab public InternalHttpClient( final ClientExecChain execChain, - final HttpClientConnectionManager connManager, final HttpRoutePlanner routePlanner, final Lookup cookieSpecRegistry, final Lookup authSchemeRegistry, @@ -91,10 +88,8 @@ class InternalHttpClient extends Closeab final List closeables) { super(); Args.notNull(execChain, "HTTP client exec chain"); - Args.notNull(connManager, "HTTP connection manager"); Args.notNull(routePlanner, "HTTP route planner"); this.execChain = execChain; - this.connManager = connManager; this.routePlanner = routePlanner; this.cookieSpecRegistry = cookieSpecRegistry; this.authSchemeRegistry = authSchemeRegistry; @@ -105,10 +100,11 @@ class InternalHttpClient extends Closeab } private HttpRoute determineRoute( - final HttpHost target, + final HttpHost host, final HttpRequest request, final HttpContext context) throws HttpException { - return this.routePlanner.determineRoute(target, request, context); + final HttpHost target = host != null ? host : this.routePlanner.determineTargetHost(request, context); + return this.routePlanner.determineRoute(target, context); } private void setupContext(final HttpClientContext context) {