📄 multithreadedhttpconnectionmanager.java
字号:
/* * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java,v 1.47 2004/12/21 11:27:55 olegk Exp $ * $Revision: 564906 $ * $Date: 2007-08-11 14:27:18 +0200 (Sat, 11 Aug 2007) $ * * ==================================================================== * * 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.commons.httpclient;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.ref.WeakReference;import java.net.InetAddress;import java.net.SocketException;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.Map;import java.util.WeakHashMap;import org.apache.commons.httpclient.params.HttpConnectionManagerParams;import org.apache.commons.httpclient.params.HttpConnectionParams;import org.apache.commons.httpclient.protocol.Protocol;import org.apache.commons.httpclient.util.IdleConnectionHandler;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;/** * Manages a set of HttpConnections for various HostConfigurations. * * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a> * @author Eric Johnson * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> * @author Carl A. Dunham * * @since 2.0 */public class MultiThreadedHttpConnectionManager implements HttpConnectionManager { // -------------------------------------------------------- Class Variables /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(MultiThreadedHttpConnectionManager.class); /** The default maximum number of connections allowed per host */ public static final int DEFAULT_MAX_HOST_CONNECTIONS = 2; // Per RFC 2616 sec 8.1.4 /** The default maximum number of connections allowed overall */ public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20; /** * A mapping from Reference to ConnectionSource. Used to reclaim resources when connections * are lost to the garbage collector. */ private static final Map REFERENCE_TO_CONNECTION_SOURCE = new HashMap(); /** * The reference queue used to track when HttpConnections are lost to the * garbage collector */ private static final ReferenceQueue REFERENCE_QUEUE = new ReferenceQueue(); /** * The thread responsible for handling lost connections. */ private static ReferenceQueueThread REFERENCE_QUEUE_THREAD; /** * Holds references to all active instances of this class. */ private static WeakHashMap ALL_CONNECTION_MANAGERS = new WeakHashMap(); // ---------------------------------------------------------- Class Methods /** * Shuts down and cleans up resources used by all instances of * MultiThreadedHttpConnectionManager. All static resources are released, all threads are * stopped, and {@link #shutdown()} is called on all live instances of * MultiThreadedHttpConnectionManager. * * @see #shutdown() */ public static void shutdownAll() { synchronized (REFERENCE_TO_CONNECTION_SOURCE) { // shutdown all connection managers synchronized (ALL_CONNECTION_MANAGERS) { // Don't use an iterator here. Iterators on WeakHashMap can // get ConcurrentModificationException on garbage collection. MultiThreadedHttpConnectionManager[] connManagers = (MultiThreadedHttpConnectionManager[]) ALL_CONNECTION_MANAGERS.keySet().toArray( new MultiThreadedHttpConnectionManager [ALL_CONNECTION_MANAGERS.size()] ); // The map may shrink after size() is called, or some entry // may get GCed while the array is built, so expect null. for (int i=0; i<connManagers.length; i++) { if (connManagers[i] != null) connManagers[i].shutdown(); } } // shutdown static resources if (REFERENCE_QUEUE_THREAD != null) { REFERENCE_QUEUE_THREAD.shutdown(); REFERENCE_QUEUE_THREAD = null; } REFERENCE_TO_CONNECTION_SOURCE.clear(); } } /** * Stores the reference to the given connection along with the host config and connection pool. * These values will be used to reclaim resources if the connection is lost to the garbage * collector. This method should be called before a connection is released from the connection * manager. * * <p>A static reference to the connection manager will also be stored. To ensure that * the connection manager can be GCed {@link #removeReferenceToConnection(HttpConnection)} * should be called for all connections that the connection manager is storing a reference * to.</p> * * @param connection the connection to create a reference for * @param hostConfiguration the connection's host config * @param connectionPool the connection pool that created the connection * * @see #removeReferenceToConnection(HttpConnection) */ private static void storeReferenceToConnection( HttpConnectionWithReference connection, HostConfiguration hostConfiguration, ConnectionPool connectionPool ) { ConnectionSource source = new ConnectionSource(); source.connectionPool = connectionPool; source.hostConfiguration = hostConfiguration; synchronized (REFERENCE_TO_CONNECTION_SOURCE) { // start the reference queue thread if needed if (REFERENCE_QUEUE_THREAD == null) { REFERENCE_QUEUE_THREAD = new ReferenceQueueThread(); REFERENCE_QUEUE_THREAD.start(); } REFERENCE_TO_CONNECTION_SOURCE.put( connection.reference, source ); } } /** * Closes and releases all connections currently checked out of the given connection pool. * @param connectionPool the connection pool to shutdown the connections for */ private static void shutdownCheckedOutConnections(ConnectionPool connectionPool) { // keep a list of the connections to be closed ArrayList connectionsToClose = new ArrayList(); synchronized (REFERENCE_TO_CONNECTION_SOURCE) { Iterator referenceIter = REFERENCE_TO_CONNECTION_SOURCE.keySet().iterator(); while (referenceIter.hasNext()) { Reference ref = (Reference) referenceIter.next(); ConnectionSource source = (ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE.get(ref); if (source.connectionPool == connectionPool) { referenceIter.remove(); HttpConnection connection = (HttpConnection) ref.get(); if (connection != null) { connectionsToClose.add(connection); } } } } // close and release the connections outside of the synchronized block to // avoid holding the lock for too long for (Iterator i = connectionsToClose.iterator(); i.hasNext();) { HttpConnection connection = (HttpConnection) i.next(); connection.close(); // remove the reference to the connection manager. this ensures // that the we don't accidentally end up here again connection.setHttpConnectionManager(null); connection.releaseConnection(); } } /** * Removes the reference being stored for the given connection. This method should be called * when the connection manager again has a direct reference to the connection. * * @param connection the connection to remove the reference for * * @see #storeReferenceToConnection(HttpConnection, HostConfiguration, ConnectionPool) */ private static void removeReferenceToConnection(HttpConnectionWithReference connection) { synchronized (REFERENCE_TO_CONNECTION_SOURCE) { REFERENCE_TO_CONNECTION_SOURCE.remove(connection.reference); } } // ----------------------------------------------------- Instance Variables /** * Collection of parameters associated with this connection manager. */ private HttpConnectionManagerParams params = new HttpConnectionManagerParams(); /** Connection Pool */ private ConnectionPool connectionPool; private volatile boolean shutdown = false; // ----------------------------------------------------------- Constructors /** * No-args constructor */ public MultiThreadedHttpConnectionManager() { this.connectionPool = new ConnectionPool(); synchronized(ALL_CONNECTION_MANAGERS) { ALL_CONNECTION_MANAGERS.put(this, null); } } // ------------------------------------------------------- Instance Methods /** * Shuts down the connection manager and releases all resources. All connections associated * with this class will be closed and released. * * <p>The connection manager can no longer be used once shut down. * * <p>Calling this method more than once will have no effect. */ public synchronized void shutdown() { synchronized (connectionPool) { if (!shutdown) { shutdown = true; connectionPool.shutdown(); } } } /** * Gets the staleCheckingEnabled value to be set on HttpConnections that are created. * * @return <code>true</code> if stale checking will be enabled on HttpConnections * * @see HttpConnection#isStaleCheckingEnabled() * * @deprecated Use {@link HttpConnectionManagerParams#isStaleCheckingEnabled()}, * {@link HttpConnectionManager#getParams()}. */ public boolean isConnectionStaleCheckingEnabled() { return this.params.isStaleCheckingEnabled(); } /** * Sets the staleCheckingEnabled value to be set on HttpConnections that are created. * * @param connectionStaleCheckingEnabled <code>true</code> if stale checking will be enabled * on HttpConnections * * @see HttpConnection#setStaleCheckingEnabled(boolean) * * @deprecated Use {@link HttpConnectionManagerParams#setStaleCheckingEnabled(boolean)}, * {@link HttpConnectionManager#getParams()}. */ public void setConnectionStaleCheckingEnabled(boolean connectionStaleCheckingEnabled) { this.params.setStaleCheckingEnabled(connectionStaleCheckingEnabled); } /** * Sets the maximum number of connections allowed for a given * HostConfiguration. Per RFC 2616 section 8.1.4, this value defaults to 2. * * @param maxHostConnections the number of connections allowed for each * hostConfiguration * * @deprecated Use {@link HttpConnectionManagerParams#setDefaultMaxConnectionsPerHost(int)}, * {@link HttpConnectionManager#getParams()}. */ public void setMaxConnectionsPerHost(int maxHostConnections) { this.params.setDefaultMaxConnectionsPerHost(maxHostConnections); } /** * Gets the maximum number of connections allowed for a given * hostConfiguration. * * @return The maximum number of connections allowed for a given * hostConfiguration. * * @deprecated Use {@link HttpConnectionManagerParams#getDefaultMaxConnectionsPerHost()}, * {@link HttpConnectionManager#getParams()}. */ public int getMaxConnectionsPerHost() { return this.params.getDefaultMaxConnectionsPerHost(); } /** * Sets the maximum number of connections allowed for this connection manager. * * @param maxTotalConnections the maximum number of connections allowed * * @deprecated Use {@link HttpConnectionManagerParams#setMaxTotalConnections(int)}, * {@link HttpConnectionManager#getParams()}. */ public void setMaxTotalConnections(int maxTotalConnections) { this.params.setMaxTotalConnections(maxTotalConnections); } /** * Gets the maximum number of connections allowed for this connection manager. * * @return The maximum number of connections allowed * * @deprecated Use {@link HttpConnectionManagerParams#getMaxTotalConnections()}, * {@link HttpConnectionManager#getParams()}. */ public int getMaxTotalConnections() { return this.params.getMaxTotalConnections(); } /** * @see HttpConnectionManager#getConnection(HostConfiguration) */ public HttpConnection getConnection(HostConfiguration hostConfiguration) { while (true) { try { return getConnectionWithTimeout(hostConfiguration, 0); } catch (ConnectionPoolTimeoutException e) { // we'll go ahead and log this, but it should never happen. HttpExceptions // are only thrown when the timeout occurs and since we have no timeout // it should never happen. LOG.debug( "Unexpected exception while waiting for connection", e ); } } } /** * Gets a connection or waits if one is not available. A connection is * available if one exists that is not being used or if fewer than * maxHostConnections have been created in the connectionPool, and fewer * than maxTotalConnections have been created in all connectionPools. * * @param hostConfiguration The host configuration specifying the connection * details. * @param timeout the number of milliseconds to wait for a connection, 0 to * wait indefinitely * * @return HttpConnection an available connection * * @throws HttpException if a connection does not become available in * 'timeout' milliseconds * * @since 3.0 */ public HttpConnection getConnectionWithTimeout(HostConfiguration hostConfiguration, long timeout) throws ConnectionPoolTimeoutException { LOG.trace("enter HttpConnectionManager.getConnectionWithTimeout(HostConfiguration, long)"); if (hostConfiguration == null) { throw new IllegalArgumentException("hostConfiguration is null"); } if (LOG.isDebugEnabled()) { LOG.debug("HttpConnectionManager.getConnection: config = " + hostConfiguration + ", timeout = " + timeout); } final HttpConnection conn = doGetConnection(hostConfiguration, timeout); // wrap the connection in an adapter so we can ensure it is used // only once return new HttpConnectionAdapter(conn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -