From bfbc573cbddfe2c607771faf02c905b837769eb9 Mon Sep 17 00:00:00 2001
From: Oleg Kalnichevski
Date: Thu, 13 Dec 2012 14:22:28 +0000
Subject: [PATCH] Added methods to set SocketConfig and ConnectionConfig for
PoolingHttpClientConnectionManager and HttpClientBuilder
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1421309 13f79535-47bb-0310-9956-ffa450edef68
---
.../http/impl/client/HttpClientBuilder.java | 30 +-
.../java/org/apache/http/impl/conn/CPool.java | 12 +-
.../conn/HttpClientConnectionManagerBase.java | 269 --------
.../PoolingHttpClientConnectionManager.java | 305 ++++++++-
.../TestHttpClientConnectionManagerBase.java | 198 ------
...estPoolingHttpClientConnectionManager.java | 578 ++++--------------
6 files changed, 411 insertions(+), 981 deletions(-)
delete mode 100644 httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionManagerBase.java
delete mode 100644 httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionManagerBase.java
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java b/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
index b79380c6b..8c7c41ae4 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
@@ -60,8 +60,10 @@ import org.apache.http.client.protocol.RequestDefaultHeaders;
import org.apache.http.client.protocol.RequestExpectContinue;
import org.apache.http.client.protocol.ResponseContentEncoding;
import org.apache.http.client.protocol.ResponseProcessCookies;
+import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Lookup;
import org.apache.http.config.RegistryBuilder;
+import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.SchemePortResolver;
@@ -125,7 +127,7 @@ import org.apache.http.util.VersionInfo;
* http.nonProxyHosts
* http.keepAlive
* http.maxConnections
- * http.user
+ * http.agent
*
*
*
@@ -164,7 +166,9 @@ public class HttpClientBuilder {
private CredentialsProvider credentialsProvider;
private String userAgent;
private Collection extends Header> defaultHeaders;
- private RequestConfig defaultConfig;
+ private SocketConfig defaultSocketConfig;
+ private ConnectionConfig defaultConnectionConfig;
+ private RequestConfig defaultRequestConfig;
private boolean systemProperties;
private boolean redirectHandlingDisabled;
@@ -379,8 +383,18 @@ public class HttpClientBuilder {
return this;
}
- public final HttpClientBuilder setDefaultConfig(final RequestConfig defaultConfig) {
- this.defaultConfig = defaultConfig;
+ public final HttpClientBuilder setDefaultSocketConfig(final SocketConfig config) {
+ this.defaultSocketConfig = config;
+ return this;
+ }
+
+ public final HttpClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
+ this.defaultConnectionConfig = config;
+ return this;
+ }
+
+ public final HttpClientBuilder setDefaultRequestConfig(final RequestConfig config) {
+ this.defaultRequestConfig = config;
return this;
}
@@ -438,6 +452,12 @@ public class HttpClientBuilder {
.register("http", PlainSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build());
+ if (defaultSocketConfig != null) {
+ poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
+ }
+ if (defaultConnectionConfig != null) {
+ poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
+ }
if (systemProperties) {
String s = System.getProperty("http.keepAlive");
if ("true".equalsIgnoreCase(s)) {
@@ -659,7 +679,7 @@ public class HttpClientBuilder {
authSchemeRegistry,
defaultCookieStore,
defaultCredentialsProvider,
- defaultConfig != null ? defaultConfig : RequestConfig.DEFAULT);
+ defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT);
}
}
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java b/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java
index 2285c766d..0ef1d92bb 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java
@@ -26,7 +26,6 @@
*/
package org.apache.http.impl.conn;
-import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
@@ -52,9 +51,10 @@ class CPool extends AbstractConnPool connFactory,
final int defaultMaxPerRoute, final int maxTotal,
final long timeToLive, final TimeUnit tunit) {
- super(new InternalConnFactory(), defaultMaxPerRoute, maxTotal);
+ super(connFactory, defaultMaxPerRoute, maxTotal);
this.timeToLive = timeToLive;
this.tunit = tunit;
}
@@ -65,12 +65,4 @@ class CPool extends AbstractConnPool {
-
- public SocketClientConnection create(final HttpRoute route) throws IOException {
- return new SocketClientConnectionImpl(8 * 1024);
- }
-
- }
-
}
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionManagerBase.java b/httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionManagerBase.java
deleted file mode 100644
index ec4a8b597..000000000
--- a/httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionManagerBase.java
+++ /dev/null
@@ -1,269 +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
- * .
- *
- */
-
-package org.apache.http.impl.conn;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.apache.http.HttpClientConnection;
-import org.apache.http.HttpHost;
-import org.apache.http.annotation.ThreadSafe;
-import org.apache.http.config.ConnectionConfig;
-import org.apache.http.config.Lookup;
-import org.apache.http.config.SocketConfig;
-import org.apache.http.conn.ConnectionPoolTimeoutException;
-import org.apache.http.conn.ConnectionRequest;
-import org.apache.http.conn.DnsResolver;
-import org.apache.http.conn.HttpClientConnectionManager;
-import org.apache.http.conn.SchemePortResolver;
-import org.apache.http.conn.SocketClientConnection;
-import org.apache.http.conn.routing.HttpRoute;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.pool.ConnPool;
-import org.apache.http.protocol.HttpContext;
-
-/**
- * Base class for {@link HttpClientConnectionManager} implementations.
- * This class primarily provides consistent implementation of
- * {@link #connect(HttpClientConnection, HttpHost, InetAddress, HttpContext, HttpParams)}
- * and {@link #upgrade(HttpClientConnection, HttpHost, HttpContext, HttpParams)}
- * methods for all standard connection managers shipped with HttpClient.
- *
- * @since 4.3
- */
-@ThreadSafe
-abstract class HttpClientConnectionManagerBase implements HttpClientConnectionManager {
-
- private final ConnPool pool;
- private final HttpClientConnectionOperator connectionOperator;
- private final Map socketConfigMap;
- private final Map connectionConfigMap;
- private volatile SocketConfig defaultSocketConfig;
- private volatile ConnectionConfig defaultConnectionConfig;
-
- HttpClientConnectionManagerBase(
- final ConnPool pool,
- final Lookup socketFactoryRegistry,
- final SchemePortResolver schemePortResolver,
- final DnsResolver dnsResolver) {
- super();
- if (pool == null) {
- throw new IllegalArgumentException("Connection pool may nor be null");
- }
- this.pool = pool;
- this.connectionOperator = new HttpClientConnectionOperator(
- socketFactoryRegistry, schemePortResolver, dnsResolver);
- this.socketConfigMap = new ConcurrentHashMap();
- this.connectionConfigMap = new ConcurrentHashMap();
- this.defaultSocketConfig = SocketConfig.DEFAULT;
- this.defaultConnectionConfig = ConnectionConfig.DEFAULT;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- shutdown();
- } finally {
- super.finalize();
- }
- }
-
- protected void onConnectionLeaseRequest(final HttpRoute route, final Object state) {
- }
-
- protected void onConnectionLease(final CPoolEntry entry) {
- }
-
- protected void onConnectionKeepAlive(final CPoolEntry entry) {
- }
-
- protected void onConnectionRelease(final CPoolEntry entry) {
- }
-
- public ConnectionRequest requestConnection(
- final HttpRoute route,
- final Object state) {
- if (route == null) {
- throw new IllegalArgumentException("HTTP route may not be null");
- }
- onConnectionLeaseRequest(route, state);
- final Future future = this.pool.lease(route, state, null);
- return new ConnectionRequest() {
-
- public boolean cancel() {
- return future.cancel(true);
- }
-
- public HttpClientConnection get(
- final long timeout,
- final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
- return leaseConnection(future, timeout, tunit);
- }
-
- };
-
- }
-
- protected HttpClientConnection leaseConnection(
- final Future future,
- final long timeout,
- final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
- CPoolEntry entry;
- try {
- entry = future.get(timeout, tunit);
- if (entry == null || future.isCancelled()) {
- throw new InterruptedException();
- }
- if (entry.getConnection() == null) {
- throw new IllegalStateException("Pool entry with no connection");
- }
- onConnectionLease(entry);
- return CPoolProxy.newProxy(entry);
- } catch (ExecutionException ex) {
- Throwable cause = ex.getCause();
- if (cause == null) {
- cause = ex;
- }
- InterruptedException intex = new InterruptedException();
- intex.initCause(cause);
- throw intex;
- } catch (TimeoutException ex) {
- throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
- }
- }
-
- public void releaseConnection(
- final HttpClientConnection managedConn,
- final Object state,
- final long keepalive, final TimeUnit tunit) {
- if (managedConn == null) {
- throw new IllegalArgumentException("Managed connection may not be null");
- }
- synchronized (managedConn) {
- CPoolEntry entry = CPoolProxy.detach(managedConn);
- if (entry == null) {
- return;
- }
- SocketClientConnection conn = entry.getConnection();
- try {
- if (conn.isOpen()) {
- entry.setState(state);
- entry.updateExpiry(keepalive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
- onConnectionKeepAlive(entry);
- }
- } finally {
- this.pool.release(entry, conn.isOpen());
- onConnectionRelease(entry);
- }
- }
- }
-
- public void connect(
- final HttpClientConnection managedConn,
- final HttpHost host,
- final InetAddress local,
- final int connectTimeout,
- final HttpContext context) throws IOException {
- if (managedConn == null) {
- throw new IllegalArgumentException("Connection may not be null");
- }
- SocketClientConnection conn;
- synchronized (managedConn) {
- CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
- conn = entry.getConnection();
- }
- SocketConfig socketConfig = this.socketConfigMap.get(host);
- if (socketConfig == null) {
- socketConfig = this.defaultSocketConfig;
- }
- ConnectionConfig connConfig = this.connectionConfigMap.get(host);
- if (connConfig == null) {
- connConfig = this.defaultConnectionConfig;
- }
-
- InetSocketAddress localAddress = local != null ? new InetSocketAddress(local, 0) : null;
- this.connectionOperator.connect(conn, host, localAddress,
- connectTimeout, socketConfig, context);
- }
-
- public void upgrade(
- final HttpClientConnection managedConn,
- final HttpHost host,
- final HttpContext context) throws IOException {
- if (managedConn == null) {
- throw new IllegalArgumentException("Connection may not be null");
- }
- SocketClientConnection conn;
- synchronized (managedConn) {
- CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
- conn = entry.getConnection();
- }
- this.connectionOperator.upgrade(conn, host, context);
- }
-
- public SocketConfig getDefaultSocketConfig() {
- return this.defaultSocketConfig;
- }
-
- public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) {
- this.defaultSocketConfig = defaultSocketConfig != null ? defaultSocketConfig :
- SocketConfig.DEFAULT;
- }
-
- public ConnectionConfig getDefaultConnectionConfig() {
- return this.defaultConnectionConfig;
- }
-
- public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) {
- this.defaultConnectionConfig = defaultConnectionConfig != null ? defaultConnectionConfig :
- ConnectionConfig.DEFAULT;
- }
-
- public SocketConfig getSocketConfig(final HttpHost host) {
- return this.socketConfigMap.get(host);
- }
-
- public void setSocketConfig(final HttpHost host, final SocketConfig socketConfig) {
- this.socketConfigMap.put(host, socketConfig);
- }
-
- public ConnectionConfig getConnectionConfig(final HttpHost host) {
- return this.connectionConfigMap.get(host);
- }
-
- public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) {
- this.connectionConfigMap.put(host, connectionConfig);
- }
-
-}
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java b/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
index 31665585f..83bf51277 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
@@ -27,22 +27,40 @@
package org.apache.http.impl.conn;
import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpHost;
import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.config.ConnectionConfig;
+import org.apache.http.config.Lookup;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.DnsResolver;
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.SchemePortResolver;
+import org.apache.http.conn.SocketClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.pool.ConnFactory;
import org.apache.http.pool.ConnPoolControl;
import org.apache.http.pool.PoolStats;
+import org.apache.http.protocol.HttpContext;
/**
* ClientConnectionPoolManager maintains a pool of
@@ -63,11 +81,13 @@ import org.apache.http.pool.PoolStats;
* @since 4.3
*/
@ThreadSafe
-public class PoolingHttpClientConnectionManager extends HttpClientConnectionManagerBase {
+public class PoolingHttpClientConnectionManager implements HttpClientConnectionManager {
private final Log log = LogFactory.getLog(getClass());
+ private final ConfigData configData;
private final CPool pool;
+ private final HttpClientConnectionOperator connectionOperator;
private static Registry getDefaultRegistry() {
return RegistryBuilder.create()
@@ -81,42 +101,51 @@ public class PoolingHttpClientConnectionManager extends HttpClientConnectionMana
}
public PoolingHttpClientConnectionManager(final long timeToLive, final TimeUnit tunit) {
- this(getDefaultRegistry(), timeToLive, tunit);
+ this(getDefaultRegistry(), null, timeToLive, tunit);
}
public PoolingHttpClientConnectionManager(
final Registry socketFactoryRegistry) {
- this(socketFactoryRegistry, -1, TimeUnit.MILLISECONDS);
+ this(socketFactoryRegistry, null, -1, TimeUnit.MILLISECONDS);
}
public PoolingHttpClientConnectionManager(
final Registry socketFactoryRegistry,
final DnsResolver dnsResolver) {
- this(socketFactoryRegistry, null, dnsResolver, -1, TimeUnit.MILLISECONDS);
+ this(socketFactoryRegistry, null, null, dnsResolver, -1, TimeUnit.MILLISECONDS);
}
public PoolingHttpClientConnectionManager(
final Registry socketFactoryRegistry,
+ final HttpConnectionFactory connFactory,
final long timeToLive, final TimeUnit tunit) {
- this(new CPool(2, 20, timeToLive, tunit), socketFactoryRegistry, null, null);
+ this(socketFactoryRegistry, connFactory, null, null, timeToLive, tunit);
}
public PoolingHttpClientConnectionManager(
final Registry socketFactoryRegistry,
+ final HttpConnectionFactory connFactory,
final SchemePortResolver schemePortResolver,
final DnsResolver dnsResolver,
final long timeToLive, final TimeUnit tunit) {
- this(new CPool(2, 20, timeToLive, tunit),
+ super();
+ this.configData = new ConfigData();
+ this.pool = new CPool(
+ new InternalConnectionFactory(this.configData, connFactory), 2, 20, timeToLive, tunit);
+ this.connectionOperator = new HttpClientConnectionOperator(
socketFactoryRegistry, schemePortResolver, dnsResolver);
}
PoolingHttpClientConnectionManager(
final CPool pool,
- final Registry socketFactoryRegistry,
+ final Lookup socketFactoryRegistry,
final SchemePortResolver schemePortResolver,
final DnsResolver dnsResolver) {
- super(pool, socketFactoryRegistry, schemePortResolver, dnsResolver);
+ super();
+ this.configData = new ConfigData();
this.pool = pool;
+ this.connectionOperator = new HttpClientConnectionOperator(
+ socketFactoryRegistry, schemePortResolver, dnsResolver);
}
@Override
@@ -160,39 +189,137 @@ public class PoolingHttpClientConnectionManager extends HttpClientConnectionMana
return buf.toString();
}
- @Override
- protected void onConnectionLeaseRequest(final HttpRoute route, final Object state) {
+ public ConnectionRequest requestConnection(
+ final HttpRoute route,
+ final Object state) {
+ if (route == null) {
+ throw new IllegalArgumentException("HTTP route may not be null");
+ }
if (this.log.isDebugEnabled()) {
this.log.debug("Connection request: " + format(route, state) + formatStats(route));
}
- }
+ final Future future = this.pool.lease(route, state, null);
+ return new ConnectionRequest() {
- @Override
- protected void onConnectionLease(final CPoolEntry entry) {
- if (this.log.isDebugEnabled()) {
- this.log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
- }
- }
-
- @Override
- protected void onConnectionKeepAlive(final CPoolEntry entry) {
- if (this.log.isDebugEnabled()) {
- long keepalive = entry.getExpiry();
- String s;
- if (keepalive > 0) {
- s = "for " + (double) keepalive / 1000 + " seconds";
- } else {
- s = "indefinitely";
+ public boolean cancel() {
+ return future.cancel(true);
}
- this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
+
+ public HttpClientConnection get(
+ final long timeout,
+ final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
+ return leaseConnection(future, timeout, tunit);
+ }
+
+ };
+
+ }
+
+ protected HttpClientConnection leaseConnection(
+ final Future future,
+ final long timeout,
+ final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
+ CPoolEntry entry;
+ try {
+ entry = future.get(timeout, tunit);
+ if (entry == null || future.isCancelled()) {
+ throw new InterruptedException();
+ }
+ if (entry.getConnection() == null) {
+ throw new IllegalStateException("Pool entry with no connection");
+ }
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
+ }
+ return CPoolProxy.newProxy(entry);
+ } catch (ExecutionException ex) {
+ Throwable cause = ex.getCause();
+ if (cause == null) {
+ cause = ex;
+ }
+ InterruptedException intex = new InterruptedException();
+ intex.initCause(cause);
+ throw intex;
+ } catch (TimeoutException ex) {
+ throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
}
}
- @Override
- protected void onConnectionRelease(final CPoolEntry entry) {
- if (this.log.isDebugEnabled()) {
- this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
+ public void releaseConnection(
+ final HttpClientConnection managedConn,
+ final Object state,
+ final long keepalive, final TimeUnit tunit) {
+ if (managedConn == null) {
+ throw new IllegalArgumentException("Managed connection may not be null");
}
+ synchronized (managedConn) {
+ CPoolEntry entry = CPoolProxy.detach(managedConn);
+ if (entry == null) {
+ return;
+ }
+ SocketClientConnection conn = entry.getConnection();
+ try {
+ if (conn.isOpen()) {
+ entry.setState(state);
+ entry.updateExpiry(keepalive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
+ if (this.log.isDebugEnabled()) {
+ String s;
+ if (keepalive > 0) {
+ s = "for " + (double) keepalive / 1000 + " seconds";
+ } else {
+ s = "indefinitely";
+ }
+ this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
+ }
+ }
+ } finally {
+ this.pool.release(entry, conn.isOpen());
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
+ }
+ }
+ }
+ }
+
+ public void connect(
+ final HttpClientConnection managedConn,
+ final HttpHost host,
+ final InetAddress local,
+ final int connectTimeout,
+ final HttpContext context) throws IOException {
+ if (managedConn == null) {
+ throw new IllegalArgumentException("Connection may not be null");
+ }
+ SocketClientConnection conn;
+ synchronized (managedConn) {
+ CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
+ conn = entry.getConnection();
+ }
+ SocketConfig socketConfig = this.configData.getSocketConfig(host);
+ if (socketConfig == null) {
+ socketConfig = this.configData.getDefaultSocketConfig();
+ }
+ if (socketConfig == null) {
+ socketConfig = SocketConfig.DEFAULT;
+ }
+ InetSocketAddress localAddress = local != null ? new InetSocketAddress(local, 0) : null;
+ this.connectionOperator.connect(
+ conn, host, localAddress, connectTimeout, socketConfig, context);
+ }
+
+ public void upgrade(
+ final HttpClientConnection managedConn,
+ final HttpHost host,
+ final HttpContext context) throws IOException {
+ if (managedConn == null) {
+ throw new IllegalArgumentException("Connection may not be null");
+ }
+ SocketClientConnection conn;
+ synchronized (managedConn) {
+ CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
+ conn = entry.getConnection();
+ }
+ this.connectionOperator.upgrade(conn, host, context);
}
public void shutdown() {
@@ -249,4 +376,116 @@ public class PoolingHttpClientConnectionManager extends HttpClientConnectionMana
return this.pool.getStats(route);
}
-}
+ public SocketConfig getDefaultSocketConfig() {
+ return this.configData.getDefaultSocketConfig();
+ }
+
+ 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);
+ }
+
+ 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() {
+ return this.defaultSocketConfig;
+ }
+
+ public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) {
+ 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);
+ }
+
+ public void setSocketConfig(final HttpHost host, final SocketConfig socketConfig) {
+ this.socketConfigMap.put(host, socketConfig);
+ }
+
+ public ConnectionConfig getConnectionConfig(final HttpHost host) {
+ return this.connectionConfigMap.get(host);
+ }
+
+ public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) {
+ this.connectionConfigMap.put(host, connectionConfig);
+ }
+
+ }
+
+ static class InternalConnectionFactory implements ConnFactory {
+
+ private final ConfigData configData;
+ private final HttpConnectionFactory connFactory;
+
+ InternalConnectionFactory(
+ final ConfigData configData,
+ final HttpConnectionFactory connFactory) {
+ super();
+ this.configData = configData != null ? configData : new ConfigData();
+ this.connFactory = connFactory != null ? connFactory :
+ DefaultClientConnectionFactory.INSTANCE;
+ }
+
+ public SocketClientConnection create(final HttpRoute route) throws IOException {
+ 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;
+ }
+ return this.connFactory.create(config);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionManagerBase.java b/httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionManagerBase.java
deleted file mode 100644
index 7628a503f..000000000
--- a/httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionManagerBase.java
+++ /dev/null
@@ -1,198 +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
- * .
- *
- */
-
-package org.apache.http.impl.conn;
-
-import java.net.Socket;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.apache.commons.logging.LogFactory;
-import org.apache.http.HttpClientConnection;
-import org.apache.http.HttpHost;
-import org.apache.http.config.Lookup;
-import org.apache.http.conn.ConnectionPoolTimeoutException;
-import org.apache.http.conn.ConnectionRequest;
-import org.apache.http.conn.DnsResolver;
-import org.apache.http.conn.SchemePortResolver;
-import org.apache.http.conn.SocketClientConnection;
-import org.apache.http.conn.routing.HttpRoute;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.pool.ConnPool;
-import org.apache.http.protocol.HttpContext;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-public class TestHttpClientConnectionManagerBase {
-
- private SocketClientConnection conn;
- private Socket socket;
- private ConnectionSocketFactory plainSocketFactory;
- private Lookup socketFactoryRegistry;
- private SchemePortResolver schemePortResolver;
- private DnsResolver dnsResolver;
- private Future future;
- private ConnPool pool;
- private HttpClientConnectionManagerBase mgr;
-
- @SuppressWarnings("unchecked")
- @Before
- public void setup() throws Exception {
- conn = Mockito.mock(SocketClientConnection.class);
- socket = Mockito.mock(Socket.class);
- plainSocketFactory = Mockito.mock(ConnectionSocketFactory.class);
- socketFactoryRegistry = Mockito.mock(Lookup.class);
- schemePortResolver = Mockito.mock(SchemePortResolver.class);
- dnsResolver = Mockito.mock(DnsResolver.class);
- pool = Mockito.mock(ConnPool.class);
- future = Mockito.mock(Future.class);
- mgr = new HttpClientConnectionManagerBase(
- pool, socketFactoryRegistry, schemePortResolver, dnsResolver) {
-
- public void closeIdleConnections(long idletime, TimeUnit tunit) {
- }
-
- public void closeExpiredConnections() {
- }
-
- public void shutdown() {
- }
-
- };
- }
-
- @Test
- public void testLeaseRelease() throws Exception {
- HttpHost target = new HttpHost("localhost");
- HttpRoute route = new HttpRoute(target);
-
- CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
- -1, TimeUnit.MILLISECONDS);
-
- Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
- Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
- Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
- Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
-
- Mockito.when(future.isCancelled()).thenReturn(false);
- Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
- Mockito.when(pool.lease(route, null, null)).thenReturn(future);
-
- ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
- HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
- Assert.assertNotNull(conn1);
- Assert.assertFalse(conn1.isOpen());
- Assert.assertNotSame(conn, conn1);
-
- mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
-
- Mockito.verify(pool).release(entry, false);
- }
-
- @Test(expected=InterruptedException.class)
- public void testLeaseFutureCancelled() throws Exception {
- HttpHost target = new HttpHost("localhost");
- HttpRoute route = new HttpRoute(target);
-
- CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
- -1, TimeUnit.MILLISECONDS);
-
- Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
- Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
- Mockito.when(pool.lease(route, null, null)).thenReturn(future);
-
- ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
- connRequest1.get(1, TimeUnit.SECONDS);
- }
-
- @Test(expected=ConnectionPoolTimeoutException.class)
- public void testLeaseFutureTimeout() throws Exception {
- HttpHost target = new HttpHost("localhost");
- HttpRoute route = new HttpRoute(target);
-
- Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
- Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
- Mockito.when(pool.lease(route, null, null)).thenReturn(future);
-
- ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
- connRequest1.get(1, TimeUnit.SECONDS);
- }
-
- @Test
- public void testReleaseReusable() throws Exception {
- HttpHost target = new HttpHost("localhost");
- HttpRoute route = new HttpRoute(target);
-
- CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
- -1, TimeUnit.MILLISECONDS));
-
- Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
- Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
- Mockito.when(pool.lease(route, null, null)).thenReturn(future);
- Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
-
- ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
- HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
- Assert.assertNotNull(conn1);
- Assert.assertTrue(conn1.isOpen());
-
- mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
-
- Mockito.verify(pool).release(entry, true);
- Mockito.verify(entry).setState("some state");
- Mockito.verify(entry).updateExpiry(Mockito.anyLong(), Mockito.eq(TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testReleaseNonReusable() throws Exception {
- HttpHost target = new HttpHost("localhost");
- HttpRoute route = new HttpRoute(target);
-
- CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
- -1, TimeUnit.MILLISECONDS));
-
- Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
- Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
- Mockito.when(pool.lease(route, null, null)).thenReturn(future);
- Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
-
- ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
- HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
- Assert.assertNotNull(conn1);
- Assert.assertFalse(conn1.isOpen());
-
- mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
-
- Mockito.verify(pool).release(entry, false);
- Mockito.verify(entry, Mockito.never()).setState(Mockito.anyObject());
- Mockito.verify(entry, Mockito.never()).updateExpiry(Mockito.anyLong(), Mockito.eq(TimeUnit.MILLISECONDS));
- }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java b/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java
index e299a2516..ab8f10d57 100644
--- a/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java
+++ b/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java
@@ -27,15 +27,25 @@
package org.apache.http.impl.conn;
+import java.net.Socket;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpHost;
+import org.apache.http.config.Lookup;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.ConnectionPoolTimeoutException;
-import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.DnsResolver;
+import org.apache.http.conn.SchemePortResolver;
+import org.apache.http.conn.SocketClientConnection;
import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.protocol.HttpContext;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
@@ -44,500 +54,136 @@ import org.mockito.Mockito;
*/
public class TestPoolingHttpClientConnectionManager {
- private static HttpClientConnection getConnection(
- final HttpClientConnectionManager mgr,
- final HttpRoute route,
- long timeout,
- TimeUnit unit) throws ConnectionPoolTimeoutException, InterruptedException {
- ConnectionRequest connRequest = mgr.requestConnection(route, null);
- return connRequest.get(timeout, unit);
+ private SocketClientConnection conn;
+ private Socket socket;
+ private ConnectionSocketFactory plainSocketFactory;
+ private Lookup socketFactoryRegistry;
+ private SchemePortResolver schemePortResolver;
+ private DnsResolver dnsResolver;
+ private Future future;
+ private CPool pool;
+ private PoolingHttpClientConnectionManager mgr;
+
+ @SuppressWarnings("unchecked")
+ @Before
+ public void setup() throws Exception {
+ conn = Mockito.mock(SocketClientConnection.class);
+ socket = Mockito.mock(Socket.class);
+ plainSocketFactory = Mockito.mock(ConnectionSocketFactory.class);
+ socketFactoryRegistry = Mockito.mock(Lookup.class);
+ schemePortResolver = Mockito.mock(SchemePortResolver.class);
+ dnsResolver = Mockito.mock(DnsResolver.class);
+ pool = Mockito.mock(CPool.class);
+ future = Mockito.mock(Future.class);
+ mgr = new PoolingHttpClientConnectionManager(
+ pool, socketFactoryRegistry, schemePortResolver, dnsResolver);
}
- private static HttpClientConnection getConnection(
- final HttpClientConnectionManager mgr,
- final HttpRoute route) throws ConnectionPoolTimeoutException, InterruptedException {
- ConnectionRequest connRequest = mgr.requestConnection(route, null);
- return connRequest.get(0, null);
- }
-
- @Test(expected=IllegalArgumentException.class)
- public void testIllegalConstructor() {
- new PoolingHttpClientConnectionManager(null);
- }
-
- @Test(expected=IllegalArgumentException.class)
- public void testGetConnection()
- throws InterruptedException, ConnectionPoolTimeoutException {
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-
- HttpHost target = new HttpHost("www.test.invalid", 80, "http");
- HttpRoute route = new HttpRoute(target, null, false);
-
- HttpClientConnection conn = getConnection(mgr, route);
- Assert.assertNotNull(conn);
- Assert.assertFalse(conn.isOpen());
-
- mgr.releaseConnection(conn, null, -1, null);
-
- try {
- getConnection(mgr, null);
- } finally {
- mgr.shutdown();
- }
- }
-
- // testTimeout in 3.x TestHttpConnectionManager is redundant
- // several other tests here rely on timeout behavior
@Test
- public void testMaxConnTotal()
- throws InterruptedException, ConnectionPoolTimeoutException {
+ public void testLeaseRelease() throws Exception {
+ HttpHost target = new HttpHost("localhost");
+ HttpRoute route = new HttpRoute(target);
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(2);
- mgr.setDefaultMaxPerRoute(1);
+ CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
+ -1, TimeUnit.MILLISECONDS);
- HttpHost target1 = new HttpHost("www.test1.invalid", 80, "http");
- HttpRoute route1 = new HttpRoute(target1, null, false);
- HttpHost target2 = new HttpHost("www.test2.invalid", 80, "http");
- HttpRoute route2 = new HttpRoute(target2, null, false);
+ Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
+ Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
+ Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
+ Mockito.when(plainSocketFactory.createSocket(Mockito.any())).thenReturn(socket);
- HttpClientConnection conn1 = getConnection(mgr, route1);
+ Mockito.when(future.isCancelled()).thenReturn(false);
+ Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
+ Mockito.when(pool.lease(route, null, null)).thenReturn(future);
+
+ ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
+ HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
Assert.assertNotNull(conn1);
- HttpClientConnection conn2 = getConnection(mgr, route2);
- Assert.assertNotNull(conn2);
+ Assert.assertFalse(conn1.isOpen());
+ Assert.assertNotSame(conn, conn1);
- try {
- // this should fail quickly, connection has not been released
- getConnection(mgr, route2, 100L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
+ mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
- // release one of the connections
- mgr.releaseConnection(conn2, null, -1, null);
- conn2 = null;
+ Mockito.verify(pool).release(entry, false);
+ }
- // there should be a connection available now
- try {
- getConnection(mgr, route2, 100L, TimeUnit.MILLISECONDS);
- } catch (ConnectionPoolTimeoutException cptx) {
- Assert.fail("connection should have been available: " + cptx);
- }
+ @Test(expected=InterruptedException.class)
+ public void testLeaseFutureCancelled() throws Exception {
+ HttpHost target = new HttpHost("localhost");
+ HttpRoute route = new HttpRoute(target);
- mgr.shutdown();
+ CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
+ -1, TimeUnit.MILLISECONDS);
+
+ Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
+ Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
+ Mockito.when(pool.lease(route, null, null)).thenReturn(future);
+
+ ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
+ connRequest1.get(1, TimeUnit.SECONDS);
+ }
+
+ @Test(expected=ConnectionPoolTimeoutException.class)
+ public void testLeaseFutureTimeout() throws Exception {
+ HttpHost target = new HttpHost("localhost");
+ HttpRoute route = new HttpRoute(target);
+
+ Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
+ Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
+ Mockito.when(pool.lease(route, null, null)).thenReturn(future);
+
+ ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
+ connRequest1.get(1, TimeUnit.SECONDS);
}
@Test
- public void testMaxConnPerHost() throws Exception {
+ public void testReleaseReusable() throws Exception {
+ HttpHost target = new HttpHost("localhost");
+ HttpRoute route = new HttpRoute(target);
- HttpHost target1 = new HttpHost("www.test1.invalid", 80, "http");
- HttpRoute route1 = new HttpRoute(target1, null, false);
- HttpHost target2 = new HttpHost("www.test2.invalid", 80, "http");
- HttpRoute route2 = new HttpRoute(target2, null, false);
- HttpHost target3 = new HttpHost("www.test3.invalid", 80, "http");
- HttpRoute route3 = new HttpRoute(target3, null, false);
+ CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
+ -1, TimeUnit.MILLISECONDS));
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(100);
- mgr.setDefaultMaxPerRoute(1);
- mgr.setMaxPerRoute(route2, 2);
- mgr.setMaxPerRoute(route3, 3);
+ Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
+ Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
+ Mockito.when(pool.lease(route, null, null)).thenReturn(future);
+ Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
- // route 3, limit 3
- HttpClientConnection conn1 =
- getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
+ ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
+ HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
Assert.assertNotNull(conn1);
- HttpClientConnection conn2 =
- getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
- Assert.assertNotNull(conn2);
- HttpClientConnection conn3 =
- getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
- Assert.assertNotNull(conn3);
- try {
- // should fail quickly, connection has not been released
- getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
+ Assert.assertTrue(conn1.isOpen());
- // route 2, limit 2
- conn1 = getConnection(mgr, route2, 10L, TimeUnit.MILLISECONDS);
- conn2 = getConnection(mgr, route2, 10L, TimeUnit.MILLISECONDS);
- try {
- // should fail quickly, connection has not been released
- getConnection(mgr, route2, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
+ mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
- // route 1, should use default limit of 1
- conn1 = getConnection(mgr, route1, 10L, TimeUnit.MILLISECONDS);
- try {
- // should fail quickly, connection has not been released
- getConnection(mgr, route1, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
- // check releaseConnection with invalid arguments
- try {
- mgr.releaseConnection(null, null, -1, null);
- Assert.fail("null connection adapter not detected");
- } catch (IllegalArgumentException iax) {
- // expected
- }
- try {
- HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
- mgr.releaseConnection(conn, null, -1, null);
- Assert.fail("foreign connection adapter not detected");
- } catch (IllegalArgumentException iax) {
- // expected
- }
-
- mgr.shutdown();
+ Mockito.verify(pool).release(entry, true);
+ Mockito.verify(entry).setState("some state");
+ Mockito.verify(entry).updateExpiry(Mockito.anyLong(), Mockito.eq(TimeUnit.MILLISECONDS));
}
@Test
- public void testReleaseConnection() throws Exception {
+ public void testReleaseNonReusable() throws Exception {
+ HttpHost target = new HttpHost("localhost");
+ HttpRoute route = new HttpRoute(target);
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(3);
- mgr.setDefaultMaxPerRoute(1);
+ CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
+ -1, TimeUnit.MILLISECONDS));
- HttpHost target1 = new HttpHost("www.test1.invalid", 80, "http");
- HttpRoute route1 = new HttpRoute(target1, null, false);
- HttpHost target2 = new HttpHost("www.test2.invalid", 80, "http");
- HttpRoute route2 = new HttpRoute(target2, null, false);
- HttpHost target3 = new HttpHost("www.test3.invalid", 80, "http");
- HttpRoute route3 = new HttpRoute(target3, null, false);
+ Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
+ Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
+ Mockito.when(pool.lease(route, null, null)).thenReturn(future);
+ Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
- // the first three allocations should pass
- HttpClientConnection conn1 =
- getConnection(mgr, route1, 10L, TimeUnit.MILLISECONDS);
- HttpClientConnection conn2 =
- getConnection(mgr, route2, 10L, TimeUnit.MILLISECONDS);
- HttpClientConnection conn3 =
- getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
+ ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
+ HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
Assert.assertNotNull(conn1);
- Assert.assertNotNull(conn2);
- Assert.assertNotNull(conn3);
+ Assert.assertFalse(conn1.isOpen());
- // obtaining another connection for either of the three should fail
- // this is somehow redundant with testMaxConnPerHost
- try {
- getConnection(mgr, route1, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
- try {
- getConnection(mgr, route2, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
- try {
- getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
-
- // now release one and check that exactly that one can be obtained then
- mgr.releaseConnection(conn2, null, -1, null);
- conn2 = null;
- try {
- getConnection(mgr, route1, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
- // this one succeeds
- conn2 = getConnection(mgr, route2, 10L, TimeUnit.MILLISECONDS);
- Assert.assertNotNull(conn2);
- try {
- getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("ConnectionPoolTimeoutException should have been thrown");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
-
- mgr.shutdown();
- }
-
- @Test
- public void testDeleteClosedConnections() throws Exception {
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-
- HttpHost target = new HttpHost("www.test.invalid", 80, "http");
- HttpRoute route = new HttpRoute(target, null, false);
-
- HttpClientConnection conn = getConnection(mgr, route);
-
- Assert.assertEquals(1, mgr.getTotalStats().getLeased());
- Assert.assertEquals(1, mgr.getStats(route).getLeased());
- mgr.releaseConnection(conn, null, -1, null);
-
- Assert.assertEquals(0, mgr.getTotalStats().getAvailable());
- Assert.assertEquals(0, mgr.getStats(route).getAvailable());
-
- mgr.shutdown();
- }
-
- @Test
- public void testShutdown() throws Exception {
- // 3.x: TestHttpConnectionManager.testShutdown
-
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(1);
- mgr.setDefaultMaxPerRoute(1);
-
- HttpHost target = new HttpHost("www.test.invalid", 80, "http");
- HttpRoute route = new HttpRoute(target, null, false);
-
- // get the only connection, then start an extra thread
- // on shutdown, the extra thread should get an exception
-
- HttpClientConnection conn =
- getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
- GetConnThread gct = new GetConnThread(mgr, route, 0L); // no timeout
- gct.start();
- Thread.sleep(100); // give extra thread time to block
-
-
- mgr.shutdown();
-
- // First release the connection. If the manager keeps working
- // despite the shutdown, this will deblock the extra thread.
- // The release itself should turn into a no-op, without exception.
- mgr.releaseConnection(conn, null, -1, null);
-
-
- gct.join(10000);
- Assert.assertNull("thread should not have obtained connection",
- gct.getConnection());
- Assert.assertNotNull("thread should have gotten an exception",
- gct.getException());
- Assert.assertSame("thread got wrong exception",
- InterruptedException.class, gct.getException().getClass());
-
- // the manager is down, we should not be able to get a connection
- try {
- getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
- Assert.fail("shut-down manager does not raise exception");
- } catch (IllegalStateException isx) {
- // expected
- }
- }
-
- @Test
- public void testInterruptThread() throws Exception {
- // 3.x: TestHttpConnectionManager.testWaitingThreadInterrupted
-
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(1);
-
- HttpHost target = new HttpHost("www.test.invalid", 80, "http");
- HttpRoute route = new HttpRoute(target, null, false);
-
- // get the only connection, then start an extra thread
- HttpClientConnection conn =
- getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
- GetConnThread gct = new GetConnThread(mgr, route, 0L); // no timeout
- gct.start();
- Thread.sleep(100); // give extra thread time to block
-
-
- // interrupt the thread, it should cancel waiting with an exception
- gct.interrupt();
-
-
- gct.join(10000);
- Assert.assertNotNull("thread should have gotten an exception",
- gct.getException());
- Assert.assertSame("thread got wrong exception",
- InterruptedException.class,
- gct.getException().getClass());
-
- // make sure the manager is still working
- try {
- getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("should have gotten a timeout");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
-
- mgr.releaseConnection(conn, null, -1, null);
- // this time: no exception
- conn = getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
- Assert.assertNotNull("should have gotten a connection", conn);
-
- mgr.shutdown();
- }
-
- @Test
- public void testReusePreference() throws Exception {
- // 3.x: TestHttpConnectionManager.testHostReusePreference
-
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(1);
-
- HttpHost target1 = new HttpHost("www.test1.invalid", 80, "http");
- HttpRoute route1 = new HttpRoute(target1, null, false);
- HttpHost target2 = new HttpHost("www.test2.invalid", 80, "http");
- HttpRoute route2 = new HttpRoute(target2, null, false);
-
- // get the only connection, then start two extra threads
- HttpClientConnection conn =
- getConnection(mgr, route1, 1L, TimeUnit.MILLISECONDS);
- GetConnThread gct1 = new GetConnThread(mgr, route1, 1000L);
- GetConnThread gct2 = new GetConnThread(mgr, route2, 1000L);
-
- // the second thread is started first, to distinguish the
- // route-based reuse preference from first-come, first-served
- gct2.start();
- Thread.sleep(100); // give the thread time to block
- gct1.start();
- Thread.sleep(100); // give the thread time to block
-
-
- // releasing the connection for route1 should deblock thread1
- // the other thread gets a timeout
- mgr.releaseConnection(conn, null, -1, null);
-
- gct1.join(10000);
- gct2.join(10000);
-
- Assert.assertNotNull("thread 1 should have gotten a connection",
- gct1.getConnection());
- Assert.assertNull ("thread 2 should NOT have gotten a connection",
- gct2.getConnection());
-
- mgr.shutdown();
- }
-
- @Test
- public void testAbortAfterRequestStarts() throws Exception {
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(1);
-
- HttpHost target = new HttpHost("www.test.invalid", 80, "http");
- HttpRoute route = new HttpRoute(target, null, false);
-
- // get the only connection, then start an extra thread
- HttpClientConnection conn = getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
- ConnectionRequest request = mgr.requestConnection(route, null);
- GetConnThread gct = new GetConnThread(request, route, 0L); // no timeout
- gct.start();
- Thread.sleep(100); // give extra thread time to block
-
- request.cancel();
-
- gct.join(10000);
- Assert.assertNotNull("thread should have gotten an exception",
- gct.getException());
- Assert.assertSame("thread got wrong exception",
- InterruptedException.class,
- gct.getException().getClass());
-
- // make sure the manager is still working
- try {
- getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("should have gotten a timeout");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
-
- mgr.releaseConnection(conn, null, -1, null);
- // this time: no exception
- conn = getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
- Assert.assertNotNull("should have gotten a connection", conn);
-
- mgr.shutdown();
- }
-
- @Test
- public void testAbortBeforeRequestStarts() throws Exception {
- PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
- mgr.setMaxTotal(1);
-
- HttpHost target = new HttpHost("www.test.invalid", 80, "http");
- HttpRoute route = new HttpRoute(target, null, false);
-
- // get the only connection, then start an extra thread
- HttpClientConnection conn = getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
- ConnectionRequest request = mgr.requestConnection(route, null);
- request.cancel();
-
- GetConnThread gct = new GetConnThread(request, route, 0L); // no timeout
- gct.start();
- Thread.sleep(100); // give extra thread time to block
-
- gct.join(10000);
- Assert.assertNotNull("thread should have gotten an exception",
- gct.getException());
- Assert.assertSame("thread got wrong exception",
- InterruptedException.class,
- gct.getException().getClass());
-
- // make sure the manager is still working
- try {
- getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
- Assert.fail("should have gotten a timeout");
- } catch (ConnectionPoolTimeoutException e) {
- // expected
- }
-
- mgr.releaseConnection(conn, null, -1, null);
- // this time: no exception
- conn = getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
- Assert.assertNotNull("should have gotten a connection", conn);
-
- mgr.shutdown();
- }
-
- public class GetConnThread extends Thread {
-
- private final ConnectionRequest connRequest;
- private final long timeout;
-
- private volatile HttpClientConnection connection;
- private volatile Exception exception;
-
- public GetConnThread(
- final HttpClientConnectionManager mgr,
- final HttpRoute route, long timeout) {
- this(mgr.requestConnection(route, null), route, timeout);
- }
-
- public GetConnThread(
- final ConnectionRequest connRequest,
- final HttpRoute route, long timeout) {
- super();
- this.connRequest = connRequest;
- this.timeout = timeout;
- }
-
- @Override
- public void run() {
- try {
- connection = connRequest.get(timeout, TimeUnit.MILLISECONDS);
- } catch (Exception ex) {
- exception = ex;
- }
- }
-
- public Throwable getException() {
- return exception;
- }
-
- public HttpClientConnection getConnection() {
- return connection;
- }
+ mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
+ Mockito.verify(pool).release(entry, false);
+ Mockito.verify(entry, Mockito.never()).setState(Mockito.anyObject());
+ Mockito.verify(entry, Mockito.never()).updateExpiry(Mockito.anyLong(), Mockito.eq(TimeUnit.MILLISECONDS));
}
}