Connection management API redesign: deprecated ClientConnectionManager, ManagedClientConnection, OperatedClientConnection and ClientConnectionOperator in favor of a simpler HttpClientConnectionManager interface. The new API has a much smaller footprint and no longer supports the concept of managed or operated connections. Internal connection mangement logic is no longer exposed to the consumer

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1405507 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2012-11-04 07:37:50 +00:00
parent 84d4b9e2ac
commit 78856ca1b1
60 changed files with 2822 additions and 2446 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
bin
.classpath
.project
.settings

View File

@ -55,18 +55,18 @@ import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.BasicHttpContext;
/**
* An Executor for fluent requests
* <p/>
* A {@link PoolingClientConnectionManager} with maximum 100 connections per route and
* A {@link PoolingHttpClientConnectionManager} with maximum 100 connections per route and
* a total maximum of 200 connections is used internally.
*/
public class Executor {
final static PoolingClientConnectionManager CONNMGR;
final static PoolingHttpClientConnectionManager CONNMGR;
final static HttpClient CLIENT;
static {
@ -90,7 +90,7 @@ public class Executor {
if (ssl != null) {
schemeRegistry.register(new Scheme("https", 443, ssl));
}
CONNMGR = new PoolingClientConnectionManager(schemeRegistry);
CONNMGR = new PoolingHttpClientConnectionManager(schemeRegistry);
CONNMGR.setDefaultMaxPerRoute(100);
CONNMGR.setMaxTotal(200);
CLIENT = new HttpClientBuilder().setConnectionManager(CONNMGR).build();

View File

@ -1,109 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.examples.conn;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.conn.ClientConnectionOperator;
import org.apache.http.conn.OperatedClientConnection;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.conn.DefaultClientConnectionOperator;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.params.SyncBasicHttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.BasicHttpContext;
/**
* How to open a direct connection using
* {@link ClientConnectionOperator ClientConnectionOperator}.
* This exemplifies the <i>opening</i> of the connection only.
* The subsequent message exchange in this example should not
* be used as a template.
*
* @since 4.0
*/
public class OperatorConnectDirect {
public static void main(String[] args) throws Exception {
HttpHost target = new HttpHost("jakarta.apache.org", 80, "http");
// some general setup
// Register the "http" protocol scheme, it is required
// by the default operator to look up socket factories.
SchemeRegistry supportedSchemes = new SchemeRegistry();
supportedSchemes.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
// Prepare parameters.
// Since this example doesn't use the full core framework,
// only few parameters are actually required.
HttpParams params = new SyncBasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setUseExpectContinue(params, false);
// one operator can be used for many connections
ClientConnectionOperator scop = new DefaultClientConnectionOperator(supportedSchemes);
HttpRequest req = new BasicHttpRequest("OPTIONS", "*", HttpVersion.HTTP_1_1);
req.addHeader("Host", target.getHostName());
HttpContext ctx = new BasicHttpContext();
OperatedClientConnection conn = scop.createConnection();
try {
System.out.println("opening connection to " + target);
scop.openConnection(conn, target, null, ctx, params);
System.out.println("sending request");
conn.sendRequestHeader(req);
// there is no request entity
conn.flush();
System.out.println("receiving response header");
HttpResponse rsp = conn.receiveResponseHeader();
System.out.println("----------------------------------------");
System.out.println(rsp.getStatusLine());
Header[] headers = rsp.getAllHeaders();
for (int i = 0; i < headers.length; i++) {
System.out.println(headers[i]);
}
System.out.println("----------------------------------------");
} finally {
System.out.println("closing connection");
conn.close();
}
}
}

View File

@ -1,163 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.examples.conn;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.conn.ClientConnectionOperator;
import org.apache.http.conn.OperatedClientConnection;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.conn.DefaultClientConnectionOperator;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.params.SyncBasicHttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.BasicHttpContext;
/**
* How to open a secure connection through a proxy using
* {@link ClientConnectionOperator ClientConnectionOperator}.
* This exemplifies the <i>opening</i> of the connection only.
* The message exchange, both subsequently and for tunnelling,
* should not be used as a template.
*
* @since 4.0
*/
public class OperatorConnectProxy {
public static void main(String[] args) throws Exception {
// make sure to use a proxy that supports CONNECT
HttpHost target = new HttpHost("issues.apache.org", 443, "https");
HttpHost proxy = new HttpHost("127.0.0.1", 8666, "http");
// some general setup
// Register the "http" and "https" protocol schemes, they are
// required by the default operator to look up socket factories.
SchemeRegistry supportedSchemes = new SchemeRegistry();
supportedSchemes.register(new Scheme("http",
80, PlainSocketFactory.getSocketFactory()));
supportedSchemes.register(new Scheme("https",
443, SSLSocketFactory.getSocketFactory()));
// Prepare parameters.
// Since this example doesn't use the full core framework,
// only few parameters are actually required.
HttpParams params = new SyncBasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setUseExpectContinue(params, false);
// one operator can be used for many connections
ClientConnectionOperator scop = new DefaultClientConnectionOperator(supportedSchemes);
HttpRequest req = new BasicHttpRequest("OPTIONS", "*", HttpVersion.HTTP_1_1);
// In a real application, request interceptors should be used
// to add the required headers.
req.addHeader("Host", target.getHostName());
HttpContext ctx = new BasicHttpContext();
OperatedClientConnection conn = scop.createConnection();
try {
System.out.println("opening connection to " + proxy);
scop.openConnection(conn, proxy, null, ctx, params);
// Creates a request to tunnel a connection.
// For details see RFC 2817, section 5.2
String authority = target.getHostName() + ":" + target.getPort();
HttpRequest connect = new BasicHttpRequest("CONNECT", authority,
HttpVersion.HTTP_1_1);
// In a real application, request interceptors should be used
// to add the required headers.
connect.addHeader("Host", authority);
System.out.println("opening tunnel to " + target);
conn.sendRequestHeader(connect);
// there is no request entity
conn.flush();
System.out.println("receiving confirmation for tunnel");
HttpResponse connected = conn.receiveResponseHeader();
System.out.println("----------------------------------------");
printResponseHeader(connected);
System.out.println("----------------------------------------");
int status = connected.getStatusLine().getStatusCode();
if ((status < 200) || (status > 299)) {
System.out.println("unexpected status code " + status);
System.exit(1);
}
System.out.println("receiving response body (ignored)");
conn.receiveResponseEntity(connected);
// Now we have a tunnel to the target. As we will be creating a
// layered TLS/SSL socket immediately afterwards, updating the
// connection with the new target is optional - but good style.
// The scheme part of the target is already "https", though the
// connection is not yet switched to the TLS/SSL protocol.
conn.update(null, target, false, params);
System.out.println("layering secure connection");
scop.updateSecureConnection(conn, target, ctx, params);
// finally we have the secure connection and can send the request
System.out.println("sending request");
conn.sendRequestHeader(req);
// there is no request entity
conn.flush();
System.out.println("receiving response header");
HttpResponse rsp = conn.receiveResponseHeader();
System.out.println("----------------------------------------");
printResponseHeader(rsp);
System.out.println("----------------------------------------");
} finally {
System.out.println("closing connection");
conn.close();
}
}
private final static void printResponseHeader(HttpResponse rsp) {
System.out.println(rsp.getStatusLine());
Header[] headers = rsp.getAllHeaders();
for (int i=0; i<headers.length; i++) {
System.out.println(headers[i]);
}
}
}

View File

@ -44,7 +44,10 @@ import org.apache.http.conn.scheme.SchemeRegistry;
* from multiple threads.
*
* @since 4.0
*
* @deprecated (4.3) replaced by {@link HttpClientConnectionManager}.
*/
@Deprecated
public interface ClientConnectionManager {
/**

View File

@ -33,9 +33,11 @@ import org.apache.http.params.HttpParams;
/**
* A factory for creating new {@link ClientConnectionManager} instances.
*
*
* @since 4.0
*
* @deprecated (4.3) replaced by {@link HttpClientConnectionManager}.
*/
@Deprecated
public interface ClientConnectionManagerFactory {
ClientConnectionManager newInstance(

View File

@ -51,7 +51,10 @@ import org.apache.http.protocol.HttpContext;
* from multiple threads.
*
* @since 4.0
*
* @deprecated (4.3) replaced by {@link HttpClientConnectionManager}.
*/
@Deprecated
public interface ClientConnectionOperator {
/**

View File

@ -33,7 +33,10 @@ import java.util.concurrent.TimeUnit;
* Encapsulates a request for a {@link ManagedClientConnection}.
*
* @since 4.0
*
* @deprecated (4.3) replaced by {@link ConnectionRequest}.
*/
@Deprecated
public interface ClientConnectionRequest {
/**

View File

@ -0,0 +1,68 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpClientConnection;
import org.apache.http.concurrent.Cancellable;
/**
* Encapsulates a request for a {@link HttpClientConnection}.
*
* @since 4.3
*/
public interface ConnectionRequest extends Cancellable {
/**
* Obtains a connection within a given time.
* This method will block until a connection becomes available,
* the timeout expires, or the connection manager is
* {@link ClientConnectionManager#shutdown() shut down}.
* Timeouts are handled with millisecond precision.
*
* If {@link #cancel()} is called while this is blocking or
* before this began, an {@link InterruptedException} will
* be thrown.
*
* @param timeout the timeout, 0 or negative for no timeout
* @param tunit the unit for the <code>timeout</code>,
* may be <code>null</code> only if there is no timeout
*
* @return a connection that can be used to communicate
* along the given route
*
* @throws ConnectionPoolTimeoutException
* in case of a timeout
* @throws InterruptedException
* if the calling thread is interrupted while waiting
*/
HttpClientConnection get(long timeout, TimeUnit tunit)
throws InterruptedException, ConnectionPoolTimeoutException;
}

View File

@ -0,0 +1,125 @@
/*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn;
import java.io.IOException;
import java.net.InetAddress;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpHost;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
/**
* Represents a manager of persistent client connections.
* <p/>
* The purpose of an HTTP connection manager is to serve as a factory for new
* HTTP connections, manage persistent connections and synchronize access to
* persistent connections making sure that only one thread of execution can
* have access to a connection at a time.
* <p/>
* Implementations of this interface must be thread-safe. Access to shared
* data must be synchronized as methods of this interface may be executed
* from multiple threads.
*
* @since 4.3
*/
public interface HttpClientConnectionManager {
SchemeRegistry getSchemeRegistry();
/**
* Returns a new {@link ClientConnectionRequest}, from which a
* {@link HttpClientConnection} can be obtained or the request can be
* aborted.
*/
ConnectionRequest requestConnection(
HttpRoute route, Object state);
/**
* Releases a connection for use by others.
* You may optionally specify how long the connection is valid
* to be reused. Values <= 0 are considered to be valid forever.
* If the connection is not marked as reusable, the connection will
* not be reused regardless of the valid duration.
*
* If the connection has been released before,
* the call will be ignored.
*
* @param conn the connection to release
* @param validDuration the duration of time this connection is valid for reuse
* @param timeUnit the unit of time validDuration is measured in
*
* @see #closeExpiredConnections()
*/
void releaseConnection(
HttpClientConnection conn, Object newState, long validDuration, TimeUnit timeUnit);
void connect(
HttpClientConnection conn, HttpHost host, InetAddress localAddress,
HttpContext context, HttpParams params) throws IOException;
void upgrade(
HttpClientConnection conn, HttpHost host,
HttpContext context, HttpParams params) throws IOException;
/**
* Closes idle connections in the pool.
* Open connections in the pool that have not been used for the
* timespan given by the argument will be closed.
* Currently allocated connections are not subject to this method.
* Times will be checked with milliseconds precision
*
* All expired connections will also be closed.
*
* @param idletime the idle time of connections to be closed
* @param tunit the unit for the <code>idletime</code>
*
* @see #closeExpiredConnections()
*/
void closeIdleConnections(long idletime, TimeUnit tunit);
/**
* Closes all expired connections in the pool.
* Open connections in the pool that have not been used for
* the timespan defined when the connection was released will be closed.
* Currently allocated connections are not subject to this method.
* Times will be checked with milliseconds precision.
*/
void closeExpiredConnections();
/**
* Shuts down this connection manager and releases allocated resources.
* This includes closing all connections, whether they are currently
* used or not.
*/
void shutdown();
}

View File

@ -0,0 +1,40 @@
/*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn;
import org.apache.http.HttpConnection;
/**
* Generic {@link HttpConnection} factory.
*
* @since 4.3
*/
public interface HttpConnectionFactory<T extends HttpConnection> {
T create();
}

View File

@ -37,7 +37,7 @@ import org.apache.http.conn.routing.HttpRoute;
*
* @since 4.1
*
* @deprecated (4.3) no longer used
* @deprecated (4.3) replaced by {@link HttpClientConnectionManager}.
*/
@Deprecated
public interface HttpRoutedConnection extends HttpInetConnection {

View File

@ -44,8 +44,10 @@ import org.apache.http.conn.routing.HttpRoute;
* Instances are typically obtained from a connection manager.
*
* @since 4.0
*
* @deprecated (4.3) replaced by {@link HttpClientConnectionManager}.
*/
@SuppressWarnings("deprecation")
@Deprecated
public interface ManagedClientConnection extends
HttpClientConnection, HttpRoutedConnection, HttpSSLConnection, ConnectionReleaseTrigger {

View File

@ -41,7 +41,10 @@ import org.apache.http.params.HttpParams;
* {@link ClientConnectionOperator operator}.
*
* @since 4.0
*
* @deprecated (4.3) replaced by {@link HttpClientConnectionManager}.
*/
@Deprecated
public interface OperatedClientConnection extends HttpClientConnection, HttpInetConnection {
/**

View File

@ -148,11 +148,6 @@ public class PlainSocketFactory implements SocketFactory, SchemeSocketFactory {
if (sock == null) {
throw new IllegalArgumentException("Socket may not be null.");
}
// This check is performed last since it calls a method implemented
// by the argument object. getClass() is final in java.lang.Object.
if (sock.isClosed()) {
throw new IllegalArgumentException("Socket is closed.");
}
return false;
}

View File

@ -940,7 +940,8 @@ public abstract class AbstractHttpClient extends AbstractBasicHttpClient {
final AuthenticationStrategy proxyAuthStrategy,
final UserTokenHandler userTokenHandler,
final HttpParams params) {
return new RequestDirectorAdaptor(
return new DefaultRequestDirector(
log,
requestExec,
conman,
reustrat,

View File

@ -61,8 +61,8 @@ import org.apache.http.client.protocol.RequestClientConnControl;
import org.apache.http.client.protocol.RequestDefaultHeaders;
import org.apache.http.client.protocol.ResponseContentEncoding;
import org.apache.http.client.protocol.ResponseProcessCookies;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeLayeredSocketFactory;
@ -83,8 +83,8 @@ import org.apache.http.impl.client.exec.ProtocolExec;
import org.apache.http.impl.client.exec.RedirectExec;
import org.apache.http.impl.client.exec.RetryExec;
import org.apache.http.impl.client.exec.ServiceUnavailableRetryExec;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.DefaultHttpRoutePlanner;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.impl.cookie.BestMatchSpecFactory;
@ -185,7 +185,7 @@ public class HttpClientBuilder {
private HttpRequestExecutor requestExec;
private SchemeLayeredSocketFactory sslSocketFactory;
private ClientConnectionManager connManager;
private HttpClientConnectionManager connManager;
private ConnectionReuseStrategy reuseStrategy;
private ConnectionKeepAliveStrategy keepAliveStrategy;
private AuthenticationStrategy targetAuthStrategy;
@ -240,7 +240,7 @@ public class HttpClientBuilder {
return this;
}
public final HttpClientBuilder setConnectionManager(final ClientConnectionManager connManager) {
public final HttpClientBuilder setConnectionManager(final HttpClientConnectionManager connManager) {
this.connManager = connManager;
return this;
}
@ -438,7 +438,7 @@ public class HttpClientBuilder {
if (requestExec == null) {
requestExec = new HttpRequestExecutor();
}
ClientConnectionManager connManager = this.connManager;
HttpClientConnectionManager connManager = this.connManager;
if (connManager == null) {
SchemeRegistry schemeRegistry = systemProperties ?
SchemeRegistryFactory.createSystemDefault() :
@ -446,7 +446,7 @@ public class HttpClientBuilder {
if (sslSocketFactory != null) {
schemeRegistry.register(new Scheme("https", 443, sslSocketFactory));
}
PoolingClientConnectionManager poolingmgr = new PoolingClientConnectionManager(
PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
schemeRegistry);
if (systemProperties) {
String s = System.getProperty("http.keepAlive");

View File

@ -28,6 +28,7 @@
package org.apache.http.impl.client;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
@ -43,8 +44,12 @@ import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.cookie.CookieSpecRegistry;
import org.apache.http.impl.client.exec.ClientExecChain;
import org.apache.http.impl.client.exec.HttpRequestWrapper;
@ -61,7 +66,7 @@ import org.apache.http.protocol.HttpContext;
class InternalHttpClient extends AbstractBasicHttpClient {
private final ClientExecChain execChain;
private final ClientConnectionManager connManager;
private final HttpClientConnectionManager connManager;
private final HttpRoutePlanner routePlanner;
private final CookieSpecRegistry cookieSpecRegistry;
private final AuthSchemeRegistry authSchemeRegistry;
@ -71,7 +76,7 @@ class InternalHttpClient extends AbstractBasicHttpClient {
public InternalHttpClient(
final ClientExecChain execChain,
final ClientConnectionManager connManager,
final HttpClientConnectionManager connManager,
final HttpRoutePlanner routePlanner,
final CookieSpecRegistry cookieSpecRegistry,
final AuthSchemeRegistry authSchemeRegistry,
@ -169,7 +174,38 @@ class InternalHttpClient extends AbstractBasicHttpClient {
}
public ClientConnectionManager getConnectionManager() {
return this.connManager;
return new ClientConnectionManager() {
public void shutdown() {
connManager.shutdown();
}
public ClientConnectionRequest requestConnection(
HttpRoute route, Object state) {
throw new UnsupportedOperationException();
}
public void releaseConnection(
ManagedClientConnection conn,
long validDuration, TimeUnit timeUnit) {
throw new UnsupportedOperationException();
}
public SchemeRegistry getSchemeRegistry() {
throw new UnsupportedOperationException();
}
public void closeIdleConnections(long idletime, TimeUnit tunit) {
connManager.closeIdleConnections(idletime, tunit);
}
public void closeExpiredConnections() {
connManager.closeExpiredConnections();
}
};
}
}

View File

@ -1,126 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.client;
import java.io.IOException;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.auth.AuthState;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.RequestDirector;
import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.impl.client.exec.ClientExecChain;
import org.apache.http.impl.client.exec.HttpRequestWrapper;
import org.apache.http.impl.client.exec.MainClientExec;
import org.apache.http.impl.client.exec.ProtocolExec;
import org.apache.http.impl.client.exec.RedirectExec;
import org.apache.http.impl.client.exec.RetryExec;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestExecutor;
@ThreadSafe
class RequestDirectorAdaptor implements RequestDirector {
private final HttpRoutePlanner routePlanner;
private final HttpParams params;
private final ClientExecChain execChain;
public RequestDirectorAdaptor(
final HttpRequestExecutor requestExecutor,
final ClientConnectionManager connman,
final ConnectionReuseStrategy reustrat,
final ConnectionKeepAliveStrategy kastrat,
final HttpRoutePlanner rouplan,
final HttpProcessor httpProcessor,
final HttpRequestRetryHandler retryHandler,
final RedirectStrategy redirectStrategy,
final AuthenticationStrategy targetAuthStrategy,
final AuthenticationStrategy proxyAuthStrategy,
final UserTokenHandler userTokenHandler,
final HttpParams params) {
this.routePlanner = rouplan;
this.params = params;
MainClientExec mainExecutor = new MainClientExec(
requestExecutor, connman, reustrat, kastrat,
targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
ProtocolExec protocolFacade = new ProtocolExec(mainExecutor, httpProcessor);
RetryExec retryFacade = new RetryExec(protocolFacade, retryHandler);
RedirectExec redirectFacade = new RedirectExec(retryFacade, rouplan, redirectStrategy);
this.execChain = redirectFacade;
}
public HttpResponse execute(
HttpHost target,
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
if (target == null) {
target = (HttpHost) this.params.getParameter(ClientPNames.DEFAULT_HOST);
}
if (target == null) {
throw new IllegalStateException("Target host must not be null, or set in parameters");
}
HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(request);
wrapper.setParams(this.params);
HttpHost virtualHost = (HttpHost) this.params.getParameter(ClientPNames.VIRTUAL_HOST);
wrapper.setVirtualHost(virtualHost);
HttpExecutionAware execListner = null;
if (request instanceof HttpExecutionAware) {
execListner = (HttpExecutionAware) request;
if (execListner.isAborted()) {
throw new RequestAbortedException("Request aborted");
}
}
HttpRoute route = this.routePlanner.determineRoute(target, request, context);
if (context.getAttribute(ClientContext.TARGET_AUTH_STATE) == null) {
context.setAttribute(ClientContext.TARGET_AUTH_STATE, new AuthState());
}
if (context.getAttribute(ClientContext.PROXY_AUTH_STATE) == null) {
context.setAttribute(ClientContext.PROXY_AUTH_STATE, new AuthState());
}
return this.execChain.execute(route, wrapper, context, execListner);
}
}

View File

@ -0,0 +1,134 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.client.exec;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.http.HttpClientConnection;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.concurrent.Cancellable;
import org.apache.http.conn.ConnectionReleaseTrigger;
import org.apache.http.conn.HttpClientConnectionManager;
/**
* Internal {@link ConnectionReleaseTrigger} implementation.
*
* @since 4.3
*/
@ThreadSafe
class ConnectionReleaseTriggerImpl implements ConnectionReleaseTrigger, Cancellable {
private final Log log;
private final HttpClientConnectionManager manager;
private final HttpClientConnection managedConn;
private volatile boolean reusable;
private volatile Object state;
private volatile long validDuration;
private volatile TimeUnit tunit;
private volatile boolean released;
public ConnectionReleaseTriggerImpl(
final Log log,
final HttpClientConnectionManager manager,
final HttpClientConnection managedConn) {
super();
this.log = log;
this.manager = manager;
this.managedConn = managedConn;
}
public boolean isReusable() {
return this.reusable;
}
public void markReusable() {
this.reusable = true;
}
public void markNonReusable() {
this.reusable = false;
}
public void setState(final Object state) {
this.state = state;
}
public void setValidFor(final long duration, final TimeUnit tunit) {
synchronized (this.managedConn) {
this.validDuration = duration;
this.tunit = tunit;
}
}
public void releaseConnection() {
synchronized (this.managedConn) {
if (this.released) {
return;
}
this.released = true;
this.manager.releaseConnection(this.managedConn,
this.state, this.validDuration, this.tunit);
}
}
public void abortConnection() {
synchronized (this.managedConn) {
if (this.released) {
return;
}
this.released = true;
try {
this.managedConn.shutdown();
log.debug("Connection discarded");
} catch (IOException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
} finally {
this.manager.releaseConnection(
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
}
}
}
public boolean cancel() {
boolean alreadyReleased = this.released;
log.debug("Cancelling request execution");
abortConnection();
return !alreadyReleased;
}
public boolean isReleased() {
return this.released;
}
}

View File

@ -44,7 +44,6 @@ import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.conn.ConnectionReleaseTrigger;
import org.apache.http.conn.EofSensorInputStream;
import org.apache.http.conn.EofSensorWatcher;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
@ -59,15 +58,17 @@ import org.apache.http.util.EntityUtils;
public class HttpResponseWrapper implements HttpResponse, ConnectionReleaseTrigger, Closeable {
private final HttpResponse original;
private final ConnectionReleaseTriggerImpl connReleaseTrigger;
private HttpEntity entity;
private ManagedClientConnection conn;
private HttpResponseWrapper(final HttpResponse original, final ManagedClientConnection conn) {
private HttpResponseWrapper(
final HttpResponse original,
final ConnectionReleaseTriggerImpl connReleaseTrigger) {
super();
this.original = original;
this.conn = conn;
this.connReleaseTrigger = connReleaseTrigger;
HttpEntity entity = original.getEntity();
if (conn != null && entity != null && entity.isStreaming()) {
if (connReleaseTrigger != null && entity != null && entity.isStreaming()) {
this.entity = new EntityWrapper(entity);
}
}
@ -185,23 +186,21 @@ public class HttpResponseWrapper implements HttpResponse, ConnectionReleaseTrigg
}
private void cleanup() throws IOException {
if (this.conn != null) {
this.conn.abortConnection();
this.conn = null;
if (this.connReleaseTrigger != null) {
this.connReleaseTrigger.abortConnection();
}
}
public void releaseConnection() throws IOException {
if (this.conn != null) {
if (this.connReleaseTrigger != null) {
try {
if (this.conn.isMarkedReusable()) {
if (this.connReleaseTrigger.isReusable()) {
HttpEntity entity = this.original.getEntity();
if (entity != null) {
EntityUtils.consume(entity);
}
this.connReleaseTrigger.releaseConnection();
}
this.conn.releaseConnection();
this.conn = null;
} finally {
cleanup();
}
@ -258,7 +257,7 @@ public class HttpResponseWrapper implements HttpResponse, ConnectionReleaseTrigg
public boolean streamClosed(InputStream wrapped) throws IOException {
try {
boolean open = conn != null && conn.isOpen();
boolean open = connReleaseTrigger != null && !connReleaseTrigger.isReleased();
// this assumes that closing the stream will
// consume the remainder of the response body:
try {
@ -284,8 +283,8 @@ public class HttpResponseWrapper implements HttpResponse, ConnectionReleaseTrigg
public static HttpResponseWrapper wrap(
final HttpResponse response,
final ManagedClientConnection conn) {
return new HttpResponseWrapper(response, conn);
final ConnectionReleaseTriggerImpl connReleaseTrigger) {
return new HttpResponseWrapper(response, connReleaseTrigger);
}
}

View File

@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
@ -52,15 +53,13 @@ import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.protocol.RequestClientConnControl;
import org.apache.http.concurrent.Cancellable;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.ConnectionReleaseTrigger;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.BasicRouteDirector;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.routing.HttpRouteDirector;
import org.apache.http.conn.routing.RouteTracker;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.BufferedHttpEntity;
@ -113,7 +112,7 @@ public class MainClientExec implements ClientExecChain {
private final Log log = LogFactory.getLog(getClass());
private final HttpRequestExecutor requestExecutor;
private final ClientConnectionManager connManager;
private final HttpClientConnectionManager connManager;
private final ConnectionReuseStrategy reuseStrategy;
private final ConnectionKeepAliveStrategy keepAliveStrategy;
private final HttpProcessor proxyHttpProcessor;
@ -126,7 +125,7 @@ public class MainClientExec implements ClientExecChain {
public MainClientExec(
final HttpRequestExecutor requestExecutor,
final ClientConnectionManager connManager,
final HttpClientConnectionManager connManager,
final ConnectionReuseStrategy reuseStrategy,
final ConnectionKeepAliveStrategy keepAliveStrategy,
final AuthenticationStrategy targetAuthStrategy,
@ -196,27 +195,20 @@ public class MainClientExec implements ClientExecChain {
Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
final ClientConnectionRequest connRequest = connManager.requestConnection(route, userToken);
final ConnectionRequest connRequest = connManager.requestConnection(route, userToken);
if (execAware != null) {
if (execAware.isAborted()) {
connRequest.abortRequest();
connRequest.cancel();
throw new RequestAbortedException("Request aborted");
} else {
execAware.setCancellable(new Cancellable() {
public boolean cancel() {
connRequest.abortRequest();
return true;
}
});
execAware.setCancellable(connRequest);
}
}
ManagedClientConnection managedConn;
HttpClientConnection managedConn;
try {
long timeout = HttpClientParams.getConnectionManagerTimeout(params);
managedConn = connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
managedConn = connRequest.get(timeout, TimeUnit.MILLISECONDS);
} catch(InterruptedException interrupted) {
throw new RequestAbortedException("Request aborted", interrupted);
}
@ -234,28 +226,18 @@ public class MainClientExec implements ClientExecChain {
}
}
if (execAware != null) {
if (execAware.isAborted()) {
managedConn.releaseConnection();
throw new RequestAbortedException("Request aborted");
} else {
final ConnectionReleaseTrigger trigger = managedConn;
execAware.setCancellable(new Cancellable() {
public boolean cancel() {
try {
trigger.abortConnection();
} catch (IOException ex) {
log.debug("I/O error aborting connection", ex);
}
return true;
}
});
}
}
ConnectionReleaseTriggerImpl releaseTrigger = new ConnectionReleaseTriggerImpl(
this.log, this.connManager, managedConn);
try {
if (execAware != null) {
if (execAware.isAborted()) {
releaseTrigger.abortConnection();
throw new RequestAbortedException("Request aborted");
} else {
execAware.setCancellable(releaseTrigger);
}
}
HttpResponse response = null;
for (int execCount = 1;; execCount++) {
@ -270,21 +252,19 @@ public class MainClientExec implements ClientExecChain {
if (!managedConn.isOpen()) {
this.log.debug("Opening connection " + route);
managedConn.open(route, context, params);
try {
establishRoute(proxyAuthState, managedConn, route, request, context);
} catch (TunnelRefusedException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage());
}
response = ex.getResponse();
break;
}
} else {
managedConn.setSocketTimeout(HttpConnectionParams.getSoTimeout(params));
}
try {
establishRoute(proxyAuthState, managedConn, route, request, context);
} catch (TunnelRefusedException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage());
}
response = ex.getResponse();
break;
}
if (execAware != null && execAware.isAborted()) {
throw new RequestAbortedException("Request aborted");
}
@ -322,15 +302,15 @@ public class MainClientExec implements ClientExecChain {
}
this.log.debug("Connection can be kept alive " + s);
}
managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
managedConn.markReusable();
releaseTrigger.setValidFor(duration, TimeUnit.MILLISECONDS);
releaseTrigger.markReusable();
} else {
managedConn.unmarkReusable();
releaseTrigger.markNonReusable();
}
if (needAuthentication(
targetAuthState, proxyAuthState, route, request, response, context)) {
if (managedConn.isMarkedReusable()) {
if (releaseTrigger.isReusable()) {
// Make sure the response body is fully consumed, if present
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
@ -364,21 +344,17 @@ public class MainClientExec implements ClientExecChain {
context.setAttribute(ClientContext.USER_TOKEN, userToken);
}
if (userToken != null) {
managedConn.setState(userToken);
releaseTrigger.setState(userToken);
}
// check for entity, release connection if possible
HttpEntity entity = response.getEntity();
if (entity == null || !entity.isStreaming()) {
// connection not needed and (assumed to be) in re-usable state
try {
managedConn.releaseConnection();
} catch(IOException ex) {
this.log.debug("IOException releasing connection", ex);
}
releaseTrigger.releaseConnection();
return HttpResponseWrapper.wrap(response, null);
} else {
return HttpResponseWrapper.wrap(response, managedConn);
return HttpResponseWrapper.wrap(response, releaseTrigger);
}
} catch (ConnectionShutdownException ex) {
InterruptedIOException ioex = new InterruptedIOException(
@ -386,13 +362,13 @@ public class MainClientExec implements ClientExecChain {
ioex.initCause(ex);
throw ioex;
} catch (HttpException ex) {
abortConnection(managedConn);
releaseTrigger.abortConnection();
throw ex;
} catch (IOException ex) {
abortConnection(managedConn);
releaseTrigger.abortConnection();
throw ex;
} catch (RuntimeException ex) {
abortConnection(managedConn);
releaseTrigger.abortConnection();
throw ex;
}
}
@ -402,27 +378,34 @@ public class MainClientExec implements ClientExecChain {
*/
private void establishRoute(
final AuthState proxyAuthState,
final ManagedClientConnection managedConn,
final HttpClientConnection managedConn,
final HttpRoute route,
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
HttpParams params = request.getParams();
RouteTracker tracker = new RouteTracker(route);
int step;
do {
HttpRoute fact = managedConn.getRoute();
HttpRoute fact = tracker.toRoute();
step = this.routeDirector.nextStep(route, fact);
switch (step) {
case HttpRouteDirector.CONNECT_TARGET:
case HttpRouteDirector.CONNECT_PROXY:
managedConn.open(route, context, params);
this.connManager.connect(
managedConn, route.getTargetHost(), route.getLocalAddress(), context, params);
tracker.connectTarget(route.isSecure());
break;
case HttpRouteDirector.CONNECT_PROXY:
this.connManager.connect(
managedConn, route.getProxyHost(), route.getLocalAddress(), context, params);
HttpHost proxy = route.getProxyHost();
tracker.connectProxy(proxy, false);
break;
case HttpRouteDirector.TUNNEL_TARGET: {
boolean secure = createTunnelToTarget(proxyAuthState, managedConn, route, request, context);
this.log.debug("Tunnel to target created.");
managedConn.tunnelTarget(secure, params);
tracker.tunnelTarget(secure);
} break;
case HttpRouteDirector.TUNNEL_PROXY: {
@ -433,11 +416,11 @@ public class MainClientExec implements ClientExecChain {
final int hop = fact.getHopCount()-1; // the hop to establish
boolean secure = createTunnelToProxy(route, hop, context);
this.log.debug("Tunnel to proxy created.");
managedConn.tunnelProxy(route.getHopTarget(hop), secure, params);
tracker.tunnelProxy(route.getHopTarget(hop), secure);
} break;
case HttpRouteDirector.LAYER_PROTOCOL:
managedConn.layerProtocol(context, params);
this.connManager.upgrade(managedConn, route.getTargetHost(), context, params);
break;
case HttpRouteDirector.UNREACHABLE:
@ -473,7 +456,7 @@ public class MainClientExec implements ClientExecChain {
*/
private boolean createTunnelToTarget(
final AuthState proxyAuthState,
final ManagedClientConnection managedConn,
final HttpClientConnection managedConn,
final HttpRoute route,
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
@ -505,7 +488,8 @@ public class MainClientExec implements ClientExecChain {
for (;;) {
if (!managedConn.isOpen()) {
managedConn.open(route, context, params);
this.connManager.connect(
managedConn, route.getProxyHost(), route.getLocalAddress(), context, params);
}
connect.removeHeaders(AUTH.PROXY_AUTH_RESP);
@ -557,8 +541,6 @@ public class MainClientExec implements ClientExecChain {
response.getStatusLine(), response);
}
managedConn.markReusable();
// How to decide on security of the tunnelled connection?
// The socket factory knows only about the segment to the proxy.
// Even if that is secure, the hop to the target may be insecure.
@ -621,21 +603,4 @@ public class MainClientExec implements ClientExecChain {
return false;
}
/**
* Shuts down the connection.
* This method is called from a <code>catch</code> block in
* {@link #execute execute} during exception handling.
*/
private void abortConnection(final ManagedClientConnection managedConn) {
// we got here as the result of an exception
// no response will be returned, release the connection
try {
managedConn.abortConnection();
} catch (IOException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
}
}
}

View File

@ -59,8 +59,11 @@ import org.apache.http.conn.scheme.SchemeRegistry;
* {@link PoolingClientConnectionManager}.
*
* @since 4.2
*
* @deprecated (4.3) use {@link BasicHttpClientConnectionManager}.
*/
@ThreadSafe
@Deprecated
public class BasicClientConnectionManager implements ClientConnectionManager {
private final Log log = LogFactory.getLog(getClass());

View File

@ -0,0 +1,335 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Date;
import java.util.concurrent.TimeUnit;
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.GuardedBy;
import org.apache.http.annotation.ThreadSafe;
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.routing.HttpRoute;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.LangUtils;
/**
* A connection manager for a single connection. This connection manager maintains only one active
* connection. Even though this class is fully thread-safe it ought to be used by one execution
* thread only, as only one thread a time can lease the connection at a time.
* <p/>
* This connection manager will make an effort to reuse the connection for subsequent requests
* with the same {@link HttpRoute route}. It will, however, close the existing connection and
* open it for the given route, if the route of the persistent connection does not match that
* of the connection request. If the connection has been already been allocated
* {@link IllegalStateException} is thrown.
* <p/>
* This connection manager implementation should be used inside an EJB container instead of
* {@link PoolingHttpClientConnectionManager}.
*
* @since 4.3
*/
@ThreadSafe
public class BasicHttpClientConnectionManager implements HttpClientConnectionManager {
private final Log log = LogFactory.getLog(getClass());
private final HttpClientConnectionOperator connectionOperator;
private final HttpConnectionFactory<DefaultClientConnection> connFactory;
@GuardedBy("this")
private DefaultClientConnection conn;
@GuardedBy("this")
private HttpRoute route;
@GuardedBy("this")
private Object state;
@GuardedBy("this")
private long updated;
@GuardedBy("this")
private long expiry;
@GuardedBy("this")
private boolean leased;
@GuardedBy("this")
private volatile boolean shutdown;
public BasicHttpClientConnectionManager(
final SchemeRegistry schemeRegistry,
final DnsResolver dnsResolver,
final HttpConnectionFactory<DefaultClientConnection> connFactory) {
if (schemeRegistry == null) {
throw new IllegalArgumentException("Scheme registry may not be null");
}
this.connectionOperator = new HttpClientConnectionOperator(schemeRegistry, dnsResolver);
this.connFactory = connFactory != null ? connFactory : DefaultClientConnectionFactory.INSTANCE;
this.expiry = Long.MAX_VALUE;
}
public BasicHttpClientConnectionManager(final SchemeRegistry schemeRegistry) {
this(schemeRegistry, null, null);
}
public BasicHttpClientConnectionManager() {
this(SchemeRegistryFactory.createDefault(), null, null);
}
@Override
protected void finalize() throws Throwable {
try {
shutdown();
} finally { // Make sure we call overridden method even if shutdown barfs
super.finalize();
}
}
public SchemeRegistry getSchemeRegistry() {
return this.connectionOperator.getSchemeRegistry();
}
HttpRoute getRoute() {
return route;
}
Object getState() {
return state;
}
public final ConnectionRequest requestConnection(
final HttpRoute route,
final Object state) {
if (route == null) {
throw new IllegalArgumentException("Route may not be null");
}
return new ConnectionRequest() {
public boolean cancel() {
// Nothing to abort, since requests are immediate.
return false;
}
public HttpClientConnection get(long timeout, TimeUnit tunit) {
return BasicHttpClientConnectionManager.this.getConnection(
route, state);
}
};
}
private void closeConnection() {
if (this.conn != null) {
this.log.debug("Closing connection");
try {
this.conn.close();
} catch (IOException iox) {
if (this.log.isDebugEnabled()) {
this.log.debug("I/O exception closing connection", iox);
}
}
this.conn = null;
}
}
private void shutdownConnection() {
if (this.conn != null) {
this.log.debug("Shutting down connection");
try {
this.conn.shutdown();
} catch (IOException iox) {
if (this.log.isDebugEnabled()) {
this.log.debug("I/O exception shutting down connection", iox);
}
}
this.conn = null;
}
}
private void checkExpiry() {
if (this.conn != null && System.currentTimeMillis() >= this.expiry) {
if (this.log.isDebugEnabled()) {
this.log.debug("Connection expired @ " + new Date(this.expiry));
}
closeConnection();
}
}
synchronized HttpClientConnection getConnection(final HttpRoute route, final Object state) {
if (this.shutdown) {
throw new IllegalStateException("Connection manager has been shut down");
}
if (this.log.isDebugEnabled()) {
this.log.debug("Get connection for route " + route);
}
if (this.leased) {
throw new IllegalStateException("Connection is still allocated");
}
if (!LangUtils.equals(this.route, route) || !LangUtils.equals(this.state, state)) {
closeConnection();
}
this.route = route;
this.state = state;
checkExpiry();
if (this.conn == null) {
this.conn = this.connFactory.create();
}
this.leased = true;
return this.conn;
}
public synchronized void releaseConnection(
final HttpClientConnection conn,
final Object state,
long keepalive, final TimeUnit tunit) {
if (conn == null) {
throw new IllegalArgumentException("Connection may not be null");
}
if (conn != this.conn) {
throw new IllegalArgumentException("Connection not obtained from this manager");
}
if (this.log.isDebugEnabled()) {
this.log.debug("Releasing connection " + conn);
}
if (this.shutdown) {
shutdownConnection();
return;
}
try {
this.updated = System.currentTimeMillis();
if (!this.conn.isOpen()) {
this.conn = null;
this.route = null;
this.conn = null;
this.expiry = Long.MAX_VALUE;
} else {
this.state = state;
if (this.log.isDebugEnabled()) {
String s;
if (keepalive > 0) {
s = "for " + keepalive + " " + tunit;
} else {
s = "indefinitely";
}
this.log.debug("Connection can be kept alive " + s);
}
if (keepalive > 0) {
this.expiry = this.updated + tunit.toMillis(keepalive);
} else {
this.expiry = Long.MAX_VALUE;
}
}
} finally {
this.leased = false;
}
}
public void connect(
final HttpClientConnection conn,
final HttpHost host,
final InetAddress local,
final HttpContext context,
final HttpParams params) throws IOException {
if (conn == null) {
throw new IllegalArgumentException("Connection may not be null");
}
if (host == null) {
throw new IllegalArgumentException("HTTP host may not be null");
}
if (conn != this.conn) {
throw new IllegalArgumentException("Connection not obtained from this manager");
}
this.connectionOperator.connect(this.conn, host, local, context, params);
}
public void upgrade(
final HttpClientConnection conn,
final HttpHost host,
final HttpContext context,
final HttpParams params) throws IOException {
if (conn == null) {
throw new IllegalArgumentException("Connection may not be null");
}
if (host == null) {
throw new IllegalArgumentException("HTTP host may not be null");
}
if (conn != this.conn) {
throw new IllegalArgumentException("Connection not obtained from this manager");
}
this.connectionOperator.upgrade(this.conn, host, context, params);
}
public synchronized void closeExpiredConnections() {
if (this.shutdown) {
return;
}
if (!this.leased) {
checkExpiry();
}
}
public synchronized void closeIdleConnections(long idletime, TimeUnit tunit) {
if (tunit == null) {
throw new IllegalArgumentException("Time unit must not be null.");
}
if (this.shutdown) {
return;
}
if (!this.leased) {
long time = tunit.toMillis(idletime);
if (time < 0) {
time = 0;
}
long deadline = System.currentTimeMillis() - time;
if (this.updated <= deadline) {
closeConnection();
}
}
}
public synchronized void shutdown() {
if (this.shutdown) {
return;
}
this.shutdown = true;
shutdownConnection();
}
}

View File

@ -0,0 +1,75 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.pool.AbstractConnPool;
import org.apache.http.pool.ConnFactory;
/**
* @since 4.3
*/
@ThreadSafe
class CPool extends AbstractConnPool<HttpRoute, DefaultClientConnection, CPoolEntry> {
private static AtomicLong COUNTER = new AtomicLong();
private final Log log = LogFactory.getLog(HttpClientConnectionManager.class);
private final long timeToLive;
private final TimeUnit tunit;
public CPool(
final int defaultMaxPerRoute, final int maxTotal,
final long timeToLive, final TimeUnit tunit) {
super(new InternalConnFactory(), defaultMaxPerRoute, maxTotal);
this.timeToLive = timeToLive;
this.tunit = tunit;
}
@Override
protected CPoolEntry createEntry(final HttpRoute route, final DefaultClientConnection conn) {
String id = Long.toString(COUNTER.getAndIncrement());
return new CPoolEntry(this.log, id, route, conn, this.timeToLive, this.tunit);
}
static class InternalConnFactory implements ConnFactory<HttpRoute, DefaultClientConnection> {
public DefaultClientConnection create(final HttpRoute route) throws IOException {
return new DefaultClientConnection();
}
}
}

View File

@ -0,0 +1,82 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.http.HttpClientConnection;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.pool.PoolEntry;
/**
* @since 4.3
*/
@ThreadSafe
class CPoolEntry extends PoolEntry<HttpRoute, DefaultClientConnection> {
private final Log log;
public CPoolEntry(
final Log log,
final String id,
final HttpRoute route,
final DefaultClientConnection conn,
final long timeToLive, final TimeUnit tunit) {
super(id, route, conn, timeToLive, tunit);
this.log = log;
}
@Override
public boolean isExpired(long now) {
boolean expired = super.isExpired(now);
if (expired && this.log.isDebugEnabled()) {
this.log.debug("Connection " + this + " expired @ " + new Date(getExpiry()));
}
return expired;
}
@Override
public boolean isClosed() {
HttpClientConnection conn = getConnection();
return !conn.isOpen();
}
@Override
public void close() {
HttpClientConnection conn = getConnection();
try {
conn.close();
} catch (IOException ex) {
this.log.debug("I/O error closing connection", ex);
}
}
}

View File

@ -0,0 +1,165 @@
/*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.http.HttpClientConnection;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.conn.HttpSSLConnection;
import org.apache.http.protocol.HttpContext;
/**
* @since 4.3
*/
@NotThreadSafe
class CPoolProxy implements InvocationHandler {
private volatile CPoolEntry poolEntry;
CPoolProxy(final CPoolEntry entry) {
super();
this.poolEntry = entry;
}
CPoolEntry getPoolEntry() {
return this.poolEntry;
}
CPoolEntry detach() {
CPoolEntry local = this.poolEntry;
this.poolEntry = null;
return local;
}
HttpClientConnection getConnection() {
CPoolEntry local = this.poolEntry;
if (local == null) {
return null;
}
return local.getConnection();
}
public void close() throws IOException {
CPoolEntry local = this.poolEntry;
if (local != null) {
HttpClientConnection conn = local.getConnection();
conn.close();
}
}
public void shutdown() throws IOException {
CPoolEntry local = this.poolEntry;
if (local != null) {
HttpClientConnection conn = local.getConnection();
conn.shutdown();
}
}
public boolean isOpen() {
HttpClientConnection conn = getConnection();
if (conn != null) {
return conn.isOpen();
} else {
return false;
}
}
public boolean isStale() {
HttpClientConnection conn = getConnection();
if (conn != null) {
return conn.isStale();
} else {
return true;
}
}
public Object invoke(
final Object proxy, final Method method, final Object[] args) throws Throwable {
String mname = method.getName();
if (mname.equals("close")) {
close();
return null;
} else if (mname.equals("shutdown")) {
shutdown();
return null;
} else if (mname.equals("isOpen")) {
return isOpen();
} else if (mname.equals("isStale")) {
return isStale();
} else {
HttpClientConnection conn = getConnection();
if (conn == null) {
throw new ConnectionShutdownException();
}
try {
return method.invoke(conn, args);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause != null) {
throw cause;
} else {
throw ex;
}
}
}
}
public static HttpClientConnection newProxy(
final CPoolEntry poolEntry) {
return (HttpClientConnection) Proxy.newProxyInstance(
CPoolProxy.class.getClassLoader(),
new Class<?>[] { HttpClientConnection.class, HttpSSLConnection.class, HttpContext.class },
new CPoolProxy(poolEntry));
}
private static CPoolProxy getHandler(
final HttpClientConnection proxy) {
InvocationHandler handler = Proxy.getInvocationHandler(proxy);
if (!CPoolProxy.class.isInstance(handler)) {
throw new IllegalStateException("Unexpected proxy handler class: " + handler);
}
return CPoolProxy.class.cast(handler);
}
public static CPoolEntry getPoolEntry(final HttpClientConnection proxy) {
CPoolEntry entry = getHandler(proxy).getPoolEntry();
if (entry == null) {
throw new ConnectionShutdownException();
}
return entry;
}
public static CPoolEntry detach(final HttpClientConnection proxy) {
return getHandler(proxy).detach();
}
}

View File

@ -33,6 +33,9 @@ import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.commons.logging.Log;
@ -51,6 +54,7 @@ import org.apache.http.io.HttpMessageParser;
import org.apache.http.io.SessionInputBuffer;
import org.apache.http.io.SessionOutputBuffer;
import org.apache.http.conn.HttpSSLConnection;
import org.apache.http.conn.OperatedClientConnection;
/**
@ -70,7 +74,7 @@ import org.apache.http.conn.OperatedClientConnection;
*/
@NotThreadSafe // connSecure, targetHost
public class DefaultClientConnection extends SocketHttpClientConnection
implements OperatedClientConnection, HttpContext {
implements OperatedClientConnection, HttpSSLConnection, HttpContext {
private final Log log = LogFactory.getLog(getClass());
private final Log headerLog = LogFactory.getLog("org.apache.http.headers");
@ -109,6 +113,14 @@ public class DefaultClientConnection extends SocketHttpClientConnection
return this.socket;
}
public SSLSession getSSLSession() {
if (this.socket instanceof SSLSocket) {
return ((SSLSocket) this.socket).getSession();
} else {
return null;
}
}
public void opening(Socket sock, HttpHost target) throws IOException {
assertNotOpen();
this.socket = sock;

View File

@ -0,0 +1,45 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import org.apache.http.annotation.Immutable;
import org.apache.http.conn.HttpConnectionFactory;
/**
* @since 4.3
*/
@Immutable
public class DefaultClientConnectionFactory implements HttpConnectionFactory<DefaultClientConnection> {
public static final DefaultClientConnectionFactory INSTANCE = new DefaultClientConnectionFactory();
public DefaultClientConnection create() {
return new DefaultClientConnection();
}
}

View File

@ -84,7 +84,10 @@ import org.apache.http.conn.DnsResolver;
* </ul>
*
* @since 4.0
*
* @deprecated (4.3) use {@link PoolingHttpClientConnectionManager}.
*/
@Deprecated
@ThreadSafe
public class DefaultClientConnectionOperator implements ClientConnectionOperator {

View File

@ -0,0 +1,215 @@
/*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.io.IOException;
import java.net.InetAddress;
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.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.routing.HttpRoute;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.params.HttpParams;
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<HttpRoute, CPoolEntry> pool;
private final HttpClientConnectionOperator connectionOperator;
HttpClientConnectionManagerBase(
final ConnPool<HttpRoute, CPoolEntry> pool,
final SchemeRegistry schemeRegistry,
final DnsResolver dnsResolver) {
super();
if (pool == null) {
throw new IllegalArgumentException("Connection pool may nor be null");
}
if (schemeRegistry == null) {
throw new IllegalArgumentException("Scheme registry may nor be null");
}
this.pool = pool;
this.connectionOperator = new HttpClientConnectionOperator(schemeRegistry, dnsResolver);
}
@Override
protected void finalize() throws Throwable {
try {
shutdown();
} finally {
super.finalize();
}
}
public SchemeRegistry getSchemeRegistry() {
return this.connectionOperator.getSchemeRegistry();
}
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<CPoolEntry> 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<CPoolEntry> 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;
}
DefaultClientConnection 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 HttpContext context,
final HttpParams params) throws IOException {
if (managedConn == null) {
throw new IllegalArgumentException("Connection may not be null");
}
DefaultClientConnection conn;
synchronized (managedConn) {
CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
conn = entry.getConnection();
}
this.connectionOperator.connect(conn, host, local, context, params);
}
public void upgrade(
final HttpClientConnection managedConn,
final HttpHost host,
final HttpContext context,
final HttpParams params) throws IOException {
if (managedConn == null) {
throw new IllegalArgumentException("Connection may not be null");
}
DefaultClientConnection conn;
synchronized (managedConn) {
CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
conn = entry.getConnection();
}
this.connectionOperator.upgrade(conn, host, context, params);
}
}

View File

@ -0,0 +1,163 @@
/*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.http.annotation.Immutable;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.conn.HttpInetSocketAddress;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeLayeredSocketFactory;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
@Immutable
class HttpClientConnectionOperator {
private final Log log = LogFactory.getLog(HttpClientConnectionManager.class);
private final SchemeRegistry schemeRegistry;
private final DnsResolver dnsResolver;
HttpClientConnectionOperator(
final SchemeRegistry schemeRegistry,
final DnsResolver dnsResolver) {
super();
if (schemeRegistry == null) {
throw new IllegalArgumentException("Scheme registry may nor be null");
}
this.schemeRegistry = schemeRegistry;
this.dnsResolver = dnsResolver != null ? dnsResolver : SystemDefaultDnsResolver.INSTANCE;
}
public SchemeRegistry getSchemeRegistry() {
return this.schemeRegistry;
}
public DnsResolver getDnsResolver() {
return this.dnsResolver;
}
private SchemeRegistry getSchemeRegistry(final HttpContext context) {
SchemeRegistry reg = (SchemeRegistry) context.getAttribute(
ClientContext.SCHEME_REGISTRY);
if (reg == null) {
reg = this.schemeRegistry;
}
return reg;
}
public void connect(
final DefaultClientConnection conn,
final HttpHost host,
final InetAddress local,
final HttpContext context,
final HttpParams params) throws IOException {
SchemeRegistry registry = getSchemeRegistry(context);
Scheme schm = registry.getScheme(host.getSchemeName());
SchemeSocketFactory sf = schm.getSchemeSocketFactory();
InetAddress[] addresses = this.dnsResolver.resolve(host.getHostName());
int port = schm.resolvePort(host.getPort());
for (int i = 0; i < addresses.length; i++) {
InetAddress address = addresses[i];
boolean last = i == addresses.length - 1;
Socket sock = sf.createSocket(params);
conn.opening(sock, host);
InetSocketAddress remoteAddress = new HttpInetSocketAddress(host, address, port);
InetSocketAddress localAddress = null;
if (local != null) {
localAddress = new InetSocketAddress(local, 0);
}
if (this.log.isDebugEnabled()) {
this.log.debug("Connecting to " + remoteAddress);
}
try {
Socket connsock = sf.connectSocket(sock, remoteAddress, localAddress, params);
if (sock != connsock) {
sock = connsock;
conn.opening(sock, host);
}
conn.openCompleted(sf.isSecure(sock), params);
return;
} catch (ConnectException ex) {
if (last) {
throw new HttpHostConnectException(host, ex);
}
} catch (ConnectTimeoutException ex) {
if (last) {
throw ex;
}
}
if (this.log.isDebugEnabled()) {
this.log.debug("Connect to " + remoteAddress + " timed out. " +
"Connection will be retried using another IP address");
}
}
}
public void upgrade(
final DefaultClientConnection conn,
final HttpHost host,
final HttpContext context,
final HttpParams params) throws IOException {
SchemeRegistry registry = getSchemeRegistry(context);
Scheme schm = registry.getScheme(host.getSchemeName());
if (!(schm.getSchemeSocketFactory() instanceof SchemeLayeredSocketFactory)) {
throw new IllegalArgumentException
("Target scheme (" + schm.getName() +
") must have layered socket factory.");
}
SchemeLayeredSocketFactory lsf = (SchemeLayeredSocketFactory) schm.getSchemeSocketFactory();
Socket sock;
try {
int port = schm.resolvePort(host.getPort());
sock = lsf.createLayeredSocket(
conn.getSocket(), host.getHostName(), port, params);
} catch (ConnectException ex) {
throw new HttpHostConnectException(host, ex);
}
conn.update(sock, host, lsf.isSecure(sock), params);
}
}

View File

@ -38,7 +38,10 @@ import org.apache.http.pool.ConnFactory;
/**
* @since 4.2
*
* @deprecated (4.3) no longer used.
*/
@Deprecated
class HttpConnPool extends AbstractConnPool<HttpRoute, OperatedClientConnection, HttpPoolEntry> {
private static AtomicLong COUNTER = new AtomicLong();

View File

@ -38,7 +38,10 @@ import org.apache.http.pool.PoolEntry;
/**
* @since 4.2
*
* @deprecated (4.3) no longer used.
*/
@Deprecated
class HttpPoolEntry extends PoolEntry<HttpRoute, OperatedClientConnection> {
private final Log log;

View File

@ -51,6 +51,12 @@ import org.apache.http.conn.routing.RouteTracker;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
/**
* @since 4.2
*
* @deprecated (4.3) no longer used.
*/
@Deprecated
@NotThreadSafe
class ManagedClientConnectionImpl implements ManagedClientConnection {

View File

@ -66,7 +66,10 @@ import org.apache.http.conn.DnsResolver;
* can be adjusted using HTTP parameters.
*
* @since 4.2
*
* @deprecated (4.3) use {@link PoolingHttpClientConnectionManager}.
*/
@Deprecated
@ThreadSafe
public class PoolingClientConnectionManager implements ClientConnectionManager, ConnPoolControl<HttpRoute> {

View File

@ -0,0 +1,231 @@
/*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpClientConnection;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.pool.ConnPoolControl;
import org.apache.http.pool.PoolStats;
/**
* <tt>ClientConnectionPoolManager</tt> maintains a pool of
* {@link HttpClientConnection}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.
* <p/>
* <tt>ClientConnectionPoolManager</tt> 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.
*
* @since 4.3
*/
@ThreadSafe
public class PoolingHttpClientConnectionManager extends HttpClientConnectionManagerBase {
private final Log log = LogFactory.getLog(getClass());
private final CPool pool;
public PoolingHttpClientConnectionManager() {
this(SchemeRegistryFactory.createDefault());
}
public PoolingHttpClientConnectionManager(final SchemeRegistry schreg) {
this(schreg, -1, TimeUnit.MILLISECONDS);
}
public PoolingHttpClientConnectionManager(
final SchemeRegistry schreg, final DnsResolver dnsResolver) {
this(schreg, dnsResolver, -1, TimeUnit.MILLISECONDS);
}
public PoolingHttpClientConnectionManager(
final SchemeRegistry schemeRegistry,
final long timeToLive, final TimeUnit tunit) {
this(new CPool(2, 20, timeToLive, tunit), schemeRegistry, null);
}
public PoolingHttpClientConnectionManager(
final SchemeRegistry schemeRegistry,
final DnsResolver dnsResolver,
final long timeToLive, final TimeUnit tunit) {
this(new CPool(2, 20, timeToLive, tunit), schemeRegistry, dnsResolver);
}
PoolingHttpClientConnectionManager(
final CPool pool,
final SchemeRegistry schemeRegistry,
final DnsResolver dnsResolver) {
super(pool, schemeRegistry, dnsResolver);
this.pool = pool;
}
@Override
protected void finalize() throws Throwable {
try {
shutdown();
} finally {
super.finalize();
}
}
private String format(final HttpRoute route, final Object state) {
StringBuilder buf = new StringBuilder();
buf.append("[route: ").append(route).append("]");
if (state != null) {
buf.append("[state: ").append(state).append("]");
}
return buf.toString();
}
private String formatStats(final HttpRoute route) {
StringBuilder buf = new StringBuilder();
PoolStats totals = this.pool.getTotalStats();
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 CPoolEntry entry) {
StringBuilder buf = new StringBuilder();
buf.append("[id: ").append(entry.getId()).append("]");
buf.append("[route: ").append(entry.getRoute()).append("]");
Object state = entry.getState();
if (state != null) {
buf.append("[state: ").append(state).append("]");
}
return buf.toString();
}
@Override
protected void onConnectionLeaseRequest(final HttpRoute route, final Object state) {
if (this.log.isDebugEnabled()) {
this.log.debug("Connection request: " + format(route, state) + formatStats(route));
}
}
@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";
}
this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
}
}
@Override
protected void onConnectionRelease(final CPoolEntry entry) {
if (this.log.isDebugEnabled()) {
this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
}
}
public void shutdown() {
this.log.debug("Connection manager is shutting down");
try {
this.pool.shutdown();
} catch (IOException ex) {
this.log.debug("I/O exception shutting down connection manager", ex);
}
this.log.debug("Connection manager shut down");
}
public void closeIdleConnections(long idleTimeout, TimeUnit tunit) {
if (this.log.isDebugEnabled()) {
this.log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit);
}
this.pool.closeIdle(idleTimeout, tunit);
}
public void closeExpiredConnections() {
this.log.debug("Closing expired connections");
this.pool.closeExpired();
}
public int getMaxTotal() {
return this.pool.getMaxTotal();
}
public void setMaxTotal(int max) {
this.pool.setMaxTotal(max);
}
public int getDefaultMaxPerRoute() {
return this.pool.getDefaultMaxPerRoute();
}
public void setDefaultMaxPerRoute(int max) {
this.pool.setDefaultMaxPerRoute(max);
}
public int getMaxPerRoute(final HttpRoute route) {
return this.pool.getMaxPerRoute(route);
}
public void setMaxPerRoute(final HttpRoute route, int max) {
this.pool.setMaxPerRoute(route, max);
}
public PoolStats getTotalStats() {
return this.pool.getTotalStats();
}
public PoolStats getStats(final HttpRoute route) {
return this.pool.getStats(route);
}
}

View File

@ -38,6 +38,8 @@ import org.apache.http.conn.DnsResolver;
*/
public class SystemDefaultDnsResolver implements DnsResolver {
public static final SystemDefaultDnsResolver INSTANCE = new SystemDefaultDnsResolver();
/**
* {@inheritDoc}
*/

View File

@ -39,7 +39,7 @@ import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.localserver.LocalTestServer;
import org.apache.http.localserver.RandomHandler;
import org.apache.http.protocol.BasicHttpProcessor;
@ -79,7 +79,7 @@ public class TestConnectionReuse {
InetSocketAddress saddress = this.localServer.getServiceAddress();
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(5);
mgr.setDefaultMaxPerRoute(5);
@ -138,7 +138,7 @@ public class TestConnectionReuse {
InetSocketAddress saddress = this.localServer.getServiceAddress();
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(5);
mgr.setDefaultMaxPerRoute(5);
@ -188,7 +188,7 @@ public class TestConnectionReuse {
InetSocketAddress saddress = this.localServer.getServiceAddress();
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(5);
mgr.setDefaultMaxPerRoute(5);
@ -239,7 +239,7 @@ public class TestConnectionReuse {
InetSocketAddress saddress = this.localServer.getServiceAddress();
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(1);
mgr.setDefaultMaxPerRoute(1);

View File

@ -1,187 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn.params;
import java.net.InetAddress;
import org.apache.http.HttpHost;
import org.apache.http.params.HttpParams;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.DefaultedHttpParams;
import org.apache.http.conn.routing.HttpRoute;
// for hierarchy testing
import org.apache.http.impl.client.ClientParamsStack;
import org.junit.Assert;
import org.junit.Test;
/**
* Unit tests for parameters.
* Trivial, but it looks better in the Clover reports.
*/
public class TestRouteParams {
public final static
HttpHost TARGET1 = new HttpHost("target1.test.invalid");
public final static
HttpRoute ROUTE1 = new HttpRoute(TARGET1);
public final static InetAddress LOCAL1;
// need static initializer to deal with exceptions
static {
try {
LOCAL1 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
} catch (Exception x) {
throw new ExceptionInInitializerError(x);
}
}
@Test
public void testSetGet() {
HttpParams params = new BasicHttpParams();
Assert.assertNull("phantom proxy",
ConnRouteParams.getDefaultProxy(params));
Assert.assertNull("phantom route",
ConnRouteParams.getForcedRoute(params));
Assert.assertNull("phantom address",
ConnRouteParams.getLocalAddress(params));
ConnRouteParams.setDefaultProxy(params, TARGET1);
Assert.assertSame("wrong proxy", TARGET1,
ConnRouteParams.getDefaultProxy(params));
ConnRouteParams.setForcedRoute(params, ROUTE1);
Assert.assertSame("wrong route", ROUTE1,
ConnRouteParams.getForcedRoute(params));
ConnRouteParams.setLocalAddress(params, LOCAL1);
Assert.assertSame("wrong address", LOCAL1,
ConnRouteParams.getLocalAddress(params));
}
@Test
public void testSetNull() {
HttpParams params = new BasicHttpParams();
ConnRouteParams.setDefaultProxy(params, null);
ConnRouteParams.setForcedRoute(params, null);
ConnRouteParams.setLocalAddress(params, null);
Assert.assertNull("phantom proxy",
ConnRouteParams.getDefaultProxy(params));
Assert.assertNull("phantom route",
ConnRouteParams.getForcedRoute(params));
Assert.assertNull("phantom address",
ConnRouteParams.getLocalAddress(params));
ConnRouteParams.setDefaultProxy(params, ConnRouteParams.NO_HOST);
Assert.assertNull("null proxy not detected",
ConnRouteParams.getDefaultProxy(params));
ConnRouteParams.setForcedRoute(params, ConnRouteParams.NO_ROUTE);
Assert.assertNull("null route not detected",
ConnRouteParams.getForcedRoute(params));
}
@Test
public void testUnsetHierarchy() {
// hierarchical unsetting is only tested for the default proxy
HttpParams daddy = new BasicHttpParams();
HttpParams dummy = new BasicHttpParams();
HttpParams child = new BasicHttpParams();
ConnRouteParams.setDefaultProxy(daddy, TARGET1);
ConnRouteParams.setDefaultProxy(child, ConnRouteParams.NO_HOST);
HttpParams hierarchy =
new ClientParamsStack(null, daddy, child, null);
Assert.assertNull("1", ConnRouteParams.getDefaultProxy(hierarchy));
hierarchy = new ClientParamsStack
(null,
daddy,
new ClientParamsStack(null, child, dummy, null),
null);
Assert.assertNull("2", ConnRouteParams.getDefaultProxy(hierarchy));
hierarchy = new ClientParamsStack
(null, daddy, new DefaultedHttpParams(child, dummy), null);
Assert.assertNull("3", ConnRouteParams.getDefaultProxy(hierarchy));
hierarchy = new DefaultedHttpParams(child, daddy);
Assert.assertNull("4", ConnRouteParams.getDefaultProxy(hierarchy));
hierarchy = new DefaultedHttpParams
(new DefaultedHttpParams(child, dummy), daddy);
Assert.assertNull("5", ConnRouteParams.getDefaultProxy(hierarchy));
hierarchy = new DefaultedHttpParams
(child, new DefaultedHttpParams(dummy, daddy));
Assert.assertNull("6", ConnRouteParams.getDefaultProxy(hierarchy));
}
@Test
public void testBadArgs() {
try {
ConnRouteParams.getDefaultProxy(null);
} catch (IllegalArgumentException iax) {
// expected
}
try {
ConnRouteParams.getForcedRoute(null);
} catch (IllegalArgumentException iax) {
// expected
}
try {
ConnRouteParams.getLocalAddress(null);
} catch (IllegalArgumentException iax) {
// expected
}
try {
ConnRouteParams.setDefaultProxy(null, null);
} catch (IllegalArgumentException iax) {
// expected
}
try {
ConnRouteParams.setForcedRoute(null, null);
} catch (IllegalArgumentException iax) {
// expected
}
try {
ConnRouteParams.setLocalAddress(null, null);
} catch (IllegalArgumentException iax) {
// expected
}
}
}

View File

@ -48,6 +48,7 @@ import org.apache.http.protocol.HttpContext;
import org.junit.Before;
import org.junit.Test;
@Deprecated
public class TestAutoRetryHttpClient{
private AutoRetryHttpClient impl;

View File

@ -34,12 +34,12 @@ import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
@ -54,7 +54,7 @@ public class TestRequestRetryHandler {
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", 80, new OppsieSchemeSocketFactory()));
ClientConnectionManager connManager = new PoolingClientConnectionManager(schemeRegistry);
HttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(schemeRegistry);
TestHttpRequestRetryHandler testRetryHandler = new TestHttpRequestRetryHandler();
HttpClient client = new HttpClientBuilder()

View File

@ -28,10 +28,12 @@ package org.apache.http.impl.client.integration;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
@ -41,16 +43,15 @@ import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.Cancellable;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.message.BasicHeader;
import org.apache.http.mockup.SocketFactoryMockup;
@ -171,7 +172,7 @@ public class TestAbortHandling extends IntegrationTestBase {
this.localServer.register("*", new BasicService());
final CountDownLatch releaseLatch = new CountDownLatch(1);
final PoolingClientConnectionManager conMan = new PoolingClientConnectionManager();
final PoolingHttpClientConnectionManager conMan = new PoolingHttpClientConnectionManager();
final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
final CountDownLatch getLatch = new CountDownLatch(1);
final HttpClient client = new HttpClientBuilder().setConnectionManager(conMan).build();
@ -210,7 +211,7 @@ public class TestAbortHandling extends IntegrationTestBase {
public void testAbortBeforeExecute() throws Exception {
this.localServer.register("*", new BasicService());
final PoolingClientConnectionManager conMan = new PoolingClientConnectionManager();
final PoolingHttpClientConnectionManager conMan = new PoolingHttpClientConnectionManager();
final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
final CountDownLatch getLatch = new CountDownLatch(1);
final CountDownLatch startLatch = new CountDownLatch(1);
@ -296,15 +297,17 @@ public class TestAbortHandling extends IntegrationTestBase {
*/
@Test
public void testSocketConnectFailureReleasesConnection() throws Exception {
ManagedClientConnection conn = Mockito.mock(ManagedClientConnection.class);
Mockito.doThrow(new ConnectException()).when(conn).open(
Mockito.any(HttpRoute.class),
HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
ConnectionRequest connrequest = Mockito.mock(ConnectionRequest.class);
Mockito.when(connrequest.get(
Mockito.anyInt(), Mockito.any(TimeUnit.class))).thenReturn(conn);
HttpClientConnectionManager connmgr = Mockito.mock(HttpClientConnectionManager.class);
Mockito.doThrow(new ConnectException()).when(connmgr).connect(
Mockito.any(HttpClientConnection.class),
Mockito.any(HttpHost.class),
Mockito.any(InetAddress.class),
Mockito.any(HttpContext.class),
Mockito.any(HttpParams.class));
ClientConnectionRequest connrequest = Mockito.mock(ClientConnectionRequest.class);
Mockito.when(connrequest.getConnection(
Mockito.anyInt(), Mockito.any(TimeUnit.class))).thenReturn(conn);
ClientConnectionManager connmgr = Mockito.mock(ClientConnectionManager.class);
SchemeRegistry schemeRegistry = SchemeRegistryFactory.createDefault();
@ -321,7 +324,7 @@ public class TestAbortHandling extends IntegrationTestBase {
Assert.fail("expected IOException");
} catch(IOException expected) {}
Mockito.verify(conn).abortConnection();
Mockito.verify(connmgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
}
private static class BasicService implements HttpRequestHandler {
@ -352,7 +355,7 @@ public class TestAbortHandling extends IntegrationTestBase {
}
}
private static class ConnMan4 extends PoolingClientConnectionManager {
private static class ConnMan4 extends PoolingHttpClientConnectionManager {
private final CountDownLatch connLatch;
private final CountDownLatch awaitLatch;
@ -363,19 +366,20 @@ public class TestAbortHandling extends IntegrationTestBase {
}
@Override
public ClientConnectionRequest requestConnection(HttpRoute route, Object state) {
public ConnectionRequest requestConnection(HttpRoute route, Object state) {
// If this is the redirect route, stub the return value
// so-as to pretend the host is waiting on a slot...
if(route.getTargetHost().getHostName().equals("localhost")) {
final Thread currentThread = Thread.currentThread();
return new ClientConnectionRequest() {
return new ConnectionRequest() {
public void abortRequest() {
public boolean cancel() {
currentThread.interrupt();
return true;
}
public ManagedClientConnection getConnection(
public HttpClientConnection get(
long timeout, TimeUnit tunit)
throws InterruptedException,
ConnectionPoolTimeoutException {
@ -388,7 +392,7 @@ public class TestAbortHandling extends IntegrationTestBase {
if(!awaitLatch.await(timeout, tunit))
throw new ConnectionPoolTimeoutException();
return Mockito.mock(ManagedClientConnection.class);
return Mockito.mock(HttpClientConnection.class);
}
};
} else {
@ -398,7 +402,7 @@ public class TestAbortHandling extends IntegrationTestBase {
}
static class ConMan implements ClientConnectionManager {
static class ConMan implements HttpClientConnectionManager {
private final CountDownLatch connLatch;
private final CountDownLatch awaitLatch;
@ -415,28 +419,25 @@ public class TestAbortHandling extends IntegrationTestBase {
throw new UnsupportedOperationException("just a mockup");
}
public ManagedClientConnection getConnection(HttpRoute route) {
throw new UnsupportedOperationException("just a mockup");
}
public ManagedClientConnection getConnection(HttpRoute route,
public HttpClientConnection getConnection(HttpRoute route,
long timeout, TimeUnit tunit) {
throw new UnsupportedOperationException("just a mockup");
}
public ClientConnectionRequest requestConnection(
public ConnectionRequest requestConnection(
final HttpRoute route,
final Object state) {
final Thread currentThread = Thread.currentThread();
return new ClientConnectionRequest() {
return new ConnectionRequest() {
public void abortRequest() {
public boolean cancel() {
currentThread.interrupt();
return true;
}
public ManagedClientConnection getConnection(
public HttpClientConnection get(
long timeout, TimeUnit tunit)
throws InterruptedException,
ConnectionPoolTimeoutException {
@ -449,8 +450,9 @@ public class TestAbortHandling extends IntegrationTestBase {
if(!awaitLatch.await(timeout, tunit))
throw new ConnectionPoolTimeoutException();
return Mockito.mock(ManagedClientConnection.class);
return Mockito.mock(HttpClientConnection.class);
}
};
}
@ -464,11 +466,22 @@ public class TestAbortHandling extends IntegrationTestBase {
return registry;
}
public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
public void shutdown() {
}
public void releaseConnection(HttpClientConnection conn, Object newState,
long validDuration, TimeUnit timeUnit) {
throw new UnsupportedOperationException("just a mockup");
}
public void shutdown() {
public void connect(HttpClientConnection conn, HttpHost host, InetAddress localAddress,
HttpContext context, HttpParams params) throws IOException {
throw new UnsupportedOperationException("just a mockup");
}
public void upgrade(HttpClientConnection conn, HttpHost host, HttpContext context,
HttpParams params) throws IOException {
throw new UnsupportedOperationException("just a mockup");
}
}

View File

@ -32,6 +32,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
@ -39,14 +40,13 @@ import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.MalformedChunkCodingException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
@ -58,12 +58,12 @@ import org.junit.Test;
public class TestConnectionAutoRelease extends IntegrationTestBase {
private PoolingClientConnectionManager mgr;
private PoolingHttpClientConnectionManager mgr;
@Before
public void setUp() throws Exception {
startServer();
this.mgr = new PoolingClientConnectionManager();
this.mgr = new PoolingHttpClientConnectionManager();
this.httpclient = new HttpClientBuilder().setConnectionManager(this.mgr).build();
}
@ -82,9 +82,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
HttpResponse response = this.httpclient.execute(target, httpget);
ClientConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
try {
connreq.getConnection(250, TimeUnit.MILLISECONDS);
connreq.get(250, TimeUnit.MILLISECONDS);
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
} catch (ConnectionPoolTimeoutException expected) {
}
@ -99,9 +99,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
// Make sure one connection is available
connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ManagedClientConnection conn = connreq.getConnection(250, TimeUnit.MILLISECONDS);
HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
this.mgr.releaseConnection(conn, -1, null);
this.mgr.releaseConnection(conn, null, -1, null);
}
@Test
@ -119,9 +119,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
HttpResponse response = this.httpclient.execute(target, httpget);
ClientConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
try {
connreq.getConnection(250, TimeUnit.MILLISECONDS);
connreq.get(250, TimeUnit.MILLISECONDS);
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
} catch (ConnectionPoolTimeoutException expected) {
}
@ -137,9 +137,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
// Make sure one connection is available
connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ManagedClientConnection conn = connreq.getConnection(250, TimeUnit.MILLISECONDS);
HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
this.mgr.releaseConnection(conn, -1, null);
this.mgr.releaseConnection(conn, null, -1, null);
}
@Test
@ -157,9 +157,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
HttpResponse response = this.httpclient.execute(target, httpget);
ClientConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
try {
connreq.getConnection(250, TimeUnit.MILLISECONDS);
connreq.get(250, TimeUnit.MILLISECONDS);
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
} catch (ConnectionPoolTimeoutException expected) {
}
@ -173,9 +173,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
// Make sure one connection is available
connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ManagedClientConnection conn = connreq.getConnection(250, TimeUnit.MILLISECONDS);
HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
this.mgr.releaseConnection(conn, -1, null);
this.mgr.releaseConnection(conn, null, -1, null);
}
@Test
@ -224,9 +224,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
HttpResponse response = this.httpclient.execute(target, httpget);
ClientConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
try {
connreq.getConnection(250, TimeUnit.MILLISECONDS);
connreq.get(250, TimeUnit.MILLISECONDS);
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
} catch (ConnectionPoolTimeoutException expected) {
}
@ -246,9 +246,9 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
// Make sure one connection is available
connreq = this.mgr.requestConnection(new HttpRoute(target), null);
ManagedClientConnection conn = connreq.getConnection(250, TimeUnit.MILLISECONDS);
HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
this.mgr.releaseConnection(conn, -1, null);
this.mgr.releaseConnection(conn, null, -1, null);
}
}

View File

@ -25,10 +25,9 @@
*
*/
package org.apache.http.impl.conn;
package org.apache.http.impl.client.integration;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
@ -37,24 +36,24 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionOperator;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.OperatedClientConnection;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.localserver.LocalServerTestBase;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams;
@ -73,76 +72,30 @@ import org.junit.Before;
import org.junit.Test;
/**
* Tests for <code>PoolingClientConnectionManager</code> that do require a server
* Tests for <code>PoolingHttpClientConnectionManager</code> that do require a server
* to communicate with.
*/
public class TestPoolingConnManager extends LocalServerTestBase {
public class TestConnectionManagement extends LocalServerTestBase {
@Before
@Before
public void setup() throws Exception {
startServer();
}
/**
* Tests executing several requests in parallel.
*/
@Test
public void testParallelRequests() throws Exception {
// 3.x: TestHttpConnectionManager.testGetFromMultipleThreads
final int COUNT = 8; // adjust to execute more requests
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
mgr.setMaxTotal(COUNT/2);
mgr.setDefaultMaxPerRoute(COUNT/2);
final HttpHost target = getServerHttp();
final HttpRoute route = new HttpRoute(target, null, false);
final int rsplen = 8;
final String uri = "/random/" + rsplen;
ExecReqThread[] threads = new ExecReqThread [COUNT];
for (int i=0; i<COUNT; i++) {
HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
threads[i] = new ExecReqThread(request, route, mgr, 5000L);
}
for (int i=0; i<threads.length; i++) {
threads[i].start();
}
for (int i=0; i<threads.length; i++) {
threads[i].join(10000);
Assert.assertNull("exception in thread " + i,
threads[i].getException());
Assert.assertNotNull("no response in thread " + i,
threads[i].getResponse());
Assert.assertEquals("wrong status code in thread " + i, 200,
threads[i].getResponse()
.getStatusLine().getStatusCode());
Assert.assertNotNull("no response data in thread " + i,
threads[i].getResponseData());
Assert.assertEquals("wrong length of data in thread" + i, rsplen,
threads[i].getResponseData().length);
}
mgr.shutdown();
}
private static ManagedClientConnection getConnection(
final ClientConnectionManager mgr,
private static HttpClientConnection getConnection(
final HttpClientConnectionManager mgr,
final HttpRoute route,
long timeout,
TimeUnit unit) throws ConnectionPoolTimeoutException, InterruptedException {
ClientConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.getConnection(timeout, unit);
ConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.get(timeout, unit);
}
private static ManagedClientConnection getConnection(
final ClientConnectionManager mgr,
private static HttpClientConnection getConnection(
final HttpClientConnectionManager mgr,
final HttpRoute route) throws ConnectionPoolTimeoutException, InterruptedException {
ClientConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.getConnection(0, null);
ConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.get(0, null);
}
/**
@ -151,7 +104,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
@Test
public void testReleaseConnection() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(1);
HttpHost target = getServerHttp();
@ -162,16 +115,16 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
ManagedClientConnection conn = getConnection(mgr, route);
conn.open(route, context, params);
HttpClientConnection conn = getConnection(mgr, route);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
HttpProcessor httpProcessor = new ImmutableHttpProcessor(
new HttpRequestInterceptor[] { new RequestContent(), new RequestConnControl() });
HttpRequestExecutor exec = new HttpRequestExecutor();
exec.preProcess(request, httpProcessor, context);
HttpResponse response = exec.execute(request, conn, context);
@ -193,13 +146,12 @@ public class TestPoolingConnManager extends LocalServerTestBase {
// expected
}
// release connection without marking for re-use
// expect the next connection obtained to be closed
mgr.releaseConnection(conn, -1, null);
conn.close();
mgr.releaseConnection(conn, null, -1, null);
conn = getConnection(mgr, route);
Assert.assertFalse("connection should have been closed", conn.isOpen());
conn.open(route, context, params);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
// repeat the communication, no need to prepare the request again
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
@ -215,8 +167,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
// release connection after marking it for re-use
// expect the next connection obtained to be open
conn.markReusable();
mgr.releaseConnection(conn, -1, null);
mgr.releaseConnection(conn, null, -1, null);
conn = getConnection(mgr, route);
Assert.assertTrue("connection should have been open", conn.isOpen());
@ -232,7 +183,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
rsplen, data.length);
// ignore data, but it must be read
mgr.releaseConnection(conn, -1, null);
mgr.releaseConnection(conn, null, -1, null);
mgr.shutdown();
}
@ -242,7 +193,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
@Test
public void testReleaseConnectionWithTimeLimits() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(1);
HttpHost target = getServerHttp();
@ -254,15 +205,15 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
ManagedClientConnection conn = getConnection(mgr, route);
conn.open(route, context, params);
HttpClientConnection conn = getConnection(mgr, route);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
HttpProcessor httpProcessor = new ImmutableHttpProcessor(
new HttpRequestInterceptor[] { new RequestContent(), new RequestConnControl() });
HttpRequestExecutor exec = new HttpRequestExecutor();
exec.preProcess(request, httpProcessor, context);
HttpResponse response = exec.execute(request, conn, context);
@ -284,15 +235,14 @@ public class TestPoolingConnManager extends LocalServerTestBase {
// expected
}
// release connection without marking for re-use
// expect the next connection obtained to be closed
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
conn.close();
mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
conn = getConnection(mgr, route);
Assert.assertFalse("connection should have been closed", conn.isOpen());
// repeat the communication, no need to prepare the request again
conn.open(route, context, params);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
response = exec.execute(request, conn, context);
@ -304,10 +254,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
rsplen, data.length);
// ignore data, but it must be read
// release connection after marking it for re-use
// expect the next connection obtained to be open
conn.markReusable();
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
conn = getConnection(mgr, route);
Assert.assertTrue("connection should have been open", conn.isOpen());
@ -323,15 +270,14 @@ public class TestPoolingConnManager extends LocalServerTestBase {
rsplen, data.length);
// ignore data, but it must be read
conn.markReusable();
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
Thread.sleep(150);
conn = getConnection(mgr, route);
Assert.assertTrue("connection should have been closed", !conn.isOpen());
// repeat the communication, no need to prepare the request again
conn.open(route, context, params);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
response = exec.execute(request, conn, context);
@ -349,7 +295,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
@Test
public void testCloseExpiredIdleConnections() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(1);
HttpHost target = getServerHttp();
@ -357,13 +303,13 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
ManagedClientConnection conn = getConnection(mgr, route);
conn.open(route, context, params);
HttpClientConnection conn = getConnection(mgr, route);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
Assert.assertEquals(1, mgr.getTotalStats().getLeased());
Assert.assertEquals(1, mgr.getStats(route).getLeased());
conn.markReusable();
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
// Released, still active.
Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
@ -389,7 +335,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
@Test
public void testCloseExpiredTTLConnections() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager(
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(
SchemeRegistryFactory.createDefault(), 100, TimeUnit.MILLISECONDS);
mgr.setMaxTotal(1);
@ -398,14 +344,13 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
ManagedClientConnection conn = getConnection(mgr, route);
conn.open(route, context, params);
HttpClientConnection conn = getConnection(mgr, route);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
Assert.assertEquals(1, mgr.getTotalStats().getLeased());
Assert.assertEquals(1, mgr.getStats(route).getLeased());
// Release, let remain idle for forever
conn.markReusable();
mgr.releaseConnection(conn, -1, TimeUnit.MILLISECONDS);
mgr.releaseConnection(conn, null, -1, TimeUnit.MILLISECONDS);
// Released, still active.
Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
@ -435,7 +380,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
@Test
public void testReleaseConnectionOnAbort() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(1);
HttpHost target = getServerHttp();
@ -448,15 +393,15 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpRequest request =
new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
ManagedClientConnection conn = getConnection(mgr, route);
conn.open(route, context, params);
HttpClientConnection conn = getConnection(mgr, route);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
HttpProcessor httpProcessor = new ImmutableHttpProcessor(
new HttpRequestInterceptor[] { new RequestContent(), new RequestConnControl() });
HttpRequestExecutor exec = new HttpRequestExecutor();
exec.preProcess(request, httpProcessor, context);
HttpResponse response = exec.execute(request, conn, context);
@ -475,14 +420,15 @@ public class TestPoolingConnManager extends LocalServerTestBase {
}
// abort the connection
Assert.assertTrue(conn instanceof ManagedClientConnection);
((ManagedClientConnection) conn).abortConnection();
Assert.assertTrue(conn instanceof HttpClientConnection);
conn.shutdown();
mgr.releaseConnection(conn, null, -1, null);
// the connection is expected to be released back to the manager
conn = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
Assert.assertFalse("connection should have been closed", conn.isOpen());
mgr.releaseConnection(conn, -1, null);
mgr.releaseConnection(conn, null, -1, null);
mgr.shutdown();
}
@ -495,7 +441,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
SchemeRegistry registry = new SchemeRegistry();
registry.register(scheme);
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager(registry);
final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(registry);
mgr.setMaxTotal(1);
HttpHost target = getServerHttp();
@ -503,14 +449,15 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
final ManagedClientConnection conn = getConnection(mgr, route);
final HttpClientConnection conn = getConnection(mgr, route);
final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
Thread abortingThread = new Thread(new Runnable() {
public void run() {
try {
stallingSocketFactory.waitForState();
conn.abortConnection();
conn.shutdown();
mgr.releaseConnection(conn, null, -1, null);
connectLatch.countDown();
} catch (Throwable e) {
throwRef.set(e);
@ -520,7 +467,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
abortingThread.start();
try {
conn.open(route, context, params);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
Assert.fail("expected SocketException");
} catch(SocketException expected) {}
@ -532,10 +479,10 @@ public class TestPoolingConnManager extends LocalServerTestBase {
Assert.assertEquals(0, localServer.getAcceptedConnectionCount());
// the connection is expected to be released back to the manager
ManagedClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
HttpClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
Assert.assertFalse("connection should have been closed", conn2.isOpen());
mgr.releaseConnection(conn2, -1, null);
mgr.releaseConnection(conn2, null, -1, null);
mgr.shutdown();
}
@ -548,7 +495,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
SchemeRegistry registry = new SchemeRegistry();
registry.register(scheme);
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager(registry);
final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(registry);
mgr.setMaxTotal(1);
HttpHost target = getServerHttp();
@ -556,14 +503,15 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
final ManagedClientConnection conn = getConnection(mgr, route);
final HttpClientConnection conn = getConnection(mgr, route);
final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
Thread abortingThread = new Thread(new Runnable() {
public void run() {
try {
stallingSocketFactory.waitForState();
conn.abortConnection();
conn.shutdown();
mgr.releaseConnection(conn, null, -1, null);
connectLatch.countDown();
} catch (Throwable e) {
throwRef.set(e);
@ -573,7 +521,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
abortingThread.start();
try {
conn.open(route, context, params);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
Assert.fail("expected exception");
} catch(IOException expected) {
Assert.assertEquals("Connection already shutdown", expected.getMessage());
@ -587,10 +535,10 @@ public class TestPoolingConnManager extends LocalServerTestBase {
Assert.assertEquals(0, localServer.getAcceptedConnectionCount());
// the connection is expected to be released back to the manager
ManagedClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
HttpClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
Assert.assertFalse("connection should have been closed", conn2.isOpen());
mgr.releaseConnection(conn2, -1, null);
mgr.releaseConnection(conn2, null, -1, null);
mgr.shutdown();
}
@ -603,7 +551,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
SchemeRegistry registry = new SchemeRegistry();
registry.register(scheme);
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager(registry);
final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(registry);
mgr.setMaxTotal(1);
HttpHost target = getServerHttp();
@ -611,14 +559,15 @@ public class TestPoolingConnManager extends LocalServerTestBase {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
final ManagedClientConnection conn = getConnection(mgr, route);
final HttpClientConnection conn = getConnection(mgr, route);
final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
Thread abortingThread = new Thread(new Runnable() {
public void run() {
try {
stallingSocketFactory.waitForState();
conn.abortConnection();
conn.shutdown();
mgr.releaseConnection(conn, null, -1, null);
connectLatch.countDown();
} catch (Throwable e) {
throwRef.set(e);
@ -628,7 +577,7 @@ public class TestPoolingConnManager extends LocalServerTestBase {
abortingThread.start();
try {
conn.open(route, context, params);
mgr.connect(conn, route.getTargetHost(), route.getLocalAddress(), context, params);
Assert.fail("expected SocketException");
} catch(SocketException expected) {}
@ -647,79 +596,15 @@ public class TestPoolingConnManager extends LocalServerTestBase {
Assert.assertEquals(1, localServer.getAcceptedConnectionCount());
// the connection is expected to be released back to the manager
ManagedClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
HttpClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
Assert.assertFalse("connection should have been closed", conn2.isOpen());
mgr.releaseConnection(conn2, -1, null);
mgr.releaseConnection(conn2, null, -1, null);
mgr.shutdown();
}
@Test
public void testAbortAfterOperatorOpen() throws Exception {
final CountDownLatch connectLatch = new CountDownLatch(1);
final AtomicReference<StallingOperator> operatorRef = new AtomicReference<StallingOperator>();
static class LatchSupport {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager() {
@Override
protected ClientConnectionOperator createConnectionOperator(
SchemeRegistry schreg) {
operatorRef.set(new StallingOperator(connectLatch, WaitPolicy.AFTER_OPEN, super.createConnectionOperator(schreg)));
return operatorRef.get();
}
};
mgr.setMaxTotal(1);
Assert.assertNotNull(operatorRef.get());
HttpHost target = getServerHttp();
HttpRoute route = new HttpRoute(target, null, false);
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
final ManagedClientConnection conn = getConnection(mgr, route);
final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
Thread abortingThread = new Thread(new Runnable() {
public void run() {
try {
operatorRef.get().waitForState();
conn.abortConnection();
connectLatch.countDown();
} catch (Throwable e) {
throwRef.set(e);
}
}
});
abortingThread.start();
try {
conn.open(route, context, params);
Assert.fail("expected exception");
} catch(IOException iox) {
}
abortingThread.join(5000);
if(throwRef.get() != null)
throw new RuntimeException(throwRef.get());
Assert.assertFalse(conn.isOpen());
// Give the server a bit of time to accept the connection, but
// ensure that it can accept it.
for(int i = 0; i < 10; i++) {
if(localServer.getAcceptedConnectionCount() == 1)
break;
Thread.sleep(100);
}
Assert.assertEquals(1, localServer.getAcceptedConnectionCount());
// the connection is expected to be released back to the manager
ManagedClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
Assert.assertFalse("connection should have been closed", conn2.isOpen());
mgr.releaseConnection(conn2, -1, null);
mgr.shutdown();
}
private static class LatchSupport {
private final CountDownLatch continueLatch;
private final CountDownLatch waitLatch = new CountDownLatch(1);
protected final WaitPolicy waitPolicy;
@ -745,34 +630,6 @@ public class TestPoolingConnManager extends LocalServerTestBase {
}
}
private static class StallingOperator extends LatchSupport implements ClientConnectionOperator {
private final ClientConnectionOperator delegate;
public StallingOperator(CountDownLatch continueLatch,
WaitPolicy waitPolicy, ClientConnectionOperator delegate) {
super(continueLatch, waitPolicy);
this.delegate = delegate;
}
public OperatedClientConnection createConnection() {
return delegate.createConnection();
}
public void openConnection(OperatedClientConnection conn,
HttpHost target, InetAddress local, HttpContext context,
HttpParams params) throws IOException {
delegate.openConnection(conn, target, local, context, params);
if(waitPolicy == WaitPolicy.AFTER_OPEN)
latch();
}
public void updateSecureConnection(OperatedClientConnection conn,
HttpHost target, HttpContext context, HttpParams params)
throws IOException {
delegate.updateSecureConnection(conn, target, context, params);
}
}
private static class StallingSocketFactory extends LatchSupport implements SchemeSocketFactory {
private final SchemeSocketFactory delegate;

View File

@ -53,7 +53,7 @@ import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.util.EntityUtils;
@ -181,7 +181,7 @@ public class TestContentCodings extends IntegrationTestBase {
*/
int clients = 100;
PoolingClientConnectionManager cm = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(clients);
this.httpclient = new HttpClientBuilder().setConnectionManager(cm).build();

View File

@ -25,7 +25,7 @@
*
*/
package org.apache.http.impl.conn;
package org.apache.http.impl.client.integration;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
@ -36,8 +36,9 @@ import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.localserver.LocalServerTestBase;
import org.apache.http.localserver.LocalTestServer;
import org.apache.http.util.EntityUtils;
@ -55,7 +56,7 @@ public class TestIdleConnectionEviction extends LocalServerTestBase {
@Test
public void testIdleConnectionEviction() throws Exception {
PoolingClientConnectionManager cm = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setDefaultMaxPerRoute(10);
cm.setMaxTotal(50);
@ -131,10 +132,10 @@ public class TestIdleConnectionEviction extends LocalServerTestBase {
public static class IdleConnectionMonitor extends Thread {
private final ClientConnectionManager cm;
private final HttpClientConnectionManager cm;
private volatile boolean shutdown;
public IdleConnectionMonitor(final ClientConnectionManager cm) {
public IdleConnectionMonitor(final HttpClientConnectionManager cm) {
super();
this.cm = cm;
setDaemon(true);

View File

@ -27,6 +27,7 @@ package org.apache.http.impl.client.integration;
import java.io.IOException;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
@ -35,10 +36,9 @@ import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
@ -91,14 +91,14 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 10);
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(workerCount);
mgr.setDefaultMaxPerRoute(workerCount);
UserTokenHandler userTokenHandler = new UserTokenHandler() {
public Object getUserToken(final HttpContext context) {
Integer id = (Integer) context.getAttribute("user");
String id = (String) context.getAttribute("user");
return id;
}
@ -113,9 +113,10 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
HttpWorker[] workers = new HttpWorker[workerCount];
for (int i = 0; i < contexts.length; i++) {
HttpContext context = new BasicHttpContext();
context.setAttribute("user", Integer.valueOf(i));
contexts[i] = context;
workers[i] = new HttpWorker(context, requestCount, target, this.httpclient);
workers[i] = new HttpWorker(
"user" + i,
context, requestCount, target, this.httpclient);
}
for (int i = 0; i < workers.length; i++) {
@ -134,12 +135,12 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
for (int i = 0; i < contexts.length; i++) {
HttpContext context = contexts[i];
Integer id = (Integer) context.getAttribute("user");
String uid = (String) context.getAttribute("user");
for (int r = 0; r < requestCount; r++) {
Integer state = (Integer) context.getAttribute("r" + r);
String state = (String) context.getAttribute("r" + r);
Assert.assertNotNull(state);
Assert.assertEquals(id, state);
Assert.assertEquals(uid, state);
}
}
@ -147,6 +148,7 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
static class HttpWorker extends Thread {
private final String uid;
private final HttpContext context;
private final int requestCount;
private final HttpHost target;
@ -156,11 +158,13 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
private volatile int count;
public HttpWorker(
final String uid,
final HttpContext context,
int requestCount,
final HttpHost target,
final HttpClient httpclient) {
super();
this.uid = uid;
this.context = context;
this.requestCount = requestCount;
this.target = target;
@ -179,6 +183,7 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
@Override
public void run() {
try {
this.context.setAttribute("user", this.uid);
for (int r = 0; r < this.requestCount; r++) {
HttpGet httpget = new HttpGet("/");
HttpResponse response = this.httpclient.execute(
@ -187,11 +192,15 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
this.context);
this.count++;
ManagedClientConnection conn = (ManagedClientConnection) this.context.getAttribute(
HttpClientConnection conn = (HttpClientConnection) this.context.getAttribute(
ExecutionContext.HTTP_CONNECTION);
this.context.setAttribute("r" + r, conn.getState());
HttpContext connContext = (HttpContext) conn;
String connuid = (String) connContext.getAttribute("user");
if (connuid == null) {
connContext.setAttribute("user", this.uid);
connuid = this.uid;
}
this.context.setAttribute("r" + r, connuid);
EntityUtils.consume(response.getEntity());
}
@ -214,7 +223,7 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
this.localServer.register("*", new SimpleService());
// We build a client with 2 max active // connections, and 2 max per route.
PoolingClientConnectionManager connMngr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager connMngr = new PoolingHttpClientConnectionManager();
connMngr.setMaxTotal(maxConn);
connMngr.setDefaultMaxPerRoute(maxConn);

View File

@ -1,120 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.ImmutableHttpProcessor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.util.EntityUtils;
class ExecReqThread extends Thread {
private final HttpRequest request;
private final HttpRoute route;
private final ClientConnectionManager connman;
private final long timeout;
private volatile Exception exception;
private volatile HttpResponse response;
private volatile byte[] response_data;
public ExecReqThread(
HttpRequest request,
HttpRoute route,
ClientConnectionManager mgr,
long timeout) {
super();
this.request = request;
this.route = route;
this.connman = mgr;
this.timeout = timeout;
}
public Exception getException() {
return this.exception;
}
public HttpResponse getResponse() {
return this.response;
}
public byte[] getResponseData() {
return this.response_data;
}
@Override
public void run() {
try {
HttpProcessor processor = new ImmutableHttpProcessor(
new HttpRequestInterceptor[] { new RequestContent(), new RequestConnControl() });
HttpRequestExecutor executor = new HttpRequestExecutor();
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
ClientConnectionRequest connRequest = this.connman.requestConnection(this.route, null);
ManagedClientConnection conn = connRequest.getConnection(this.timeout, TimeUnit.MILLISECONDS);
try {
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, this.route.getTargetHost());
context.setAttribute(ClientContext.ROUTE, this.route);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
conn.open(this.route, context, params);
executor.preProcess(this.request, processor, context);
this.response = executor.execute(this.request, conn, context);
if (this.response.getEntity() != null) {
this.response_data = EntityUtils.toByteArray(this.response.getEntity());
}
} finally {
this.connman.releaseConnection(conn, -1, null);
}
} catch (Exception ex) {
this.exception = ex;
}
}
}

View File

@ -1,228 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.localserver.LocalServerTestBase;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.ImmutableHttpProcessor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.util.EntityUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class TestBasicConnManager extends LocalServerTestBase {
@Before
public void setup() throws Exception {
startServer();
}
/**
* Tests that SCM can still connect to the same host after
* a connection was aborted.
*/
@Test
public void testOpenAfterAbort() throws Exception {
BasicClientConnectionManager mgr = new BasicClientConnectionManager();
HttpHost target = getServerHttp();
HttpRoute route = new HttpRoute(target, null, false);
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
ManagedClientConnection conn = mgr.getConnection(route, null);
conn.abortConnection();
conn = mgr.getConnection(route, null);
Assert.assertFalse("connection should have been closed", conn.isOpen());
conn.open(route, context, params);
mgr.releaseConnection(conn, -1, null);
mgr.shutdown();
}
/**
* Tests releasing with time limits.
*/
@Test
public void testReleaseConnectionWithTimeLimits() throws Exception {
BasicClientConnectionManager mgr = new BasicClientConnectionManager();
HttpHost target = getServerHttp();
HttpRoute route = new HttpRoute(target, null, false);
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
int rsplen = 8;
String uri = "/random/" + rsplen;
HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
ManagedClientConnection conn = mgr.getConnection(route, null);
conn.open(route, context, params);
// a new context is created for each test case, no need to reset
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
HttpProcessor httpProcessor = new ImmutableHttpProcessor(
new HttpRequestInterceptor[] { new RequestContent(), new RequestConnControl() });
HttpRequestExecutor exec = new HttpRequestExecutor();
exec.preProcess(request, httpProcessor, context);
HttpResponse response = exec.execute(request, conn, context);
Assert.assertEquals("wrong status in first response",
HttpStatus.SC_OK,
response.getStatusLine().getStatusCode());
byte[] data = EntityUtils.toByteArray(response.getEntity());
Assert.assertEquals("wrong length of first response entity",
rsplen, data.length);
// ignore data, but it must be read
// release connection without marking for re-use
// expect the next connection obtained to be closed
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
conn = mgr.getConnection(route, null);
Assert.assertFalse("connection should have been closed", conn.isOpen());
// repeat the communication, no need to prepare the request again
conn.open(route, context, params);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
response = exec.execute(request, conn, context);
Assert.assertEquals("wrong status in second response",
HttpStatus.SC_OK,
response.getStatusLine().getStatusCode());
data = EntityUtils.toByteArray(response.getEntity());
Assert.assertEquals("wrong length of second response entity",
rsplen, data.length);
// ignore data, but it must be read
// release connection after marking it for re-use
// expect the next connection obtained to be open
conn.markReusable();
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
conn = mgr.getConnection(route, null);
Assert.assertTrue("connection should have been open", conn.isOpen());
// repeat the communication, no need to prepare the request again
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
response = exec.execute(request, conn, context);
Assert.assertEquals("wrong status in third response",
HttpStatus.SC_OK,
response.getStatusLine().getStatusCode());
data = EntityUtils.toByteArray(response.getEntity());
Assert.assertEquals("wrong length of third response entity",
rsplen, data.length);
// ignore data, but it must be read
conn.markReusable();
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
Thread.sleep(150);
conn = mgr.getConnection(route, null);
Assert.assertTrue("connection should have been closed", !conn.isOpen());
// repeat the communication, no need to prepare the request again
conn.open(route, context, params);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
response = exec.execute(request, conn, context);
Assert.assertEquals("wrong status in third response",
HttpStatus.SC_OK,
response.getStatusLine().getStatusCode());
data = EntityUtils.toByteArray(response.getEntity());
Assert.assertEquals("wrong length of fourth response entity",
rsplen, data.length);
// ignore data, but it must be read
mgr.shutdown();
}
@Test
public void testCloseExpiredConnections() throws Exception {
BasicClientConnectionManager mgr = new BasicClientConnectionManager();
HttpHost target = getServerHttp();
HttpRoute route = new HttpRoute(target, null, false);
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
ManagedClientConnection conn = mgr.getConnection(route, null);
conn.open(route, context, params);
conn.markReusable();
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
mgr.closeExpiredConnections();
conn = mgr.getConnection(route, null);
Assert.assertTrue(conn.isOpen());
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
Thread.sleep(150);
mgr.closeExpiredConnections();
conn = mgr.getConnection(route, null);
Assert.assertFalse(conn.isOpen());
mgr.shutdown();
}
@Test(expected=IllegalStateException.class)
public void testAlreadyLeased() throws Exception {
BasicClientConnectionManager mgr = new BasicClientConnectionManager();
HttpHost target = getServerHttp();
HttpRoute route = new HttpRoute(target, null, false);
ManagedClientConnection conn = mgr.getConnection(route, null);
mgr.releaseConnection(conn, 100, TimeUnit.MILLISECONDS);
mgr.getConnection(route, null);
mgr.getConnection(route, null);
}
}

View File

@ -0,0 +1,308 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpHost;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.params.HttpParams;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
public class TestBasicHttpClientConnectionManager {
private DefaultClientConnection conn;
private HttpConnectionFactory<DefaultClientConnection> connFactory;
private Socket socket;
private SchemeSocketFactory plainSocketFactory;
private SchemeRegistry schemeRegistry;
private DnsResolver dnsResolver;
private BasicHttpClientConnectionManager mgr;
@SuppressWarnings("unchecked")
@Before
public void setup() throws Exception {
conn = Mockito.mock(DefaultClientConnection.class);
connFactory = Mockito.mock(HttpConnectionFactory.class);
Mockito.when(connFactory.create()).thenReturn(conn);
socket = Mockito.mock(Socket.class);
plainSocketFactory = Mockito.mock(SchemeSocketFactory.class);
Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpParams>any())).thenReturn(socket);
Scheme http = new Scheme("http", 80, plainSocketFactory);
schemeRegistry = new SchemeRegistry();
schemeRegistry.register(http);
dnsResolver = Mockito.mock(DnsResolver.class);
mgr = new BasicHttpClientConnectionManager(schemeRegistry, dnsResolver, connFactory);
}
@Test
public void testLeaseReleaseNonReusable() throws Exception {
HttpHost target = new HttpHost("localhost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Assert.assertFalse(conn1.isOpen());
mgr.releaseConnection(conn1, null, 100, TimeUnit.MILLISECONDS);
Assert.assertNull(mgr.getRoute());
Assert.assertNull(mgr.getState());
ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn2);
Assert.assertFalse(conn2.isOpen());
Mockito.verify(connFactory, Mockito.times(2)).create();
}
@Test
public void testLeaseReleaseReusable() throws Exception {
HttpHost target = new HttpHost("somehost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Mockito.verify(connFactory, Mockito.times(1)).create();
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
mgr.releaseConnection(conn1, null, 10000, TimeUnit.MILLISECONDS);
Assert.assertEquals(route, mgr.getRoute());
Assert.assertEquals(null, mgr.getState());
ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn2);
Assert.assertTrue(conn2.isOpen());
Mockito.verify(connFactory, Mockito.times(1)).create();
}
@Test
public void testLeaseReleaseReusableWithState() throws Exception {
HttpHost target = new HttpHost("somehost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, "some state");
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Mockito.verify(connFactory, Mockito.times(1)).create();
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
mgr.releaseConnection(conn1, "some other state", 10000, TimeUnit.MILLISECONDS);
Assert.assertEquals(route, mgr.getRoute());
Assert.assertEquals("some other state", mgr.getState());
ConnectionRequest connRequest2 = mgr.requestConnection(route, "some other state");
HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn2);
Assert.assertTrue(conn2.isOpen());
Mockito.verify(connFactory, Mockito.times(1)).create();
}
@Test
public void testLeaseDifferentRoute() throws Exception {
HttpHost target1 = new HttpHost("somehost");
HttpRoute route1 = new HttpRoute(target1);
ConnectionRequest connRequest1 = mgr.requestConnection(route1, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Mockito.verify(connFactory, Mockito.times(1)).create();
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
Assert.assertEquals(route1, mgr.getRoute());
Assert.assertEquals(null, mgr.getState());
HttpHost target2 = new HttpHost("otherhost");
HttpRoute route2 = new HttpRoute(target2);
ConnectionRequest connRequest2 = mgr.requestConnection(route2, null);
HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn2);
Assert.assertFalse(conn2.isOpen());
Mockito.verify(conn).close();
Mockito.verify(connFactory, Mockito.times(2)).create();
}
@Test
public void testLeaseExpired() throws Exception {
HttpHost target = new HttpHost("somehost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Mockito.verify(connFactory, Mockito.times(1)).create();
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
mgr.releaseConnection(conn1, null, 10, TimeUnit.MILLISECONDS);
Assert.assertEquals(route, mgr.getRoute());
Assert.assertEquals(null, mgr.getState());
Thread.sleep(50);
ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn2);
Assert.assertFalse(conn2.isOpen());
Mockito.verify(conn).close();
Mockito.verify(connFactory, Mockito.times(2)).create();
}
@Test(expected=IllegalArgumentException.class)
public void testLeaseInvalidArg() throws Exception {
mgr.requestConnection(null, null);
}
@Test(expected=IllegalArgumentException.class)
public void testReleaseInvalidArg() throws Exception {
mgr.releaseConnection(null, null, 0, TimeUnit.MILLISECONDS);
}
@Test(expected=IllegalArgumentException.class)
public void testReleaseAnotherConnection() throws Exception {
HttpClientConnection wrongCon = Mockito.mock(HttpClientConnection.class);
mgr.releaseConnection(wrongCon, null, 0, TimeUnit.MILLISECONDS);
}
@Test
public void testShutdown() throws Exception {
HttpHost target = new HttpHost("somehost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Mockito.verify(connFactory, Mockito.times(1)).create();
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
mgr.shutdown();
Mockito.verify(conn, Mockito.times(1)).shutdown();
try {
ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
connRequest2.get(0, TimeUnit.MILLISECONDS);
Assert.fail("IllegalStateException expected");
} catch (IllegalStateException ex) {
}
}
@Test
public void testCloseExpired() throws Exception {
HttpHost target = new HttpHost("somehost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Mockito.verify(connFactory, Mockito.times(1)).create();
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
mgr.releaseConnection(conn1, null, 10, TimeUnit.MILLISECONDS);
Assert.assertEquals(route, mgr.getRoute());
Assert.assertEquals(null, mgr.getState());
Thread.sleep(50);
mgr.closeExpiredConnections();
Mockito.verify(conn).close();
}
@Test
public void testCloseIdle() throws Exception {
HttpHost target = new HttpHost("somehost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Mockito.verify(connFactory, Mockito.times(1)).create();
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
Assert.assertEquals(route, mgr.getRoute());
Assert.assertEquals(null, mgr.getState());
Thread.sleep(100);
mgr.closeIdleConnections(50, TimeUnit.MILLISECONDS);
Mockito.verify(conn).close();
}
@Test(expected=IllegalStateException.class)
public void testAlreadyLeased() throws Exception {
HttpHost target = new HttpHost("somehost");
HttpRoute route = new HttpRoute(target);
ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
mgr.releaseConnection(conn1, null, 100, TimeUnit.MILLISECONDS);
mgr.getConnection(route, null);
mgr.getConnection(route, null);
}
}

View File

@ -37,6 +37,7 @@ import org.apache.http.conn.DnsResolver;
import org.junit.Assert;
import org.junit.Test;
@Deprecated
public class TestDefaultClientConnectOperator {
@Test

View File

@ -0,0 +1,194 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.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.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.params.HttpParams;
import org.apache.http.pool.ConnPool;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
public class TestHttpClientConnectionManagerBase {
private DefaultClientConnection conn;
private Socket socket;
private SchemeSocketFactory plainSocketFactory;
private SchemeRegistry schemeRegistry;
private DnsResolver dnsResolver;
private Future<CPoolEntry> future;
private ConnPool<HttpRoute, CPoolEntry> pool;
private HttpClientConnectionManagerBase mgr;
@SuppressWarnings("unchecked")
@Before
public void setup() throws Exception {
conn = Mockito.mock(DefaultClientConnection.class);
socket = Mockito.mock(Socket.class);
plainSocketFactory = Mockito.mock(SchemeSocketFactory.class);
Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpParams>any())).thenReturn(socket);
dnsResolver = Mockito.mock(DnsResolver.class);
Scheme http = new Scheme("http", 80, plainSocketFactory);
schemeRegistry = new SchemeRegistry();
schemeRegistry.register(http);
pool = Mockito.mock(ConnPool.class);
future = Mockito.mock(Future.class);
mgr = new HttpClientConnectionManagerBase(pool, schemeRegistry, 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(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(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(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(false);
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
Mockito.when(conn.isOpen()).thenReturn(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(false);
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
Mockito.when(conn.isOpen()).thenReturn(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));
}
}

View File

@ -0,0 +1,179 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.apache.http.HttpHost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpInetSocketAddress;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeLayeredSocketFactory;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
public class TestHttpClientConnectionOperator {
private DefaultClientConnection conn;
private Socket socket;
private SchemeSocketFactory plainSocketFactory;
private SchemeLayeredSocketFactory sslSocketFactory;
private SchemeRegistry schemeRegistry;
private DnsResolver dnsResolver;
private HttpClientConnectionOperator connectionOperator;
@Before
public void setup() throws Exception {
conn = Mockito.mock(DefaultClientConnection.class);
socket = Mockito.mock(Socket.class);
plainSocketFactory = Mockito.mock(SchemeSocketFactory.class);
sslSocketFactory = Mockito.mock(SchemeLayeredSocketFactory.class);
Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpParams>any())).thenReturn(socket);
Mockito.when(sslSocketFactory.createSocket(Mockito.<HttpParams>any())).thenReturn(socket);
dnsResolver = Mockito.mock(DnsResolver.class);
Scheme http = new Scheme("http", 80, plainSocketFactory);
Scheme https = new Scheme("https", 443, sslSocketFactory);
schemeRegistry = new SchemeRegistry();
schemeRegistry.register(http);
schemeRegistry.register(https);
connectionOperator = new HttpClientConnectionOperator(schemeRegistry, dnsResolver);
}
@Test
public void testConnect() throws Exception {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
HttpHost host = new HttpHost("somehost");
InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
InetAddress ip1 = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
InetAddress ip2 = InetAddress.getByAddress(new byte[] {127, 0, 0, 2});
Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
Mockito.when(plainSocketFactory.connectSocket(
Mockito.<Socket>any(),
Mockito.<InetSocketAddress>any(),
Mockito.<InetSocketAddress>any(),
Mockito.<HttpParams>any())).thenReturn(socket);
connectionOperator.connect(conn, host, local, context, params);
Mockito.verify(plainSocketFactory).connectSocket(socket,
new InetSocketAddress(ip1, 80),
new InetSocketAddress(local, 0), params);
Mockito.verify(conn).opening(socket, host);
Mockito.verify(conn).openCompleted(false, params);
}
@Test(expected=ConnectTimeoutException.class)
public void testConnectFailure() throws Exception {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
HttpHost host = new HttpHost("somehost");
InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
Mockito.when(plainSocketFactory.connectSocket(
Mockito.<Socket>any(),
Mockito.<InetSocketAddress>any(),
Mockito.<InetSocketAddress>any(),
Mockito.<HttpParams>any())).thenThrow(new ConnectTimeoutException());
connectionOperator.connect(conn, host, local, context, params);
}
@Test
public void testConnectFailover() throws Exception {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
HttpHost host = new HttpHost("somehost");
InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
Mockito.when(plainSocketFactory.connectSocket(
Mockito.<Socket>any(),
Mockito.eq(new HttpInetSocketAddress(host, ip1, 80)),
Mockito.<InetSocketAddress>any(),
Mockito.<HttpParams>any())).thenThrow(new ConnectTimeoutException());
Mockito.when(plainSocketFactory.connectSocket(
Mockito.<Socket>any(),
Mockito.eq(new HttpInetSocketAddress(host, ip2, 80)),
Mockito.<InetSocketAddress>any(),
Mockito.<HttpParams>any())).thenReturn(socket);
connectionOperator.connect(conn, host, local, context, params);
Mockito.verify(plainSocketFactory).connectSocket(socket,
new HttpInetSocketAddress(host, ip2, 80),
new InetSocketAddress(local, 0), params);
Mockito.verify(conn, Mockito.times(2)).opening(socket, host);
Mockito.verify(conn).openCompleted(false, params);
}
@Test
public void testUpgrade() throws Exception {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
HttpHost host = new HttpHost("somehost", -1, "https");
Mockito.when(sslSocketFactory.createLayeredSocket(
Mockito.<Socket>any(),
Mockito.eq("somehost"),
Mockito.eq(443),
Mockito.<HttpParams>any())).thenReturn(socket);
connectionOperator.upgrade(conn, host, context, params);
Mockito.verify(conn).update(socket, host, false, params);
}
@Test(expected=IllegalArgumentException.class)
public void testUpgradeNonLayeringScheme() throws Exception {
HttpContext context = new BasicHttpContext();
HttpParams params = new BasicHttpParams();
HttpHost host = new HttpHost("somehost", -1, "http");
connectionOperator.upgrade(conn, host, context, params);
}
}

View File

@ -29,76 +29,55 @@ package org.apache.http.impl.conn;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpHost;
import org.apache.http.HttpVersion;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.conn.tsccm.GetConnThread;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
/**
* Tests for <code>PoolingClientConnectionManager</code> that do not require a server to
* communicate with.
* {@link PoolingHttpClientConnectionManager} tests.
*/
public class TestPoolingConnManagerNoServer {
public class TestPoolingHttpClientConnectionManager {
private static ManagedClientConnection getConnection(
final ClientConnectionManager mgr,
private static HttpClientConnection getConnection(
final HttpClientConnectionManager mgr,
final HttpRoute route,
long timeout,
TimeUnit unit) throws ConnectionPoolTimeoutException, InterruptedException {
ClientConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.getConnection(timeout, unit);
ConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.get(timeout, unit);
}
private static ManagedClientConnection getConnection(
final ClientConnectionManager mgr,
private static HttpClientConnection getConnection(
final HttpClientConnectionManager mgr,
final HttpRoute route) throws ConnectionPoolTimeoutException, InterruptedException {
ClientConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.getConnection(0, null);
}
/**
* Instantiates default parameters.
*
* @return the default parameters
*/
public HttpParams createDefaultParams() {
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setUseExpectContinue(params, false);
return params;
ConnectionRequest connRequest = mgr.requestConnection(route, null);
return connRequest.get(0, null);
}
@Test(expected=IllegalArgumentException.class)
public void testIllegalConstructor() {
new PoolingClientConnectionManager(null);
new PoolingHttpClientConnectionManager(null);
}
@Test(expected=IllegalArgumentException.class)
public void testGetConnection()
throws InterruptedException, ConnectionPoolTimeoutException {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
HttpHost target = new HttpHost("www.test.invalid", 80, "http");
HttpRoute route = new HttpRoute(target, null, false);
ManagedClientConnection conn = getConnection(mgr, route);
HttpClientConnection conn = getConnection(mgr, route);
Assert.assertNotNull(conn);
Assert.assertNull(conn.getRoute());
Assert.assertFalse(conn.isOpen());
mgr.releaseConnection(conn, -1, null);
mgr.releaseConnection(conn, null, -1, null);
try {
getConnection(mgr, null);
@ -113,7 +92,7 @@ public class TestPoolingConnManagerNoServer {
public void testMaxConnTotal()
throws InterruptedException, ConnectionPoolTimeoutException {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(2);
mgr.setDefaultMaxPerRoute(1);
@ -122,9 +101,9 @@ public class TestPoolingConnManagerNoServer {
HttpHost target2 = new HttpHost("www.test2.invalid", 80, "http");
HttpRoute route2 = new HttpRoute(target2, null, false);
ManagedClientConnection conn1 = getConnection(mgr, route1);
HttpClientConnection conn1 = getConnection(mgr, route1);
Assert.assertNotNull(conn1);
ManagedClientConnection conn2 = getConnection(mgr, route2);
HttpClientConnection conn2 = getConnection(mgr, route2);
Assert.assertNotNull(conn2);
try {
@ -136,7 +115,7 @@ public class TestPoolingConnManagerNoServer {
}
// release one of the connections
mgr.releaseConnection(conn2, -1, null);
mgr.releaseConnection(conn2, null, -1, null);
conn2 = null;
// there should be a connection available now
@ -159,20 +138,20 @@ public class TestPoolingConnManagerNoServer {
HttpHost target3 = new HttpHost("www.test3.invalid", 80, "http");
HttpRoute route3 = new HttpRoute(target3, null, false);
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(100);
mgr.setDefaultMaxPerRoute(1);
mgr.setMaxPerRoute(route2, 2);
mgr.setMaxPerRoute(route3, 3);
// route 3, limit 3
ManagedClientConnection conn1 =
HttpClientConnection conn1 =
getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
ManagedClientConnection conn2 =
HttpClientConnection conn2 =
getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn2);
ManagedClientConnection conn3 =
HttpClientConnection conn3 =
getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn3);
try {
@ -203,18 +182,16 @@ public class TestPoolingConnManagerNoServer {
} catch (ConnectionPoolTimeoutException e) {
// expected
}
// check releaseConnection with invalid arguments
try {
mgr.releaseConnection(null, -1, null);
mgr.releaseConnection(null, null, -1, null);
Assert.fail("null connection adapter not detected");
} catch (IllegalArgumentException iax) {
// expected
}
try {
ManagedClientConnection conn = Mockito.mock(ManagedClientConnection.class);
mgr.releaseConnection(conn, -1, null);
HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
mgr.releaseConnection(conn, null, -1, null);
Assert.fail("foreign connection adapter not detected");
} catch (IllegalArgumentException iax) {
// expected
@ -226,7 +203,7 @@ public class TestPoolingConnManagerNoServer {
@Test
public void testReleaseConnection() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(3);
mgr.setDefaultMaxPerRoute(1);
@ -238,11 +215,11 @@ public class TestPoolingConnManagerNoServer {
HttpRoute route3 = new HttpRoute(target3, null, false);
// the first three allocations should pass
ManagedClientConnection conn1 =
HttpClientConnection conn1 =
getConnection(mgr, route1, 10L, TimeUnit.MILLISECONDS);
ManagedClientConnection conn2 =
HttpClientConnection conn2 =
getConnection(mgr, route2, 10L, TimeUnit.MILLISECONDS);
ManagedClientConnection conn3 =
HttpClientConnection conn3 =
getConnection(mgr, route3, 10L, TimeUnit.MILLISECONDS);
Assert.assertNotNull(conn1);
Assert.assertNotNull(conn2);
@ -270,7 +247,7 @@ public class TestPoolingConnManagerNoServer {
}
// now release one and check that exactly that one can be obtained then
mgr.releaseConnection(conn2, -1, null);
mgr.releaseConnection(conn2, null, -1, null);
conn2 = null;
try {
getConnection(mgr, route1, 10L, TimeUnit.MILLISECONDS);
@ -292,26 +269,17 @@ public class TestPoolingConnManagerNoServer {
}
@Test
public void testDeleteClosedConnections()
throws InterruptedException, ConnectionPoolTimeoutException {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
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);
ManagedClientConnection conn = getConnection(mgr, route);
HttpClientConnection conn = getConnection(mgr, route);
Assert.assertEquals(1, mgr.getTotalStats().getLeased());
Assert.assertEquals(1, mgr.getStats(route).getLeased());
conn.markReusable();
mgr.releaseConnection(conn, -1, null);
Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
Assert.assertEquals(1, mgr.getStats(route).getAvailable());
// this implicitly deletes them
mgr.closeIdleConnections(0L, TimeUnit.MILLISECONDS);
mgr.releaseConnection(conn, null, -1, null);
Assert.assertEquals(0, mgr.getTotalStats().getAvailable());
Assert.assertEquals(0, mgr.getStats(route).getAvailable());
@ -323,7 +291,7 @@ public class TestPoolingConnManagerNoServer {
public void testShutdown() throws Exception {
// 3.x: TestHttpConnectionManager.testShutdown
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(1);
mgr.setDefaultMaxPerRoute(1);
@ -333,7 +301,7 @@ public class TestPoolingConnManagerNoServer {
// get the only connection, then start an extra thread
// on shutdown, the extra thread should get an exception
ManagedClientConnection conn =
HttpClientConnection conn =
getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
GetConnThread gct = new GetConnThread(mgr, route, 0L); // no timeout
gct.start();
@ -345,7 +313,7 @@ public class TestPoolingConnManagerNoServer {
// 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, -1, null);
mgr.releaseConnection(conn, null, -1, null);
gct.join(10000);
@ -369,14 +337,14 @@ public class TestPoolingConnManagerNoServer {
public void testInterruptThread() throws Exception {
// 3.x: TestHttpConnectionManager.testWaitingThreadInterrupted
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
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
ManagedClientConnection conn =
HttpClientConnection conn =
getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
GetConnThread gct = new GetConnThread(mgr, route, 0L); // no timeout
gct.start();
@ -402,7 +370,7 @@ public class TestPoolingConnManagerNoServer {
// expected
}
mgr.releaseConnection(conn, -1, null);
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);
@ -414,7 +382,7 @@ public class TestPoolingConnManagerNoServer {
public void testReusePreference() throws Exception {
// 3.x: TestHttpConnectionManager.testHostReusePreference
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
mgr.setMaxTotal(1);
HttpHost target1 = new HttpHost("www.test1.invalid", 80, "http");
@ -423,7 +391,7 @@ public class TestPoolingConnManagerNoServer {
HttpRoute route2 = new HttpRoute(target2, null, false);
// get the only connection, then start two extra threads
ManagedClientConnection conn =
HttpClientConnection conn =
getConnection(mgr, route1, 1L, TimeUnit.MILLISECONDS);
GetConnThread gct1 = new GetConnThread(mgr, route1, 1000L);
GetConnThread gct2 = new GetConnThread(mgr, route2, 1000L);
@ -438,7 +406,7 @@ public class TestPoolingConnManagerNoServer {
// releasing the connection for route1 should deblock thread1
// the other thread gets a timeout
mgr.releaseConnection(conn, -1, null);
mgr.releaseConnection(conn, null, -1, null);
gct1.join(10000);
gct2.join(10000);
@ -453,20 +421,20 @@ public class TestPoolingConnManagerNoServer {
@Test
public void testAbortAfterRequestStarts() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
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
ManagedClientConnection conn = getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
ClientConnectionRequest request = mgr.requestConnection(route, null);
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.abortRequest();
request.cancel();
gct.join(10000);
Assert.assertNotNull("thread should have gotten an exception",
@ -483,7 +451,7 @@ public class TestPoolingConnManagerNoServer {
// expected
}
mgr.releaseConnection(conn, -1, null);
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);
@ -493,16 +461,16 @@ public class TestPoolingConnManagerNoServer {
@Test
public void testAbortBeforeRequestStarts() throws Exception {
PoolingClientConnectionManager mgr = new PoolingClientConnectionManager();
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
ManagedClientConnection conn = getConnection(mgr, route, 1L, TimeUnit.MILLISECONDS);
ClientConnectionRequest request = mgr.requestConnection(route, null);
request.abortRequest();
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();
@ -523,7 +491,7 @@ public class TestPoolingConnManagerNoServer {
// expected
}
mgr.releaseConnection(conn, -1, null);
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);
@ -531,4 +499,45 @@ public class TestPoolingConnManagerNoServer {
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;
}
}
}

View File

@ -1,93 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn.tsccm;
import java.util.Date;
import java.util.concurrent.locks.Lock;
/**
* Thread to await something.
*/
@Deprecated
public class AwaitThread extends Thread {
protected final WaitingThread wait_object;
protected final Lock wait_lock;
protected final Date wait_deadline;
protected volatile boolean waiting;
protected volatile Throwable exception;
/**
* Creates a new thread.
* When this thread is started, it will wait on the argument object.
*/
public AwaitThread(WaitingThread where, Lock lck, Date deadline) {
wait_object = where;
wait_lock = lck;
wait_deadline = deadline;
}
/**
* This method is executed when the thread is started.
*/
@Override
public void run() {
try {
wait_lock.lock();
waiting = true;
wait_object.await(wait_deadline);
} catch (Throwable dart) {
exception = dart;
} finally {
waiting = false;
wait_lock.unlock();
}
// terminate
}
public Throwable getException() {
return exception;
}
public boolean isWaiting() {
try {
wait_lock.lock();
return waiting;
} finally {
wait_lock.unlock();
}
}
}

View File

@ -1,99 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn.tsccm;
import java.util.concurrent.TimeUnit;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.ManagedClientConnection;
/**
* Thread to get a connection from a connection manager.
* Used by connection manager tests.
* Code based on HttpClient 3.x class <code>TestHttpConnectionManager</code>.
*/
public class GetConnThread extends Thread {
protected final HttpRoute conn_route;
protected final long conn_timeout;
protected final ClientConnectionRequest conn_request;
protected volatile ManagedClientConnection connection;
protected volatile Exception exception;
/**
* Creates a new thread for requesting a connection from the given manager.
*
* When this thread is started, it will try to obtain a connection.
* The timeout is in milliseconds.
*/
public GetConnThread(ClientConnectionManager mgr,
HttpRoute route, long timeout) {
this(mgr.requestConnection(route, null), route, timeout);
}
/**
* Creates a new for requesting a connection from the given request object.
*
* When this thread is started, it will try to obtain a connection.
* The timeout is in milliseconds.
*/
public GetConnThread(ClientConnectionRequest connectionRequest,
HttpRoute route, long timeout) {
conn_route = route;
conn_timeout = timeout;
conn_request = connectionRequest;
}
/**
* This method is executed when the thread is started.
*/
@Override
public void run() {
try {
connection = conn_request.getConnection
(conn_timeout, TimeUnit.MILLISECONDS);
} catch (Exception ex) {
exception = ex;
}
// terminate
}
public Throwable getException() {
return exception;
}
public ManagedClientConnection getConnection() {
return connection;
}
}

View File

@ -1,458 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn.tsccm;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpHost;
import org.apache.http.conn.ClientConnectionOperator;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.OperatedClientConnection;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.conn.DefaultClientConnectionOperator;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.localserver.LocalServerTestBase;
import org.apache.http.params.BasicHttpParams;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
@SuppressWarnings("deprecation")
@RunWith(MockitoJUnitRunner.class)
@Deprecated
public class TestConnPoolByRoute extends LocalServerTestBase {
private ConnPoolByRoute impl;
private HttpRoute route = new HttpRoute(new HttpHost("localhost"));
private HttpRoute route2 = new HttpRoute(new HttpHost("localhost:8080"));
@Mock private OperatedClientConnection mockConnection;
@Mock private OperatedClientConnection mockConnection2;
@Mock private ClientConnectionOperator mockOperator;
@Before
public void setUp() throws Exception {
startServer();
impl = new ConnPoolByRoute(
new DefaultClientConnectionOperator(SchemeRegistryFactory.createDefault()),
new ConnPerRouteBean(), 1, -1, TimeUnit.MILLISECONDS);
}
private void useMockOperator() {
Mockito.reset(mockOperator);
impl = new ConnPoolByRoute(
mockOperator, new ConnPerRouteBean(), 1, -1, TimeUnit.MILLISECONDS);
Mockito.when(mockOperator.createConnection()).thenReturn(mockConnection);
}
@Test
public void testStatelessConnections() throws Exception {
final HttpHost target = getServerHttp();
final HttpRoute route = new HttpRoute(target, null, false);
ClientConnectionOperator operator = new DefaultClientConnectionOperator(
SchemeRegistryFactory.createDefault());
ConnPerRouteBean connPerRoute = new ConnPerRouteBean(3);
ConnPoolByRoute connPool = new ConnPoolByRoute(operator, connPerRoute, 20);
try {
// Allocate max possible entries
PoolEntryRequest r1 = connPool.requestPoolEntry(route, null);
BasicPoolEntry e1 = r1.getPoolEntry(10, TimeUnit.SECONDS);
Assert.assertNotNull(e1);
PoolEntryRequest r2 = connPool.requestPoolEntry(route, null);
BasicPoolEntry e2 = r2.getPoolEntry(10, TimeUnit.SECONDS);
Assert.assertNotNull(e2);
PoolEntryRequest r3 = connPool.requestPoolEntry(route, null);
BasicPoolEntry e3 = r3.getPoolEntry(10, TimeUnit.SECONDS);
Assert.assertNotNull(e3);
// Attempt to allocate one more. Expected to fail
PoolEntryRequest r4 = connPool.requestPoolEntry(route, null);
try {
r4.getPoolEntry(250, TimeUnit.MICROSECONDS);
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
} catch (ConnectionPoolTimeoutException expected) {
}
// Free one
connPool.freeEntry(e3, true, -1, null);
// This time the request should succeed
PoolEntryRequest r5 = connPool.requestPoolEntry(route, null);
BasicPoolEntry e5 = r5.getPoolEntry(10, TimeUnit.SECONDS);
Assert.assertNotNull(e5);
} finally {
connPool.shutdown();
}
}
@Test
public void testStatefullConnections() throws Exception {
final HttpHost target = getServerHttp();
final HttpRoute route = new HttpRoute(target, null, false);
ClientConnectionOperator operator = new DefaultClientConnectionOperator(
SchemeRegistryFactory.createDefault());
ConnPerRouteBean connPerRoute = new ConnPerRouteBean(3);
ConnPoolByRoute connPool = new ConnPoolByRoute(operator, connPerRoute, 20);
try {
// Allocate max possible entries
PoolEntryRequest r1 = connPool.requestPoolEntry(route, null);
BasicPoolEntry e1 = r1.getPoolEntry(10, TimeUnit.SECONDS);
PoolEntryRequest r2 = connPool.requestPoolEntry(route, null);
BasicPoolEntry e2 = r2.getPoolEntry(10, TimeUnit.SECONDS);
PoolEntryRequest r3 = connPool.requestPoolEntry(route, null);
BasicPoolEntry e3 = r3.getPoolEntry(10, TimeUnit.SECONDS);
// Set states
e1.setState(Integer.valueOf(1));
e2.setState(Integer.valueOf(2));
e3.setState(Integer.valueOf(3));
// Release entries
connPool.freeEntry(e1, true, -1, null);
connPool.freeEntry(e2, true, -1, null);
connPool.freeEntry(e3, true, -1, null);
// Request statefull entries
PoolEntryRequest r4 = connPool.requestPoolEntry(route, Integer.valueOf(2));
BasicPoolEntry e4 = r4.getPoolEntry(10, TimeUnit.SECONDS);
PoolEntryRequest r5 = connPool.requestPoolEntry(route, Integer.valueOf(3));
BasicPoolEntry e5 = r5.getPoolEntry(10, TimeUnit.SECONDS);
PoolEntryRequest r6 = connPool.requestPoolEntry(route, Integer.valueOf(1));
BasicPoolEntry e6 = r6.getPoolEntry(10, TimeUnit.SECONDS);
Assert.assertNotNull(e4.getState());
Assert.assertNotNull(e5.getState());
Assert.assertNotNull(e6.getState());
// Check whether we got the same objects
Assert.assertTrue(e4 == e2);
Assert.assertTrue(e5 == e3);
Assert.assertTrue(e6 == e1);
// Release entries again
connPool.freeEntry(e4, true, -1, null);
connPool.freeEntry(e5, true, -1, null);
connPool.freeEntry(e6, true, -1, null);
// Request an entry with a state not avaialable in the pool
PoolEntryRequest r7 = connPool.requestPoolEntry(route, Integer.valueOf(4));
BasicPoolEntry e7 = r7.getPoolEntry(10, TimeUnit.SECONDS);
// Make sure we got a closed connection and a stateless entry back
Assert.assertFalse(e7.getConnection().isOpen());
Assert.assertNull(e7.getState());
} finally {
connPool.shutdown();
}
}
@Test(expected=IllegalArgumentException.class)
public void nullOperatorIsNotAllowed() {
new ConnPoolByRoute(null, new ConnPerRouteBean(), 1, -1, TimeUnit.MILLISECONDS);
}
@Test(expected=IllegalArgumentException.class)
public void nullConnPerRouteIsNotAllowed() {
new ConnPoolByRoute(new DefaultClientConnectionOperator(
SchemeRegistryFactory.createDefault()),
null, 1, -1, TimeUnit.MILLISECONDS);
}
@Test
public void deprecatedConstructorIsStillSupported() {
new ConnPoolByRoute(new DefaultClientConnectionOperator(
SchemeRegistryFactory.createDefault()),
new BasicHttpParams());
}
@Test
public void emptyPoolHasNoConnections() {
assertEquals(0, impl.getConnectionsInPool());
}
@Test
public void poolHasOneConnectionAfterRequestingOne() throws Exception {
useMockOperator();
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
assertEquals(1, impl.getConnectionsInPool());
}
@Test
public void emptyPoolHasNoRouteSpecificConnections() {
assertEquals(0, impl.getConnectionsInPool(route));
}
@Test
public void routeSpecificPoolHasOneConnectionAfterRequestingOne() throws Exception {
useMockOperator();
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
assertEquals(1, impl.getConnectionsInPool(route));
}
@Test
public void abortingPoolEntryRequestEarlyDoesNotCreateConnection() {
PoolEntryRequest req = impl.requestPoolEntry(route, new Object());
req.abortRequest();
assertEquals(0, impl.getConnectionsInPool(route));
}
@Test(expected=IllegalStateException.class)
public void cannotAcquireConnectionIfPoolShutdown() throws Exception {
impl.shutdown();
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
}
@Test
public void multipleShutdownsAreOk() {
impl.shutdown();
impl.shutdown();
}
@Test
public void canAcquirePoolEntry() throws Exception {
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
}
@Test
public void canRetrieveMaxTotalConnections() {
int max = (new Random()).nextInt(10) + 2;
impl.setMaxTotalConnections(max);
assertEquals(max, impl.getMaxTotalConnections());
}
@Test
public void closesFreedConnectionsWhenShutdown() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.shutdown();
impl.freeEntry(entry, true, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Mockito.verify(mockConnection, Mockito.atLeastOnce()).close();
}
@Test
public void deleteClosedConnectionsReclaimsPoolSpace() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
assertFalse(impl.freeConnections.isEmpty());
Mockito.when(mockConnection.isOpen()).thenReturn(false);
impl.deleteClosedConnections();
assertTrue(impl.freeConnections.isEmpty());
assertEquals(0, impl.numConnections);
}
@Test
public void deleteClosedConnectionsDoesNotReclaimOpenConnections() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
assertFalse(impl.freeConnections.isEmpty());
Mockito.when(mockConnection.isOpen()).thenReturn(true);
impl.deleteClosedConnections();
assertFalse(impl.freeConnections.isEmpty());
assertEquals(1, impl.numConnections);
}
@Test
public void closeIdleConnectionsClosesThoseThatHaveTimedOut() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Thread.sleep(200L);
impl.closeIdleConnections(1, TimeUnit.MILLISECONDS);
Mockito.verify(mockConnection, Mockito.atLeastOnce()).close();
}
@Test
public void closeIdleConnectionsDoesNotCloseThoseThatHaveNotTimedOut() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
impl.closeIdleConnections(3, TimeUnit.SECONDS);
Mockito.verify(mockConnection, Mockito.never()).close();
}
@Test
public void closeExpiredConnectionsClosesExpiredOnes() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, 1, TimeUnit.MILLISECONDS);
Thread.sleep(200L);
impl.closeExpiredConnections();
Mockito.verify(mockConnection, Mockito.atLeastOnce()).close();
}
@Test
public void closeExpiredConnectionsDoesNotCloseUnexpiredOnes() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, 10, TimeUnit.SECONDS);
Thread.sleep(200L);
impl.closeExpiredConnections();
Mockito.verify(mockConnection, Mockito.never()).close();
}
@Test
public void closesNonReusableConnections() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, false, 0, TimeUnit.MILLISECONDS);
Mockito.verify(mockConnection, Mockito.atLeastOnce()).close();
}
@Test
public void handlesExceptionsWhenClosingConnections() throws Exception {
useMockOperator();
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
Mockito.doThrow(new IOException()).when(mockConnection).close();
impl.freeEntry(entry, false, 0, TimeUnit.MILLISECONDS);
}
@Test
public void wakesUpWaitingThreadsWhenEntryAvailable() throws Exception {
useMockOperator();
Mockito.when(mockOperator.createConnection()).thenReturn(mockConnection);
impl.setMaxTotalConnections(1);
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
final Flag f = new Flag(false);
Thread t = new Thread(new Runnable() {
public void run() {
try {
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
f.flag = true;
} catch (ConnectionPoolTimeoutException e) {
} catch (InterruptedException e) {
}
}
});
t.start();
Thread.sleep(100);
impl.freeEntry(entry, true, 1000, TimeUnit.MILLISECONDS);
Thread.sleep(100);
assertTrue(f.flag);
}
@Test
public void wakesUpWaitingThreadsOnOtherRoutesWhenEntryAvailable() throws Exception {
useMockOperator();
Mockito.when(mockOperator.createConnection()).thenReturn(mockConnection);
impl.setMaxTotalConnections(1);
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
final Flag f = new Flag(false);
Thread t = new Thread(new Runnable() {
public void run() {
try {
impl.requestPoolEntry(route2, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
f.flag = true;
} catch (ConnectionPoolTimeoutException e) {
} catch (InterruptedException e) {
}
}
});
t.start();
Thread.sleep(100);
impl.freeEntry(entry, true, 1000, TimeUnit.MILLISECONDS);
Thread.sleep(100);
assertTrue(f.flag);
}
@Test
public void doesNotRecycleExpiredConnections() throws Exception {
useMockOperator();
Mockito.when(mockOperator.createConnection()).thenReturn(mockConnection, mockConnection2);
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, 1, TimeUnit.MILLISECONDS);
Thread.sleep(200L);
BasicPoolEntry entry2 = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
assertNotSame(mockConnection, entry2.getConnection());
}
@Test
public void closesExpiredConnectionsWhenNotReusingThem() throws Exception {
useMockOperator();
Mockito.when(mockOperator.createConnection()).thenReturn(mockConnection, mockConnection2);
BasicPoolEntry entry = impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
impl.freeEntry(entry, true, 1, TimeUnit.MILLISECONDS);
Thread.sleep(200L);
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
Mockito.verify(mockConnection, Mockito.atLeastOnce()).close();
}
@Test
public void wakesUpWaitingThreadsOnShutdown() throws Exception {
useMockOperator();
Mockito.when(mockOperator.createConnection()).thenReturn(mockConnection);
Mockito.when(mockOperator.createConnection()).thenReturn(mockConnection);
impl.setMaxTotalConnections(1);
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
final Flag f = new Flag(false);
Thread t = new Thread(new Runnable() {
public void run() {
try {
impl.requestPoolEntry(route, new Object()).getPoolEntry(-1, TimeUnit.MILLISECONDS);
} catch (IllegalStateException expected) {
f.flag = true;
} catch (ConnectionPoolTimeoutException e) {
} catch (InterruptedException e) {
}
}
});
t.start();
Thread.sleep(1);
impl.shutdown();
Thread.sleep(1);
assertTrue(f.flag);
}
private static class Flag {
public boolean flag;
public Flag(boolean init) { flag = init; }
}
}

View File

@ -1,167 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn.tsccm;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import org.apache.http.HttpHost;
import org.apache.http.conn.ClientConnectionOperator;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.params.ConnPerRoute;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests for spurious wakeups in <code>WaitingThread</code>.
* Requires some wrapping code to get at the lock and condition,
* which is required to trigger a wakeup without actually
* satisfying the condition.
*
*/
@Deprecated
public class TestSpuriousWakeup {
public final static
HttpHost TARGET = new HttpHost("target.test.invalid");
public final static
HttpRoute ROUTE = new HttpRoute(TARGET);
/**
* An extended connection pool that gives access to some internals.
*/
private static class XConnPoolByRoute extends ConnPoolByRoute {
/** The last WaitingThread object created. */
protected WaitingThread newestWT;
public XConnPoolByRoute(
final ClientConnectionOperator operator,
final ConnPerRoute connPerRoute,
int maxTotalConnections) {
super(operator, connPerRoute, maxTotalConnections);
}
@Override
protected synchronized
WaitingThread newWaitingThread(Condition cond,
RouteSpecificPool rospl) {
WaitingThread wt = super.newWaitingThread(cond, rospl);
newestWT = wt;
return wt;
}
} // class XConnPoolByRoute
/**
* An extended TSCCM that uses XConnPoolByRoute.
*/
private static class XTSCCM extends ThreadSafeClientConnManager {
/** The extended connection pool. */
protected XConnPoolByRoute extendedCPBR;
public XTSCCM(SchemeRegistry schreg) {
super(schreg);
}
@Override
protected ConnPoolByRoute createConnectionPool(long connTTL, TimeUnit connTTLUnit) {
extendedCPBR = new XConnPoolByRoute(connOperator, connPerRoute, 20);
// no connection GC required
return extendedCPBR;
}
} // class XTSCCM
@Test
public void testSpuriousWakeup() throws Exception {
SchemeRegistry schreg = new SchemeRegistry();
SchemeSocketFactory sf = PlainSocketFactory.getSocketFactory();
schreg.register(new Scheme("http", 80, sf));
XTSCCM mgr = new XTSCCM(schreg);
try {
mgr.setMaxTotal(1);
mgr.setDefaultMaxPerRoute(1);
// take out the only connection
ClientConnectionRequest connRequest = mgr.requestConnection(ROUTE, null);
ManagedClientConnection conn = connRequest.getConnection(0, null);
Assert.assertNotNull(conn);
// send a thread waiting
GetConnThread gct = new GetConnThread(mgr, ROUTE, 0L);
gct.start();
Thread.sleep(100); // give extra thread time to block
Assert.assertEquals("thread not waiting",
Thread.State.WAITING, gct.getState());
// get access to the objects we need
Lock lck = mgr.extendedCPBR.getLock();
Condition cnd = mgr.extendedCPBR.newestWT.getCondition();
// Now trigger spurious wakeups. We'll do it several times
// in a loop, just to be sure the connection manager has a
// fair chance of misbehaving, and the gct to register it.
for (int i=0; i<3; i++) {
if (i > 0)
Thread.sleep(333); // don't go too fast
try {
lck.lock();
cnd.signalAll(); // this is the spurious wakeup
} finally {
lck.unlock();
}
// now give the waiting thread some time to register a wakeup
Thread.sleep(100);
Assert.assertEquals("thread no longer waiting, iteration " + i,
Thread.State.WAITING, gct.getState());
}
} finally {
// don't worry about releasing the connection, just shut down
mgr.shutdown();
}
}
}

View File

@ -1,172 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn.tsccm;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.http.HttpHost;
import org.apache.http.conn.params.ConnPerRoute;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.routing.HttpRoute;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests for <code>WaitingThread</code>.
*/
@Deprecated
public class TestWaitingThread {
public final static
HttpHost TARGET = new HttpHost("target.test.invalid");
@Test
public void testConstructor() {
try {
new WaitingThread(null, null);
Assert.fail("null condition not detected");
} catch (IllegalArgumentException iax) {
// expected
}
Lock lck = new ReentrantLock();
Condition cnd = lck.newCondition();
WaitingThread wt = new WaitingThread(cnd, null);
Assert.assertEquals("wrong condition", cnd, wt.getCondition());
Assert.assertNull ("pool from nowhere", wt.getPool());
Assert.assertNull ("thread from nowhere", wt.getThread());
HttpRoute route = new HttpRoute(TARGET);
ConnPerRoute connPerRoute = new ConnPerRouteBean(10);
RouteSpecificPool rospl = new RouteSpecificPool(route, connPerRoute);
wt = new WaitingThread(cnd, rospl);
Assert.assertEquals("wrong condition", cnd, wt.getCondition());
Assert.assertEquals("wrong pool", rospl, wt.getPool());
Assert.assertNull ("thread from nowhere", wt.getThread());
}
@Test
public void testAwaitWakeup() throws InterruptedException {
Lock lck = new ReentrantLock();
Condition cnd = lck.newCondition();
WaitingThread wt = new WaitingThread(cnd, null);
AwaitThread ath = new AwaitThread(wt, lck, null);
ath.start();
Thread.sleep(100); // give extra thread time to block
Assert.assertNull("thread caught exception", ath.getException());
Assert.assertTrue("thread not waiting", ath.isWaiting());
Assert.assertEquals("wrong thread", ath, wt.getThread());
Thread.sleep(500); // just for fun, let it wait for some time
// this may fail due to a spurious wakeup
Assert.assertTrue("thread not waiting, spurious wakeup?", ath.isWaiting());
try {
lck.lock();
wt.wakeup();
} finally {
lck.unlock();
}
ath.join(10000);
Assert.assertFalse("thread still waiting", ath.isWaiting());
Assert.assertNull("thread caught exception", ath.getException());
Assert.assertNull("thread still there", wt.getThread());
}
@Test
public void testInterrupt() throws InterruptedException {
Lock lck = new ReentrantLock();
Condition cnd = lck.newCondition();
WaitingThread wt = new WaitingThread(cnd, null);
AwaitThread ath = new AwaitThread(wt, lck, null);
ath.start();
Thread.sleep(100); // give extra thread time to block
Assert.assertNull("thread caught exception", ath.getException());
Assert.assertTrue("thread not waiting", ath.isWaiting());
Assert.assertEquals("wrong thread", ath, wt.getThread());
ath.interrupt();
Thread.sleep(100); // give extra thread time to wake up
Assert.assertFalse("thread still waiting", ath.isWaiting());
Assert.assertNotNull("thread didn't catch exception", ath.getException());
Assert.assertTrue("thread caught wrong exception",
ath.getException() instanceof InterruptedException);
Assert.assertNull("thread still there", wt.getThread());
}
@Test
public void testIllegal() throws InterruptedException {
Lock lck = new ReentrantLock();
Condition cnd = lck.newCondition();
WaitingThread wt = new WaitingThread(cnd, null);
try {
lck.lock();
wt.wakeup();
Assert.fail("missing waiter not detected");
} catch (IllegalStateException isx) {
// expected
} finally {
lck.unlock();
}
AwaitThread ath1 = new AwaitThread(wt, lck, null);
ath1.start();
Thread.sleep(100); // give extra thread time to block
Assert.assertNull("thread caught exception", ath1.getException());
Assert.assertTrue("thread not waiting", ath1.isWaiting());
Assert.assertEquals("wrong thread", ath1, wt.getThread());
AwaitThread ath2 = new AwaitThread(wt, lck, null);
ath2.start();
Thread.sleep(100); // give extra thread time to try to block
Assert.assertFalse("thread waiting", ath2.isWaiting());
Assert.assertNotNull("thread didn't catch exception", ath2.getException());
Assert.assertTrue("thread caught wrong exception",
ath2.getException() instanceof IllegalStateException);
// clean up by letting the threads terminate
ath1.interrupt();
ath2.interrupt();
}
}