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:
Roland Weber 2007-01-21 13:28:45 +00:00
parent b5a4cb74b0
commit dff91540f3
2 changed files with 245 additions and 19 deletions

View File

@ -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

View File

@ -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. */