connection manager, part 2 - example and a fix
git-svn-id: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpclient/trunk@498312 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b5a4cb74b0
commit
dff91540f3
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* $HeadURL$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.HttpHost;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.apache.http.message.BasicHttpRequest;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.params.HttpProtocolParams;
|
||||
import org.apache.http.impl.DefaultHttpParams;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.protocol.HttpExecutionContext;
|
||||
|
||||
import org.apache.http.conn.Scheme;
|
||||
import org.apache.http.conn.SocketFactory;
|
||||
import org.apache.http.conn.PlainSocketFactory;
|
||||
import org.apache.http.conn.HostConfiguration;
|
||||
import org.apache.http.conn.ManagedClientConnection;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.conn.impl.ThreadSafeClientConnManager;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* How to open a direct connection using
|
||||
* {@link ClientConnectionManager ClientConnectionManager}.
|
||||
* This exemplifies the <i>opening</i> of the connection only.
|
||||
* The subsequent message exchange in this example should not
|
||||
* be used as a template.
|
||||
*
|
||||
* @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
|
||||
*
|
||||
*
|
||||
* <!-- empty lines above to avoid 'svn diff' context problems -->
|
||||
* @version $Revision$ $Date$
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ManagerConnectDirect {
|
||||
|
||||
/**
|
||||
* The default parameters.
|
||||
* Instantiated in {@link #setup setup}.
|
||||
*/
|
||||
private static HttpParams defaultParameters = null;
|
||||
|
||||
|
||||
/**
|
||||
* Main entry point to this example.
|
||||
*
|
||||
* @param args ignored
|
||||
*/
|
||||
public final static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
final HttpHost target = new HttpHost("jakarta.apache.org", 80, "http");
|
||||
|
||||
setup(); // some general setup
|
||||
|
||||
// one operator can be used for many connections
|
||||
ClientConnectionManager clcm = createManager();
|
||||
|
||||
HttpRequest req = createRequest(target);
|
||||
HttpContext ctx = createContext();
|
||||
|
||||
System.out.println("preparing route to " + target);
|
||||
HostConfiguration route = new HostConfiguration(target, null, null);
|
||||
|
||||
System.out.println("requesting connection for " + route);
|
||||
ManagedClientConnection conn = clcm.getConnection(route);
|
||||
try {
|
||||
System.out.println("opening connection");
|
||||
conn.open(route, ctx, getParams());
|
||||
|
||||
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(getParams());
|
||||
|
||||
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("----------------------------------------");
|
||||
|
||||
System.out.println("closing connection");
|
||||
conn.close();
|
||||
|
||||
} finally {
|
||||
|
||||
if (conn.isOpen()) {
|
||||
System.out.println("shutting down connection");
|
||||
try {
|
||||
conn.shutdown();
|
||||
} catch (Exception x) {
|
||||
System.out.println("problem during shutdown");
|
||||
x.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("releasing connection");
|
||||
clcm.releaseConnection(conn);
|
||||
}
|
||||
|
||||
} // main
|
||||
|
||||
|
||||
private final static ClientConnectionManager createManager() {
|
||||
return new ThreadSafeClientConnManager(getParams());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs general setup.
|
||||
* This should be called only once.
|
||||
*/
|
||||
private final static void setup() {
|
||||
|
||||
// Register the "http" protocol scheme, it is required
|
||||
// by the default operator to look up socket factories.
|
||||
SocketFactory sf = PlainSocketFactory.getSocketFactory();
|
||||
Scheme.registerScheme("http", new Scheme("http", sf, 80));
|
||||
|
||||
// Prepare parameters.
|
||||
// Since this example doesn't use the full core framework,
|
||||
// only few parameters are actually required.
|
||||
HttpParams params = new DefaultHttpParams();
|
||||
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
|
||||
HttpProtocolParams.setUseExpectContinue(params, false);
|
||||
defaultParameters = params;
|
||||
|
||||
} // setup
|
||||
|
||||
|
||||
private final static HttpParams getParams() {
|
||||
return defaultParameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a request to execute in this example.
|
||||
* In a real application, request interceptors should be used
|
||||
* to add the required headers.
|
||||
*
|
||||
* @param target the target server for the request
|
||||
*
|
||||
* @return a request without an entity
|
||||
*/
|
||||
private final static HttpRequest createRequest(HttpHost target) {
|
||||
|
||||
HttpRequest req = new BasicHttpRequest
|
||||
("OPTIONS", "*", HttpVersion.HTTP_1_1);
|
||||
|
||||
req.addHeader("Host", target.getHostName());
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a context for executing a request.
|
||||
* Since this example doesn't really use the execution framework,
|
||||
* the context can be left empty.
|
||||
*
|
||||
* @return a new, empty context
|
||||
*/
|
||||
private final static HttpContext createContext() {
|
||||
return new HttpExecutionContext(null);
|
||||
}
|
||||
|
||||
} // class ManagerConnectDirect
|
||||
|
|
@ -293,6 +293,8 @@ public class ThreadSafeClientConnManager
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return entry;
|
||||
|
||||
} // doGetConnection
|
||||
|
@ -506,7 +508,7 @@ public class ThreadSafeClientConnManager
|
|||
(ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE.get(ref);
|
||||
if (source.connectionPool == connectionPool) {
|
||||
referenceIter.remove();
|
||||
Object entry = ref.get(); // class TrackingPoolEntry
|
||||
Object entry = ref.get(); // TrackingPoolEntry
|
||||
if (entry != null) {
|
||||
connectionsToClose.add(entry);
|
||||
}
|
||||
|
@ -679,8 +681,11 @@ public class ThreadSafeClientConnManager
|
|||
idleConnectionHandler.removeAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new pool entry for an operated connection.
|
||||
* This method assumes that the new connection will be handed
|
||||
* out immediately.
|
||||
*
|
||||
* @param route the route associated with the new entry
|
||||
* @param conn the underlying connection for the new entry
|
||||
|
@ -696,6 +701,7 @@ public class ThreadSafeClientConnManager
|
|||
LOG.debug("Allocating new connection, hostConfiguration=" + route);
|
||||
}
|
||||
TrackingPoolEntry entry = new TrackingPoolEntry(conn);
|
||||
entry.plannedRoute = route;
|
||||
numConnections++;
|
||||
hostPool.numConnections++;
|
||||
|
||||
|
@ -707,12 +713,15 @@ public class ThreadSafeClientConnManager
|
|||
|
||||
|
||||
/**
|
||||
* Handles cleaning up for a lost connection with the given config. Decrements any
|
||||
* connection counts and notifies waiting threads, if appropriate.
|
||||
* Handles cleaning up for a lost connection with the given config.
|
||||
* Decrements any connection counts and notifies waiting threads,
|
||||
* if appropriate.
|
||||
*
|
||||
* @param config the host configuration of the connection that was lost
|
||||
*/
|
||||
public synchronized void handleLostConnection(HostConfiguration config) {
|
||||
public synchronized
|
||||
void handleLostConnection(HostConfiguration config) {
|
||||
|
||||
HostConnectionPool hostPool = getHostPool(config);
|
||||
hostPool.numConnections--;
|
||||
if (hostPool.numConnections < 1)
|
||||
|
@ -723,26 +732,28 @@ public class ThreadSafeClientConnManager
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the pool (list) of connections available for the given hostConfig.
|
||||
* Get the pool (list) of connections available for the given route.
|
||||
*
|
||||
* @param hostConfiguration the configuraton for the connection pool
|
||||
* @return a pool (list) of connections available for the given config
|
||||
* @param route the configuraton for the connection pool
|
||||
* @return a pool (list) of connections available for the given route
|
||||
*/
|
||||
public synchronized HostConnectionPool getHostPool(HostConfiguration hostConfiguration) {
|
||||
public synchronized
|
||||
HostConnectionPool getHostPool(HostConfiguration route) {
|
||||
|
||||
// Look for a list of connections for the given config
|
||||
HostConnectionPool listConnections = (HostConnectionPool)
|
||||
mapHosts.get(hostConfiguration);
|
||||
HostConnectionPool listConnections =
|
||||
(HostConnectionPool) mapHosts.get(route);
|
||||
if (listConnections == null) {
|
||||
// First time for this config
|
||||
listConnections = new HostConnectionPool();
|
||||
listConnections.hostConfiguration = hostConfiguration;
|
||||
mapHosts.put(hostConfiguration, listConnections);
|
||||
listConnections.hostConfiguration = route;
|
||||
mapHosts.put(route, listConnections);
|
||||
}
|
||||
|
||||
|
||||
return listConnections;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If available, get a free connection for this host
|
||||
*
|
||||
|
@ -900,7 +911,7 @@ public class ThreadSafeClientConnManager
|
|||
*/
|
||||
private void freeConnection(TrackingPoolEntry entry) {
|
||||
|
||||
HostConfiguration route = entry.route;
|
||||
HostConfiguration route = entry.plannedRoute;
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Freeing connection, hostConfig=" + route);
|
||||
|
@ -917,7 +928,8 @@ public class ThreadSafeClientConnManager
|
|||
|
||||
HostConnectionPool hostPool = getHostPool(route);
|
||||
|
||||
// Put the connect back in the available list and notify a waiter
|
||||
// Put the connection back in the available list
|
||||
// and notify a waiter
|
||||
hostPool.freeConnections.add(entry);
|
||||
if (hostPool.numConnections == 0) {
|
||||
// for some reason this connection pool didn't already exist
|
||||
|
@ -927,8 +939,9 @@ public class ThreadSafeClientConnManager
|
|||
}
|
||||
|
||||
freeConnections.add(entry);
|
||||
// we can remove the reference to this connection as we have control over
|
||||
// it again. this also ensures that the connection manager can be GCed
|
||||
// We can remove the reference to this connection as we have
|
||||
// control over it again. This also ensures that the connection
|
||||
// manager can be GCed.
|
||||
removeReferenceToConnection(entry);
|
||||
if (numConnections == 0) {
|
||||
// for some reason this connection pool didn't already exist
|
||||
|
@ -1075,10 +1088,13 @@ public class ThreadSafeClientConnManager
|
|||
/** The underlying connection being pooled or used. */
|
||||
private OperatedClientConnection connection;
|
||||
|
||||
/** The host configuration part of the route. */
|
||||
/** The route for which this entry gets allocated. */
|
||||
private HostConfiguration plannedRoute;
|
||||
|
||||
/** The host configuration part of the tracked route. */
|
||||
private HostConfiguration route;
|
||||
|
||||
/** The tunnel created flag part of the route. */
|
||||
/** The tunnel created flag part of the tracked route. */
|
||||
private boolean tunnelled;
|
||||
|
||||
/** The connection manager. */
|
||||
|
|
Loading…
Reference in New Issue