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:
parent
84d4b9e2ac
commit
78856ca1b1
|
@ -1,3 +1,4 @@
|
|||
bin
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,8 @@ import org.apache.http.conn.DnsResolver;
|
|||
*/
|
||||
public class SystemDefaultDnsResolver implements DnsResolver {
|
||||
|
||||
public static final SystemDefaultDnsResolver INSTANCE = new SystemDefaultDnsResolver();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -37,6 +37,7 @@ import org.apache.http.conn.DnsResolver;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@Deprecated
|
||||
public class TestDefaultClientConnectOperator {
|
||||
|
||||
@Test
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue