0001: /*
0002: * $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 $
0003: * $Revision: 564906 $
0004: * $Date: 2007-08-11 14:27:18 +0200 (Sat, 11 Aug 2007) $
0005: *
0006: * ====================================================================
0007: *
0008: * Licensed to the Apache Software Foundation (ASF) under one or more
0009: * contributor license agreements. See the NOTICE file distributed with
0010: * this work for additional information regarding copyright ownership.
0011: * The ASF licenses this file to You under the Apache License, Version 2.0
0012: * (the "License"); you may not use this file except in compliance with
0013: * the License. You may obtain a copy of the License at
0014: *
0015: * http://www.apache.org/licenses/LICENSE-2.0
0016: *
0017: * Unless required by applicable law or agreed to in writing, software
0018: * distributed under the License is distributed on an "AS IS" BASIS,
0019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0020: * See the License for the specific language governing permissions and
0021: * limitations under the License.
0022: * ====================================================================
0023: *
0024: * This software consists of voluntary contributions made by many
0025: * individuals on behalf of the Apache Software Foundation. For more
0026: * information on the Apache Software Foundation, please see
0027: * <http://www.apache.org/>.
0028: *
0029: */
0030:
0031: package org.apache.commons.httpclient;
0032:
0033: import java.io.IOException;
0034: import java.io.InputStream;
0035: import java.io.OutputStream;
0036: import java.lang.ref.Reference;
0037: import java.lang.ref.ReferenceQueue;
0038: import java.lang.ref.WeakReference;
0039: import java.net.InetAddress;
0040: import java.net.SocketException;
0041: import java.util.ArrayList;
0042: import java.util.HashMap;
0043: import java.util.Iterator;
0044: import java.util.LinkedList;
0045: import java.util.Map;
0046: import java.util.WeakHashMap;
0047:
0048: import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
0049: import org.apache.commons.httpclient.params.HttpConnectionParams;
0050: import org.apache.commons.httpclient.protocol.Protocol;
0051: import org.apache.commons.httpclient.util.IdleConnectionHandler;
0052: import org.apache.commons.logging.Log;
0053: import org.apache.commons.logging.LogFactory;
0054:
0055: /**
0056: * Manages a set of HttpConnections for various HostConfigurations.
0057: *
0058: * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
0059: * @author Eric Johnson
0060: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
0061: * @author Carl A. Dunham
0062: *
0063: * @since 2.0
0064: */
0065: public class MultiThreadedHttpConnectionManager implements
0066: HttpConnectionManager {
0067:
0068: // -------------------------------------------------------- Class Variables
0069:
0070: /** Log object for this class. */
0071: private static final Log LOG = LogFactory
0072: .getLog(MultiThreadedHttpConnectionManager.class);
0073:
0074: /** The default maximum number of connections allowed per host */
0075: public static final int DEFAULT_MAX_HOST_CONNECTIONS = 2; // Per RFC 2616 sec 8.1.4
0076:
0077: /** The default maximum number of connections allowed overall */
0078: public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20;
0079:
0080: /**
0081: * A mapping from Reference to ConnectionSource. Used to reclaim resources when connections
0082: * are lost to the garbage collector.
0083: */
0084: private static final Map REFERENCE_TO_CONNECTION_SOURCE = new HashMap();
0085:
0086: /**
0087: * The reference queue used to track when HttpConnections are lost to the
0088: * garbage collector
0089: */
0090: private static final ReferenceQueue REFERENCE_QUEUE = new ReferenceQueue();
0091:
0092: /**
0093: * The thread responsible for handling lost connections.
0094: */
0095: private static ReferenceQueueThread REFERENCE_QUEUE_THREAD;
0096:
0097: /**
0098: * Holds references to all active instances of this class.
0099: */
0100: private static WeakHashMap ALL_CONNECTION_MANAGERS = new WeakHashMap();
0101:
0102: // ---------------------------------------------------------- Class Methods
0103:
0104: /**
0105: * Shuts down and cleans up resources used by all instances of
0106: * MultiThreadedHttpConnectionManager. All static resources are released, all threads are
0107: * stopped, and {@link #shutdown()} is called on all live instances of
0108: * MultiThreadedHttpConnectionManager.
0109: *
0110: * @see #shutdown()
0111: */
0112: public static void shutdownAll() {
0113:
0114: synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0115: // shutdown all connection managers
0116: synchronized (ALL_CONNECTION_MANAGERS) {
0117: // Don't use an iterator here. Iterators on WeakHashMap can
0118: // get ConcurrentModificationException on garbage collection.
0119: MultiThreadedHttpConnectionManager[] connManagers = (MultiThreadedHttpConnectionManager[]) ALL_CONNECTION_MANAGERS
0120: .keySet()
0121: .toArray(
0122: new MultiThreadedHttpConnectionManager[ALL_CONNECTION_MANAGERS
0123: .size()]);
0124:
0125: // The map may shrink after size() is called, or some entry
0126: // may get GCed while the array is built, so expect null.
0127: for (int i = 0; i < connManagers.length; i++) {
0128: if (connManagers[i] != null)
0129: connManagers[i].shutdown();
0130: }
0131: }
0132:
0133: // shutdown static resources
0134: if (REFERENCE_QUEUE_THREAD != null) {
0135: REFERENCE_QUEUE_THREAD.shutdown();
0136: REFERENCE_QUEUE_THREAD = null;
0137: }
0138: REFERENCE_TO_CONNECTION_SOURCE.clear();
0139: }
0140: }
0141:
0142: /**
0143: * Stores the reference to the given connection along with the host config and connection pool.
0144: * These values will be used to reclaim resources if the connection is lost to the garbage
0145: * collector. This method should be called before a connection is released from the connection
0146: * manager.
0147: *
0148: * <p>A static reference to the connection manager will also be stored. To ensure that
0149: * the connection manager can be GCed {@link #removeReferenceToConnection(HttpConnection)}
0150: * should be called for all connections that the connection manager is storing a reference
0151: * to.</p>
0152: *
0153: * @param connection the connection to create a reference for
0154: * @param hostConfiguration the connection's host config
0155: * @param connectionPool the connection pool that created the connection
0156: *
0157: * @see #removeReferenceToConnection(HttpConnection)
0158: */
0159: private static void storeReferenceToConnection(
0160: HttpConnectionWithReference connection,
0161: HostConfiguration hostConfiguration,
0162: ConnectionPool connectionPool) {
0163:
0164: ConnectionSource source = new ConnectionSource();
0165: source.connectionPool = connectionPool;
0166: source.hostConfiguration = hostConfiguration;
0167:
0168: synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0169:
0170: // start the reference queue thread if needed
0171: if (REFERENCE_QUEUE_THREAD == null) {
0172: REFERENCE_QUEUE_THREAD = new ReferenceQueueThread();
0173: REFERENCE_QUEUE_THREAD.start();
0174: }
0175:
0176: REFERENCE_TO_CONNECTION_SOURCE.put(connection.reference,
0177: source);
0178: }
0179: }
0180:
0181: /**
0182: * Closes and releases all connections currently checked out of the given connection pool.
0183: * @param connectionPool the connection pool to shutdown the connections for
0184: */
0185: private static void shutdownCheckedOutConnections(
0186: ConnectionPool connectionPool) {
0187:
0188: // keep a list of the connections to be closed
0189: ArrayList connectionsToClose = new ArrayList();
0190:
0191: synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0192:
0193: Iterator referenceIter = REFERENCE_TO_CONNECTION_SOURCE
0194: .keySet().iterator();
0195: while (referenceIter.hasNext()) {
0196: Reference ref = (Reference) referenceIter.next();
0197: ConnectionSource source = (ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE
0198: .get(ref);
0199: if (source.connectionPool == connectionPool) {
0200: referenceIter.remove();
0201: HttpConnection connection = (HttpConnection) ref
0202: .get();
0203: if (connection != null) {
0204: connectionsToClose.add(connection);
0205: }
0206: }
0207: }
0208: }
0209:
0210: // close and release the connections outside of the synchronized block to
0211: // avoid holding the lock for too long
0212: for (Iterator i = connectionsToClose.iterator(); i.hasNext();) {
0213: HttpConnection connection = (HttpConnection) i.next();
0214: connection.close();
0215: // remove the reference to the connection manager. this ensures
0216: // that the we don't accidentally end up here again
0217: connection.setHttpConnectionManager(null);
0218: connection.releaseConnection();
0219: }
0220: }
0221:
0222: /**
0223: * Removes the reference being stored for the given connection. This method should be called
0224: * when the connection manager again has a direct reference to the connection.
0225: *
0226: * @param connection the connection to remove the reference for
0227: *
0228: * @see #storeReferenceToConnection(HttpConnection, HostConfiguration, ConnectionPool)
0229: */
0230: private static void removeReferenceToConnection(
0231: HttpConnectionWithReference connection) {
0232:
0233: synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0234: REFERENCE_TO_CONNECTION_SOURCE.remove(connection.reference);
0235: }
0236: }
0237:
0238: // ----------------------------------------------------- Instance Variables
0239:
0240: /**
0241: * Collection of parameters associated with this connection manager.
0242: */
0243: private HttpConnectionManagerParams params = new HttpConnectionManagerParams();
0244:
0245: /** Connection Pool */
0246: private ConnectionPool connectionPool;
0247:
0248: private volatile boolean shutdown = false;
0249:
0250: // ----------------------------------------------------------- Constructors
0251:
0252: /**
0253: * No-args constructor
0254: */
0255: public MultiThreadedHttpConnectionManager() {
0256: this .connectionPool = new ConnectionPool();
0257: synchronized (ALL_CONNECTION_MANAGERS) {
0258: ALL_CONNECTION_MANAGERS.put(this , null);
0259: }
0260: }
0261:
0262: // ------------------------------------------------------- Instance Methods
0263:
0264: /**
0265: * Shuts down the connection manager and releases all resources. All connections associated
0266: * with this class will be closed and released.
0267: *
0268: * <p>The connection manager can no longer be used once shut down.
0269: *
0270: * <p>Calling this method more than once will have no effect.
0271: */
0272: public synchronized void shutdown() {
0273: synchronized (connectionPool) {
0274: if (!shutdown) {
0275: shutdown = true;
0276: connectionPool.shutdown();
0277: }
0278: }
0279: }
0280:
0281: /**
0282: * Gets the staleCheckingEnabled value to be set on HttpConnections that are created.
0283: *
0284: * @return <code>true</code> if stale checking will be enabled on HttpConnections
0285: *
0286: * @see HttpConnection#isStaleCheckingEnabled()
0287: *
0288: * @deprecated Use {@link HttpConnectionManagerParams#isStaleCheckingEnabled()},
0289: * {@link HttpConnectionManager#getParams()}.
0290: */
0291: public boolean isConnectionStaleCheckingEnabled() {
0292: return this .params.isStaleCheckingEnabled();
0293: }
0294:
0295: /**
0296: * Sets the staleCheckingEnabled value to be set on HttpConnections that are created.
0297: *
0298: * @param connectionStaleCheckingEnabled <code>true</code> if stale checking will be enabled
0299: * on HttpConnections
0300: *
0301: * @see HttpConnection#setStaleCheckingEnabled(boolean)
0302: *
0303: * @deprecated Use {@link HttpConnectionManagerParams#setStaleCheckingEnabled(boolean)},
0304: * {@link HttpConnectionManager#getParams()}.
0305: */
0306: public void setConnectionStaleCheckingEnabled(
0307: boolean connectionStaleCheckingEnabled) {
0308: this .params
0309: .setStaleCheckingEnabled(connectionStaleCheckingEnabled);
0310: }
0311:
0312: /**
0313: * Sets the maximum number of connections allowed for a given
0314: * HostConfiguration. Per RFC 2616 section 8.1.4, this value defaults to 2.
0315: *
0316: * @param maxHostConnections the number of connections allowed for each
0317: * hostConfiguration
0318: *
0319: * @deprecated Use {@link HttpConnectionManagerParams#setDefaultMaxConnectionsPerHost(int)},
0320: * {@link HttpConnectionManager#getParams()}.
0321: */
0322: public void setMaxConnectionsPerHost(int maxHostConnections) {
0323: this .params.setDefaultMaxConnectionsPerHost(maxHostConnections);
0324: }
0325:
0326: /**
0327: * Gets the maximum number of connections allowed for a given
0328: * hostConfiguration.
0329: *
0330: * @return The maximum number of connections allowed for a given
0331: * hostConfiguration.
0332: *
0333: * @deprecated Use {@link HttpConnectionManagerParams#getDefaultMaxConnectionsPerHost()},
0334: * {@link HttpConnectionManager#getParams()}.
0335: */
0336: public int getMaxConnectionsPerHost() {
0337: return this .params.getDefaultMaxConnectionsPerHost();
0338: }
0339:
0340: /**
0341: * Sets the maximum number of connections allowed for this connection manager.
0342: *
0343: * @param maxTotalConnections the maximum number of connections allowed
0344: *
0345: * @deprecated Use {@link HttpConnectionManagerParams#setMaxTotalConnections(int)},
0346: * {@link HttpConnectionManager#getParams()}.
0347: */
0348: public void setMaxTotalConnections(int maxTotalConnections) {
0349: this .params.setMaxTotalConnections(maxTotalConnections);
0350: }
0351:
0352: /**
0353: * Gets the maximum number of connections allowed for this connection manager.
0354: *
0355: * @return The maximum number of connections allowed
0356: *
0357: * @deprecated Use {@link HttpConnectionManagerParams#getMaxTotalConnections()},
0358: * {@link HttpConnectionManager#getParams()}.
0359: */
0360: public int getMaxTotalConnections() {
0361: return this .params.getMaxTotalConnections();
0362: }
0363:
0364: /**
0365: * @see HttpConnectionManager#getConnection(HostConfiguration)
0366: */
0367: public HttpConnection getConnection(
0368: HostConfiguration hostConfiguration) {
0369:
0370: while (true) {
0371: try {
0372: return getConnectionWithTimeout(hostConfiguration, 0);
0373: } catch (ConnectionPoolTimeoutException e) {
0374: // we'll go ahead and log this, but it should never happen. HttpExceptions
0375: // are only thrown when the timeout occurs and since we have no timeout
0376: // it should never happen.
0377: LOG
0378: .debug(
0379: "Unexpected exception while waiting for connection",
0380: e);
0381: }
0382: }
0383: }
0384:
0385: /**
0386: * Gets a connection or waits if one is not available. A connection is
0387: * available if one exists that is not being used or if fewer than
0388: * maxHostConnections have been created in the connectionPool, and fewer
0389: * than maxTotalConnections have been created in all connectionPools.
0390: *
0391: * @param hostConfiguration The host configuration specifying the connection
0392: * details.
0393: * @param timeout the number of milliseconds to wait for a connection, 0 to
0394: * wait indefinitely
0395: *
0396: * @return HttpConnection an available connection
0397: *
0398: * @throws HttpException if a connection does not become available in
0399: * 'timeout' milliseconds
0400: *
0401: * @since 3.0
0402: */
0403: public HttpConnection getConnectionWithTimeout(
0404: HostConfiguration hostConfiguration, long timeout)
0405: throws ConnectionPoolTimeoutException {
0406:
0407: LOG
0408: .trace("enter HttpConnectionManager.getConnectionWithTimeout(HostConfiguration, long)");
0409:
0410: if (hostConfiguration == null) {
0411: throw new IllegalArgumentException(
0412: "hostConfiguration is null");
0413: }
0414:
0415: if (LOG.isDebugEnabled()) {
0416: LOG.debug("HttpConnectionManager.getConnection: config = "
0417: + hostConfiguration + ", timeout = " + timeout);
0418: }
0419:
0420: final HttpConnection conn = doGetConnection(hostConfiguration,
0421: timeout);
0422:
0423: // wrap the connection in an adapter so we can ensure it is used
0424: // only once
0425: return new HttpConnectionAdapter(conn);
0426: }
0427:
0428: /**
0429: * @see HttpConnectionManager#getConnection(HostConfiguration, long)
0430: *
0431: * @deprecated Use #getConnectionWithTimeout(HostConfiguration, long)
0432: */
0433: public HttpConnection getConnection(
0434: HostConfiguration hostConfiguration, long timeout)
0435: throws HttpException {
0436:
0437: LOG
0438: .trace("enter HttpConnectionManager.getConnection(HostConfiguration, long)");
0439: try {
0440: return getConnectionWithTimeout(hostConfiguration, timeout);
0441: } catch (ConnectionPoolTimeoutException e) {
0442: throw new HttpException(e.getMessage());
0443: }
0444: }
0445:
0446: private HttpConnection doGetConnection(
0447: HostConfiguration hostConfiguration, long timeout)
0448: throws ConnectionPoolTimeoutException {
0449:
0450: HttpConnection connection = null;
0451:
0452: int maxHostConnections = this .params
0453: .getMaxConnectionsPerHost(hostConfiguration);
0454: int maxTotalConnections = this .params.getMaxTotalConnections();
0455:
0456: synchronized (connectionPool) {
0457:
0458: // we clone the hostConfiguration
0459: // so that it cannot be changed once the connection has been retrieved
0460: hostConfiguration = new HostConfiguration(hostConfiguration);
0461: HostConnectionPool hostPool = connectionPool.getHostPool(
0462: hostConfiguration, true);
0463: WaitingThread waitingThread = null;
0464:
0465: boolean useTimeout = (timeout > 0);
0466: long timeToWait = timeout;
0467: long startWait = 0;
0468: long endWait = 0;
0469:
0470: while (connection == null) {
0471:
0472: if (shutdown) {
0473: throw new IllegalStateException(
0474: "Connection factory has been shutdown.");
0475: }
0476:
0477: // happen to have a free connection with the right specs
0478: //
0479: if (hostPool.freeConnections.size() > 0) {
0480: connection = connectionPool
0481: .getFreeConnection(hostConfiguration);
0482:
0483: // have room to make more
0484: //
0485: } else if ((hostPool.numConnections < maxHostConnections)
0486: && (connectionPool.numConnections < maxTotalConnections)) {
0487:
0488: connection = connectionPool
0489: .createConnection(hostConfiguration);
0490:
0491: // have room to add host connection, and there is at least one free
0492: // connection that can be liberated to make overall room
0493: //
0494: } else if ((hostPool.numConnections < maxHostConnections)
0495: && (connectionPool.freeConnections.size() > 0)) {
0496:
0497: connectionPool.deleteLeastUsedConnection();
0498: connection = connectionPool
0499: .createConnection(hostConfiguration);
0500:
0501: // otherwise, we have to wait for one of the above conditions to
0502: // become true
0503: //
0504: } else {
0505: // TODO: keep track of which hostConfigurations have waiting
0506: // threads, so they avoid being sacrificed before necessary
0507:
0508: try {
0509:
0510: if (useTimeout && timeToWait <= 0) {
0511: throw new ConnectionPoolTimeoutException(
0512: "Timeout waiting for connection");
0513: }
0514:
0515: if (LOG.isDebugEnabled()) {
0516: LOG
0517: .debug("Unable to get a connection, waiting..., hostConfig="
0518: + hostConfiguration);
0519: }
0520:
0521: if (waitingThread == null) {
0522: waitingThread = new WaitingThread();
0523: waitingThread.hostConnectionPool = hostPool;
0524: waitingThread.thread = Thread
0525: .currentThread();
0526: } else {
0527: waitingThread.interruptedByConnectionPool = false;
0528: }
0529:
0530: if (useTimeout) {
0531: startWait = System.currentTimeMillis();
0532: }
0533:
0534: hostPool.waitingThreads.addLast(waitingThread);
0535: connectionPool.waitingThreads
0536: .addLast(waitingThread);
0537: connectionPool.wait(timeToWait);
0538: } catch (InterruptedException e) {
0539: if (!waitingThread.interruptedByConnectionPool) {
0540: LOG
0541: .debug(
0542: "Interrupted while waiting for connection",
0543: e);
0544: throw new IllegalThreadStateException(
0545: "Interrupted while waiting in MultiThreadedHttpConnectionManager");
0546: }
0547: // Else, do nothing, we were interrupted by the connection pool
0548: // and should now have a connection waiting for us, continue
0549: // in the loop and let's get it.
0550: } finally {
0551: if (!waitingThread.interruptedByConnectionPool) {
0552: // Either we timed out, experienced a "spurious wakeup", or were
0553: // interrupted by an external thread. Regardless we need to
0554: // cleanup for ourselves in the wait queue.
0555: hostPool.waitingThreads
0556: .remove(waitingThread);
0557: connectionPool.waitingThreads
0558: .remove(waitingThread);
0559: }
0560:
0561: if (useTimeout) {
0562: endWait = System.currentTimeMillis();
0563: timeToWait -= (endWait - startWait);
0564: }
0565: }
0566: }
0567: }
0568: }
0569: return connection;
0570: }
0571:
0572: /**
0573: * Gets the total number of pooled connections for the given host configuration. This
0574: * is the total number of connections that have been created and are still in use
0575: * by this connection manager for the host configuration. This value will
0576: * not exceed the {@link #getMaxConnectionsPerHost() maximum number of connections per
0577: * host}.
0578: *
0579: * @param hostConfiguration The host configuration
0580: * @return The total number of pooled connections
0581: */
0582: public int getConnectionsInPool(HostConfiguration hostConfiguration) {
0583: synchronized (connectionPool) {
0584: HostConnectionPool hostPool = connectionPool.getHostPool(
0585: hostConfiguration, false);
0586: return (hostPool != null) ? hostPool.numConnections : 0;
0587: }
0588: }
0589:
0590: /**
0591: * Gets the total number of pooled connections. This is the total number of
0592: * connections that have been created and are still in use by this connection
0593: * manager. This value will not exceed the {@link #getMaxTotalConnections()
0594: * maximum number of connections}.
0595: *
0596: * @return the total number of pooled connections
0597: */
0598: public int getConnectionsInPool() {
0599: synchronized (connectionPool) {
0600: return connectionPool.numConnections;
0601: }
0602: }
0603:
0604: /**
0605: * Gets the number of connections in use for this configuration.
0606: *
0607: * @param hostConfiguration the key that connections are tracked on
0608: * @return the number of connections in use
0609: *
0610: * @deprecated Use {@link #getConnectionsInPool(HostConfiguration)}
0611: */
0612: public int getConnectionsInUse(HostConfiguration hostConfiguration) {
0613: return getConnectionsInPool(hostConfiguration);
0614: }
0615:
0616: /**
0617: * Gets the total number of connections in use.
0618: *
0619: * @return the total number of connections in use
0620: *
0621: * @deprecated Use {@link #getConnectionsInPool()}
0622: */
0623: public int getConnectionsInUse() {
0624: return getConnectionsInPool();
0625: }
0626:
0627: /**
0628: * Deletes all closed connections. Only connections currently owned by the connection
0629: * manager are processed.
0630: *
0631: * @see HttpConnection#isOpen()
0632: *
0633: * @since 3.0
0634: */
0635: public void deleteClosedConnections() {
0636: connectionPool.deleteClosedConnections();
0637: }
0638:
0639: /**
0640: * @since 3.0
0641: */
0642: public void closeIdleConnections(long idleTimeout) {
0643: connectionPool.closeIdleConnections(idleTimeout);
0644: deleteClosedConnections();
0645: }
0646:
0647: /**
0648: * Make the given HttpConnection available for use by other requests.
0649: * If another thread is blocked in getConnection() that could use this
0650: * connection, it will be woken up.
0651: *
0652: * @param conn the HttpConnection to make available.
0653: */
0654: public void releaseConnection(HttpConnection conn) {
0655: LOG
0656: .trace("enter HttpConnectionManager.releaseConnection(HttpConnection)");
0657:
0658: if (conn instanceof HttpConnectionAdapter) {
0659: // connections given out are wrapped in an HttpConnectionAdapter
0660: conn = ((HttpConnectionAdapter) conn)
0661: .getWrappedConnection();
0662: } else {
0663: // this is okay, when an HttpConnectionAdapter is released
0664: // is releases the real connection
0665: }
0666:
0667: // make sure that the response has been read.
0668: SimpleHttpConnectionManager.finishLastResponse(conn);
0669:
0670: connectionPool.freeConnection(conn);
0671: }
0672:
0673: /**
0674: * Gets the host configuration for a connection.
0675: * @param conn the connection to get the configuration of
0676: * @return a new HostConfiguration
0677: */
0678: private HostConfiguration configurationForConnection(
0679: HttpConnection conn) {
0680:
0681: HostConfiguration connectionConfiguration = new HostConfiguration();
0682:
0683: connectionConfiguration.setHost(conn.getHost(), conn.getPort(),
0684: conn.getProtocol());
0685: if (conn.getLocalAddress() != null) {
0686: connectionConfiguration.setLocalAddress(conn
0687: .getLocalAddress());
0688: }
0689: if (conn.getProxyHost() != null) {
0690: connectionConfiguration.setProxy(conn.getProxyHost(), conn
0691: .getProxyPort());
0692: }
0693:
0694: return connectionConfiguration;
0695: }
0696:
0697: /**
0698: * Returns {@link HttpConnectionManagerParams parameters} associated
0699: * with this connection manager.
0700: *
0701: * @since 3.0
0702: *
0703: * @see HttpConnectionManagerParams
0704: */
0705: public HttpConnectionManagerParams getParams() {
0706: return this .params;
0707: }
0708:
0709: /**
0710: * Assigns {@link HttpConnectionManagerParams parameters} for this
0711: * connection manager.
0712: *
0713: * @since 3.0
0714: *
0715: * @see HttpConnectionManagerParams
0716: */
0717: public void setParams(final HttpConnectionManagerParams params) {
0718: if (params == null) {
0719: throw new IllegalArgumentException(
0720: "Parameters may not be null");
0721: }
0722: this .params = params;
0723: }
0724:
0725: /**
0726: * Global Connection Pool, including per-host pools
0727: */
0728: private class ConnectionPool {
0729:
0730: /** The list of free connections */
0731: private LinkedList freeConnections = new LinkedList();
0732:
0733: /** The list of WaitingThreads waiting for a connection */
0734: private LinkedList waitingThreads = new LinkedList();
0735:
0736: /**
0737: * Map where keys are {@link HostConfiguration}s and values are {@link
0738: * HostConnectionPool}s
0739: */
0740: private final Map mapHosts = new HashMap();
0741:
0742: private IdleConnectionHandler idleConnectionHandler = new IdleConnectionHandler();
0743:
0744: /** The number of created connections */
0745: private int numConnections = 0;
0746:
0747: /**
0748: * Cleans up all connection pool resources.
0749: */
0750: public synchronized void shutdown() {
0751:
0752: // close all free connections
0753: Iterator iter = freeConnections.iterator();
0754: while (iter.hasNext()) {
0755: HttpConnection conn = (HttpConnection) iter.next();
0756: iter.remove();
0757: conn.close();
0758: }
0759:
0760: // close all connections that have been checked out
0761: shutdownCheckedOutConnections(this );
0762:
0763: // interrupt all waiting threads
0764: iter = waitingThreads.iterator();
0765: while (iter.hasNext()) {
0766: WaitingThread waiter = (WaitingThread) iter.next();
0767: iter.remove();
0768: waiter.interruptedByConnectionPool = true;
0769: waiter.thread.interrupt();
0770: }
0771:
0772: // clear out map hosts
0773: mapHosts.clear();
0774:
0775: // remove all references to connections
0776: idleConnectionHandler.removeAll();
0777: }
0778:
0779: /**
0780: * Creates a new connection and returns it for use of the calling method.
0781: *
0782: * @param hostConfiguration the configuration for the connection
0783: * @return a new connection or <code>null</code> if none are available
0784: */
0785: public synchronized HttpConnection createConnection(
0786: HostConfiguration hostConfiguration) {
0787: HostConnectionPool hostPool = getHostPool(
0788: hostConfiguration, true);
0789: if (LOG.isDebugEnabled()) {
0790: LOG.debug("Allocating new connection, hostConfig="
0791: + hostConfiguration);
0792: }
0793: HttpConnectionWithReference connection = new HttpConnectionWithReference(
0794: hostConfiguration);
0795: connection.getParams().setDefaults(
0796: MultiThreadedHttpConnectionManager.this .params);
0797: connection
0798: .setHttpConnectionManager(MultiThreadedHttpConnectionManager.this );
0799: numConnections++;
0800: hostPool.numConnections++;
0801:
0802: // store a reference to this connection so that it can be cleaned up
0803: // in the event it is not correctly released
0804: storeReferenceToConnection(connection, hostConfiguration,
0805: this );
0806: return connection;
0807: }
0808:
0809: /**
0810: * Handles cleaning up for a lost connection with the given config. Decrements any
0811: * connection counts and notifies waiting threads, if appropriate.
0812: *
0813: * @param config the host configuration of the connection that was lost
0814: */
0815: public synchronized void handleLostConnection(
0816: HostConfiguration config) {
0817: HostConnectionPool hostPool = getHostPool(config, true);
0818: hostPool.numConnections--;
0819: if ((hostPool.numConnections == 0)
0820: && hostPool.waitingThreads.isEmpty()) {
0821:
0822: mapHosts.remove(config);
0823: }
0824:
0825: numConnections--;
0826: notifyWaitingThread(config);
0827: }
0828:
0829: /**
0830: * Get the pool (list) of connections available for the given hostConfig.
0831: *
0832: * @param hostConfiguration the configuraton for the connection pool
0833: * @param create <code>true</code> to create a pool if not found,
0834: * <code>false</code> to return <code>null</code>
0835: *
0836: * @return a pool (list) of connections available for the given config,
0837: * or <code>null</code> if neither found nor created
0838: */
0839: public synchronized HostConnectionPool getHostPool(
0840: HostConfiguration hostConfiguration, boolean create) {
0841: LOG
0842: .trace("enter HttpConnectionManager.ConnectionPool.getHostPool(HostConfiguration)");
0843:
0844: // Look for a list of connections for the given config
0845: HostConnectionPool listConnections = (HostConnectionPool) mapHosts
0846: .get(hostConfiguration);
0847: if ((listConnections == null) && create) {
0848: // First time for this config
0849: listConnections = new HostConnectionPool();
0850: listConnections.hostConfiguration = hostConfiguration;
0851: mapHosts.put(hostConfiguration, listConnections);
0852: }
0853:
0854: return listConnections;
0855: }
0856:
0857: /**
0858: * If available, get a free connection for this host
0859: *
0860: * @param hostConfiguration the configuraton for the connection pool
0861: * @return an available connection for the given config
0862: */
0863: public synchronized HttpConnection getFreeConnection(
0864: HostConfiguration hostConfiguration) {
0865:
0866: HttpConnectionWithReference connection = null;
0867:
0868: HostConnectionPool hostPool = getHostPool(
0869: hostConfiguration, false);
0870:
0871: if ((hostPool != null)
0872: && (hostPool.freeConnections.size() > 0)) {
0873: connection = (HttpConnectionWithReference) hostPool.freeConnections
0874: .removeLast();
0875: freeConnections.remove(connection);
0876: // store a reference to this connection so that it can be cleaned up
0877: // in the event it is not correctly released
0878: storeReferenceToConnection(connection,
0879: hostConfiguration, this );
0880: if (LOG.isDebugEnabled()) {
0881: LOG.debug("Getting free connection, hostConfig="
0882: + hostConfiguration);
0883: }
0884:
0885: // remove the connection from the timeout handler
0886: idleConnectionHandler.remove(connection);
0887: } else if (LOG.isDebugEnabled()) {
0888: LOG
0889: .debug("There were no free connections to get, hostConfig="
0890: + hostConfiguration);
0891: }
0892: return connection;
0893: }
0894:
0895: /**
0896: * Deletes all closed connections.
0897: */
0898: public synchronized void deleteClosedConnections() {
0899:
0900: Iterator iter = freeConnections.iterator();
0901:
0902: while (iter.hasNext()) {
0903: HttpConnection conn = (HttpConnection) iter.next();
0904: if (!conn.isOpen()) {
0905: iter.remove();
0906: deleteConnection(conn);
0907: }
0908: }
0909: }
0910:
0911: /**
0912: * Closes idle connections.
0913: * @param idleTimeout
0914: */
0915: public synchronized void closeIdleConnections(long idleTimeout) {
0916: idleConnectionHandler.closeIdleConnections(idleTimeout);
0917: }
0918:
0919: /**
0920: * Deletes the given connection. This will remove all reference to the connection
0921: * so that it can be GCed.
0922: *
0923: * <p><b>Note:</b> Does not remove the connection from the freeConnections list. It
0924: * is assumed that the caller has already handled this case.</p>
0925: *
0926: * @param connection The connection to delete
0927: */
0928: private synchronized void deleteConnection(
0929: HttpConnection connection) {
0930:
0931: HostConfiguration connectionConfiguration = configurationForConnection(connection);
0932:
0933: if (LOG.isDebugEnabled()) {
0934: LOG.debug("Reclaiming connection, hostConfig="
0935: + connectionConfiguration);
0936: }
0937:
0938: connection.close();
0939:
0940: HostConnectionPool hostPool = getHostPool(
0941: connectionConfiguration, true);
0942:
0943: hostPool.freeConnections.remove(connection);
0944: hostPool.numConnections--;
0945: numConnections--;
0946: if ((hostPool.numConnections == 0)
0947: && hostPool.waitingThreads.isEmpty()) {
0948:
0949: mapHosts.remove(connectionConfiguration);
0950: }
0951:
0952: // remove the connection from the timeout handler
0953: idleConnectionHandler.remove(connection);
0954: }
0955:
0956: /**
0957: * Close and delete an old, unused connection to make room for a new one.
0958: */
0959: public synchronized void deleteLeastUsedConnection() {
0960:
0961: HttpConnection connection = (HttpConnection) freeConnections
0962: .removeFirst();
0963:
0964: if (connection != null) {
0965: deleteConnection(connection);
0966: } else if (LOG.isDebugEnabled()) {
0967: LOG
0968: .debug("Attempted to reclaim an unused connection but there were none.");
0969: }
0970: }
0971:
0972: /**
0973: * Notifies a waiting thread that a connection for the given configuration is
0974: * available.
0975: * @param configuration the host config to use for notifying
0976: * @see #notifyWaitingThread(HostConnectionPool)
0977: */
0978: public synchronized void notifyWaitingThread(
0979: HostConfiguration configuration) {
0980: notifyWaitingThread(getHostPool(configuration, true));
0981: }
0982:
0983: /**
0984: * Notifies a waiting thread that a connection for the given configuration is
0985: * available. This will wake a thread waiting in this host pool or if there is not
0986: * one a thread in the connection pool will be notified.
0987: *
0988: * @param hostPool the host pool to use for notifying
0989: */
0990: public synchronized void notifyWaitingThread(
0991: HostConnectionPool hostPool) {
0992:
0993: // find the thread we are going to notify, we want to ensure that each
0994: // waiting thread is only interrupted once so we will remove it from
0995: // all wait queues before interrupting it
0996: WaitingThread waitingThread = null;
0997:
0998: if (hostPool.waitingThreads.size() > 0) {
0999: if (LOG.isDebugEnabled()) {
1000: LOG
1001: .debug("Notifying thread waiting on host pool, hostConfig="
1002: + hostPool.hostConfiguration);
1003: }
1004: waitingThread = (WaitingThread) hostPool.waitingThreads
1005: .removeFirst();
1006: waitingThreads.remove(waitingThread);
1007: } else if (waitingThreads.size() > 0) {
1008: if (LOG.isDebugEnabled()) {
1009: LOG
1010: .debug("No-one waiting on host pool, notifying next waiting thread.");
1011: }
1012: waitingThread = (WaitingThread) waitingThreads
1013: .removeFirst();
1014: waitingThread.hostConnectionPool.waitingThreads
1015: .remove(waitingThread);
1016: } else if (LOG.isDebugEnabled()) {
1017: LOG
1018: .debug("Notifying no-one, there are no waiting threads");
1019: }
1020:
1021: if (waitingThread != null) {
1022: waitingThread.interruptedByConnectionPool = true;
1023: waitingThread.thread.interrupt();
1024: }
1025: }
1026:
1027: /**
1028: * Marks the given connection as free.
1029: * @param conn a connection that is no longer being used
1030: */
1031: public void freeConnection(HttpConnection conn) {
1032:
1033: HostConfiguration connectionConfiguration = configurationForConnection(conn);
1034:
1035: if (LOG.isDebugEnabled()) {
1036: LOG.debug("Freeing connection, hostConfig="
1037: + connectionConfiguration);
1038: }
1039:
1040: synchronized (this ) {
1041:
1042: if (shutdown) {
1043: // the connection manager has been shutdown, release the connection's
1044: // resources and get out of here
1045: conn.close();
1046: return;
1047: }
1048:
1049: HostConnectionPool hostPool = getHostPool(
1050: connectionConfiguration, true);
1051:
1052: // Put the connect back in the available list and notify a waiter
1053: hostPool.freeConnections.add(conn);
1054: if (hostPool.numConnections == 0) {
1055: // for some reason this connection pool didn't already exist
1056: LOG
1057: .error("Host connection pool not found, hostConfig="
1058: + connectionConfiguration);
1059: hostPool.numConnections = 1;
1060: }
1061:
1062: freeConnections.add(conn);
1063: // we can remove the reference to this connection as we have control over
1064: // it again. this also ensures that the connection manager can be GCed
1065: removeReferenceToConnection((HttpConnectionWithReference) conn);
1066: if (numConnections == 0) {
1067: // for some reason this connection pool didn't already exist
1068: LOG
1069: .error("Host connection pool not found, hostConfig="
1070: + connectionConfiguration);
1071: numConnections = 1;
1072: }
1073:
1074: // register the connection with the timeout handler
1075: idleConnectionHandler.add(conn);
1076:
1077: notifyWaitingThread(hostPool);
1078: }
1079: }
1080: }
1081:
1082: /**
1083: * A simple struct-like class to combine the objects needed to release a connection's
1084: * resources when claimed by the garbage collector.
1085: */
1086: private static class ConnectionSource {
1087:
1088: /** The connection pool that created the connection */
1089: public ConnectionPool connectionPool;
1090:
1091: /** The connection's host configuration */
1092: public HostConfiguration hostConfiguration;
1093: }
1094:
1095: /**
1096: * A simple struct-like class to combine the connection list and the count
1097: * of created connections.
1098: */
1099: private static class HostConnectionPool {
1100: /** The hostConfig this pool is for */
1101: public HostConfiguration hostConfiguration;
1102:
1103: /** The list of free connections */
1104: public LinkedList freeConnections = new LinkedList();
1105:
1106: /** The list of WaitingThreads for this host */
1107: public LinkedList waitingThreads = new LinkedList();
1108:
1109: /** The number of created connections */
1110: public int numConnections = 0;
1111: }
1112:
1113: /**
1114: * A simple struct-like class to combine the waiting thread and the connection
1115: * pool it is waiting on.
1116: */
1117: private static class WaitingThread {
1118: /** The thread that is waiting for a connection */
1119: public Thread thread;
1120:
1121: /** The connection pool the thread is waiting for */
1122: public HostConnectionPool hostConnectionPool;
1123:
1124: /** Flag to indicate if the thread was interrupted by the ConnectionPool. Set
1125: * to true inside {@link ConnectionPool#notifyWaitingThread(HostConnectionPool)}
1126: * before the thread is interrupted. */
1127: public boolean interruptedByConnectionPool = false;
1128: }
1129:
1130: /**
1131: * A thread for listening for HttpConnections reclaimed by the garbage
1132: * collector.
1133: */
1134: private static class ReferenceQueueThread extends Thread {
1135:
1136: private volatile boolean shutdown = false;
1137:
1138: /**
1139: * Create an instance and make this a daemon thread.
1140: */
1141: public ReferenceQueueThread() {
1142: setDaemon(true);
1143: setName("MultiThreadedHttpConnectionManager cleanup");
1144: }
1145:
1146: public void shutdown() {
1147: this .shutdown = true;
1148: this .interrupt();
1149: }
1150:
1151: /**
1152: * Handles cleaning up for the given connection reference.
1153: *
1154: * @param ref the reference to clean up
1155: */
1156: private void handleReference(Reference ref) {
1157:
1158: ConnectionSource source = null;
1159:
1160: synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
1161: source = (ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE
1162: .remove(ref);
1163: }
1164: // only clean up for this reference if it is still associated with
1165: // a ConnectionSource
1166: if (source != null) {
1167: if (LOG.isDebugEnabled()) {
1168: LOG
1169: .debug("Connection reclaimed by garbage collector, hostConfig="
1170: + source.hostConfiguration);
1171: }
1172:
1173: source.connectionPool
1174: .handleLostConnection(source.hostConfiguration);
1175: }
1176: }
1177:
1178: /**
1179: * Start execution.
1180: */
1181: public void run() {
1182: while (!shutdown) {
1183: try {
1184: // remove the next reference and process it
1185: Reference ref = REFERENCE_QUEUE.remove();
1186: if (ref != null) {
1187: handleReference(ref);
1188: }
1189: } catch (InterruptedException e) {
1190: LOG.debug("ReferenceQueueThread interrupted", e);
1191: }
1192: }
1193: }
1194:
1195: }
1196:
1197: /**
1198: * A connection that keeps a reference to itself.
1199: */
1200: private static class HttpConnectionWithReference extends
1201: HttpConnection {
1202:
1203: public WeakReference reference = new WeakReference(this ,
1204: REFERENCE_QUEUE);
1205:
1206: /**
1207: * @param hostConfiguration
1208: */
1209: public HttpConnectionWithReference(
1210: HostConfiguration hostConfiguration) {
1211: super (hostConfiguration);
1212: }
1213:
1214: }
1215:
1216: /**
1217: * An HttpConnection wrapper that ensures a connection cannot be used
1218: * once released.
1219: */
1220: private static class HttpConnectionAdapter extends HttpConnection {
1221:
1222: // the wrapped connection
1223: private HttpConnection wrappedConnection;
1224:
1225: /**
1226: * Creates a new HttpConnectionAdapter.
1227: * @param connection the connection to be wrapped
1228: */
1229: public HttpConnectionAdapter(HttpConnection connection) {
1230: super (connection.getHost(), connection.getPort(),
1231: connection.getProtocol());
1232: this .wrappedConnection = connection;
1233: }
1234:
1235: /**
1236: * Tests if the wrapped connection is still available.
1237: * @return boolean
1238: */
1239: protected boolean hasConnection() {
1240: return wrappedConnection != null;
1241: }
1242:
1243: /**
1244: * @return HttpConnection
1245: */
1246: HttpConnection getWrappedConnection() {
1247: return wrappedConnection;
1248: }
1249:
1250: public void close() {
1251: if (hasConnection()) {
1252: wrappedConnection.close();
1253: } else {
1254: // do nothing
1255: }
1256: }
1257:
1258: public InetAddress getLocalAddress() {
1259: if (hasConnection()) {
1260: return wrappedConnection.getLocalAddress();
1261: } else {
1262: return null;
1263: }
1264: }
1265:
1266: /**
1267: * @deprecated
1268: */
1269: public boolean isStaleCheckingEnabled() {
1270: if (hasConnection()) {
1271: return wrappedConnection.isStaleCheckingEnabled();
1272: } else {
1273: return false;
1274: }
1275: }
1276:
1277: public void setLocalAddress(InetAddress localAddress) {
1278: if (hasConnection()) {
1279: wrappedConnection.setLocalAddress(localAddress);
1280: } else {
1281: throw new IllegalStateException(
1282: "Connection has been released");
1283: }
1284: }
1285:
1286: /**
1287: * @deprecated
1288: */
1289: public void setStaleCheckingEnabled(boolean staleCheckEnabled) {
1290: if (hasConnection()) {
1291: wrappedConnection
1292: .setStaleCheckingEnabled(staleCheckEnabled);
1293: } else {
1294: throw new IllegalStateException(
1295: "Connection has been released");
1296: }
1297: }
1298:
1299: public String getHost() {
1300: if (hasConnection()) {
1301: return wrappedConnection.getHost();
1302: } else {
1303: return null;
1304: }
1305: }
1306:
1307: public HttpConnectionManager getHttpConnectionManager() {
1308: if (hasConnection()) {
1309: return wrappedConnection.getHttpConnectionManager();
1310: } else {
1311: return null;
1312: }
1313: }
1314:
1315: public InputStream getLastResponseInputStream() {
1316: if (hasConnection()) {
1317: return wrappedConnection.getLastResponseInputStream();
1318: } else {
1319: return null;
1320: }
1321: }
1322:
1323: public int getPort() {
1324: if (hasConnection()) {
1325: return wrappedConnection.getPort();
1326: } else {
1327: return -1;
1328: }
1329: }
1330:
1331: public Protocol getProtocol() {
1332: if (hasConnection()) {
1333: return wrappedConnection.getProtocol();
1334: } else {
1335: return null;
1336: }
1337: }
1338:
1339: public String getProxyHost() {
1340: if (hasConnection()) {
1341: return wrappedConnection.getProxyHost();
1342: } else {
1343: return null;
1344: }
1345: }
1346:
1347: public int getProxyPort() {
1348: if (hasConnection()) {
1349: return wrappedConnection.getProxyPort();
1350: } else {
1351: return -1;
1352: }
1353: }
1354:
1355: public OutputStream getRequestOutputStream()
1356: throws IOException, IllegalStateException {
1357: if (hasConnection()) {
1358: return wrappedConnection.getRequestOutputStream();
1359: } else {
1360: return null;
1361: }
1362: }
1363:
1364: public InputStream getResponseInputStream() throws IOException,
1365: IllegalStateException {
1366: if (hasConnection()) {
1367: return wrappedConnection.getResponseInputStream();
1368: } else {
1369: return null;
1370: }
1371: }
1372:
1373: public boolean isOpen() {
1374: if (hasConnection()) {
1375: return wrappedConnection.isOpen();
1376: } else {
1377: return false;
1378: }
1379: }
1380:
1381: public boolean closeIfStale() throws IOException {
1382: if (hasConnection()) {
1383: return wrappedConnection.closeIfStale();
1384: } else {
1385: return false;
1386: }
1387: }
1388:
1389: public boolean isProxied() {
1390: if (hasConnection()) {
1391: return wrappedConnection.isProxied();
1392: } else {
1393: return false;
1394: }
1395: }
1396:
1397: public boolean isResponseAvailable() throws IOException {
1398: if (hasConnection()) {
1399: return wrappedConnection.isResponseAvailable();
1400: } else {
1401: return false;
1402: }
1403: }
1404:
1405: public boolean isResponseAvailable(int timeout)
1406: throws IOException {
1407: if (hasConnection()) {
1408: return wrappedConnection.isResponseAvailable(timeout);
1409: } else {
1410: return false;
1411: }
1412: }
1413:
1414: public boolean isSecure() {
1415: if (hasConnection()) {
1416: return wrappedConnection.isSecure();
1417: } else {
1418: return false;
1419: }
1420: }
1421:
1422: public boolean isTransparent() {
1423: if (hasConnection()) {
1424: return wrappedConnection.isTransparent();
1425: } else {
1426: return false;
1427: }
1428: }
1429:
1430: public void open() throws IOException {
1431: if (hasConnection()) {
1432: wrappedConnection.open();
1433: } else {
1434: throw new IllegalStateException(
1435: "Connection has been released");
1436: }
1437: }
1438:
1439: /**
1440: * @deprecated
1441: */
1442: public void print(String data) throws IOException,
1443: IllegalStateException {
1444: if (hasConnection()) {
1445: wrappedConnection.print(data);
1446: } else {
1447: throw new IllegalStateException(
1448: "Connection has been released");
1449: }
1450: }
1451:
1452: public void printLine() throws IOException,
1453: IllegalStateException {
1454: if (hasConnection()) {
1455: wrappedConnection.printLine();
1456: } else {
1457: throw new IllegalStateException(
1458: "Connection has been released");
1459: }
1460: }
1461:
1462: /**
1463: * @deprecated
1464: */
1465: public void printLine(String data) throws IOException,
1466: IllegalStateException {
1467: if (hasConnection()) {
1468: wrappedConnection.printLine(data);
1469: } else {
1470: throw new IllegalStateException(
1471: "Connection has been released");
1472: }
1473: }
1474:
1475: /**
1476: * @deprecated
1477: */
1478: public String readLine() throws IOException,
1479: IllegalStateException {
1480: if (hasConnection()) {
1481: return wrappedConnection.readLine();
1482: } else {
1483: throw new IllegalStateException(
1484: "Connection has been released");
1485: }
1486: }
1487:
1488: public String readLine(String charset) throws IOException,
1489: IllegalStateException {
1490: if (hasConnection()) {
1491: return wrappedConnection.readLine(charset);
1492: } else {
1493: throw new IllegalStateException(
1494: "Connection has been released");
1495: }
1496: }
1497:
1498: public void releaseConnection() {
1499: if (!isLocked() && hasConnection()) {
1500: HttpConnection wrappedConnection = this .wrappedConnection;
1501: this .wrappedConnection = null;
1502: wrappedConnection.releaseConnection();
1503: } else {
1504: // do nothing
1505: }
1506: }
1507:
1508: /**
1509: * @deprecated
1510: */
1511: public void setConnectionTimeout(int timeout) {
1512: if (hasConnection()) {
1513: wrappedConnection.setConnectionTimeout(timeout);
1514: } else {
1515: // do nothing
1516: }
1517: }
1518:
1519: public void setHost(String host) throws IllegalStateException {
1520: if (hasConnection()) {
1521: wrappedConnection.setHost(host);
1522: } else {
1523: // do nothing
1524: }
1525: }
1526:
1527: public void setHttpConnectionManager(
1528: HttpConnectionManager httpConnectionManager) {
1529: if (hasConnection()) {
1530: wrappedConnection
1531: .setHttpConnectionManager(httpConnectionManager);
1532: } else {
1533: // do nothing
1534: }
1535: }
1536:
1537: public void setLastResponseInputStream(InputStream inStream) {
1538: if (hasConnection()) {
1539: wrappedConnection.setLastResponseInputStream(inStream);
1540: } else {
1541: // do nothing
1542: }
1543: }
1544:
1545: public void setPort(int port) throws IllegalStateException {
1546: if (hasConnection()) {
1547: wrappedConnection.setPort(port);
1548: } else {
1549: // do nothing
1550: }
1551: }
1552:
1553: public void setProtocol(Protocol protocol) {
1554: if (hasConnection()) {
1555: wrappedConnection.setProtocol(protocol);
1556: } else {
1557: // do nothing
1558: }
1559: }
1560:
1561: public void setProxyHost(String host)
1562: throws IllegalStateException {
1563: if (hasConnection()) {
1564: wrappedConnection.setProxyHost(host);
1565: } else {
1566: // do nothing
1567: }
1568: }
1569:
1570: public void setProxyPort(int port) throws IllegalStateException {
1571: if (hasConnection()) {
1572: wrappedConnection.setProxyPort(port);
1573: } else {
1574: // do nothing
1575: }
1576: }
1577:
1578: /**
1579: * @deprecated
1580: */
1581: public void setSoTimeout(int timeout) throws SocketException,
1582: IllegalStateException {
1583: if (hasConnection()) {
1584: wrappedConnection.setSoTimeout(timeout);
1585: } else {
1586: // do nothing
1587: }
1588: }
1589:
1590: /**
1591: * @deprecated
1592: */
1593: public void shutdownOutput() {
1594: if (hasConnection()) {
1595: wrappedConnection.shutdownOutput();
1596: } else {
1597: // do nothing
1598: }
1599: }
1600:
1601: public void tunnelCreated() throws IllegalStateException,
1602: IOException {
1603: if (hasConnection()) {
1604: wrappedConnection.tunnelCreated();
1605: } else {
1606: // do nothing
1607: }
1608: }
1609:
1610: public void write(byte[] data, int offset, int length)
1611: throws IOException, IllegalStateException {
1612: if (hasConnection()) {
1613: wrappedConnection.write(data, offset, length);
1614: } else {
1615: throw new IllegalStateException(
1616: "Connection has been released");
1617: }
1618: }
1619:
1620: public void write(byte[] data) throws IOException,
1621: IllegalStateException {
1622: if (hasConnection()) {
1623: wrappedConnection.write(data);
1624: } else {
1625: throw new IllegalStateException(
1626: "Connection has been released");
1627: }
1628: }
1629:
1630: public void writeLine() throws IOException,
1631: IllegalStateException {
1632: if (hasConnection()) {
1633: wrappedConnection.writeLine();
1634: } else {
1635: throw new IllegalStateException(
1636: "Connection has been released");
1637: }
1638: }
1639:
1640: public void writeLine(byte[] data) throws IOException,
1641: IllegalStateException {
1642: if (hasConnection()) {
1643: wrappedConnection.writeLine(data);
1644: } else {
1645: throw new IllegalStateException(
1646: "Connection has been released");
1647: }
1648: }
1649:
1650: public void flushRequestOutputStream() throws IOException {
1651: if (hasConnection()) {
1652: wrappedConnection.flushRequestOutputStream();
1653: } else {
1654: throw new IllegalStateException(
1655: "Connection has been released");
1656: }
1657: }
1658:
1659: /**
1660: * @deprecated
1661: */
1662: public int getSoTimeout() throws SocketException {
1663: if (hasConnection()) {
1664: return wrappedConnection.getSoTimeout();
1665: } else {
1666: throw new IllegalStateException(
1667: "Connection has been released");
1668: }
1669: }
1670:
1671: /**
1672: * @deprecated
1673: */
1674: public String getVirtualHost() {
1675: if (hasConnection()) {
1676: return wrappedConnection.getVirtualHost();
1677: } else {
1678: throw new IllegalStateException(
1679: "Connection has been released");
1680: }
1681: }
1682:
1683: /**
1684: * @deprecated
1685: */
1686: public void setVirtualHost(String host)
1687: throws IllegalStateException {
1688: if (hasConnection()) {
1689: wrappedConnection.setVirtualHost(host);
1690: } else {
1691: throw new IllegalStateException(
1692: "Connection has been released");
1693: }
1694: }
1695:
1696: public int getSendBufferSize() throws SocketException {
1697: if (hasConnection()) {
1698: return wrappedConnection.getSendBufferSize();
1699: } else {
1700: throw new IllegalStateException(
1701: "Connection has been released");
1702: }
1703: }
1704:
1705: /**
1706: * @deprecated
1707: */
1708: public void setSendBufferSize(int sendBufferSize)
1709: throws SocketException {
1710: if (hasConnection()) {
1711: wrappedConnection.setSendBufferSize(sendBufferSize);
1712: } else {
1713: throw new IllegalStateException(
1714: "Connection has been released");
1715: }
1716: }
1717:
1718: public HttpConnectionParams getParams() {
1719: if (hasConnection()) {
1720: return wrappedConnection.getParams();
1721: } else {
1722: throw new IllegalStateException(
1723: "Connection has been released");
1724: }
1725: }
1726:
1727: public void setParams(final HttpConnectionParams params) {
1728: if (hasConnection()) {
1729: wrappedConnection.setParams(params);
1730: } else {
1731: throw new IllegalStateException(
1732: "Connection has been released");
1733: }
1734: }
1735:
1736: /* (non-Javadoc)
1737: * @see org.apache.commons.httpclient.HttpConnection#print(java.lang.String, java.lang.String)
1738: */
1739: public void print(String data, String charset)
1740: throws IOException, IllegalStateException {
1741: if (hasConnection()) {
1742: wrappedConnection.print(data, charset);
1743: } else {
1744: throw new IllegalStateException(
1745: "Connection has been released");
1746: }
1747: }
1748:
1749: /* (non-Javadoc)
1750: * @see org.apache.commons.httpclient.HttpConnection#printLine(java.lang.String, java.lang.String)
1751: */
1752: public void printLine(String data, String charset)
1753: throws IOException, IllegalStateException {
1754: if (hasConnection()) {
1755: wrappedConnection.printLine(data, charset);
1756: } else {
1757: throw new IllegalStateException(
1758: "Connection has been released");
1759: }
1760: }
1761:
1762: /* (non-Javadoc)
1763: * @see org.apache.commons.httpclient.HttpConnection#setSocketTimeout(int)
1764: */
1765: public void setSocketTimeout(int timeout)
1766: throws SocketException, IllegalStateException {
1767: if (hasConnection()) {
1768: wrappedConnection.setSocketTimeout(timeout);
1769: } else {
1770: throw new IllegalStateException(
1771: "Connection has been released");
1772: }
1773: }
1774:
1775: }
1776:
1777: }
|