Home » commons-httpclient-3.1-src » org.apache.commons » httpclient » [javadoc | source]

    1   /*
    2    * $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 $
    3    * $Revision: 564906 $
    4    * $Date: 2007-08-11 14:27:18 +0200 (Sat, 11 Aug 2007) $
    5    *
    6    * ====================================================================
    7    *
    8    *  Licensed to the Apache Software Foundation (ASF) under one or more
    9    *  contributor license agreements.  See the NOTICE file distributed with
   10    *  this work for additional information regarding copyright ownership.
   11    *  The ASF licenses this file to You under the Apache License, Version 2.0
   12    *  (the "License"); you may not use this file except in compliance with
   13    *  the License.  You may obtain a copy of the License at
   14    *
   15    *      http://www.apache.org/licenses/LICENSE-2.0
   16    *
   17    *  Unless required by applicable law or agreed to in writing, software
   18    *  distributed under the License is distributed on an "AS IS" BASIS,
   19    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   20    *  See the License for the specific language governing permissions and
   21    *  limitations under the License.
   22    * ====================================================================
   23    *
   24    * This software consists of voluntary contributions made by many
   25    * individuals on behalf of the Apache Software Foundation.  For more
   26    * information on the Apache Software Foundation, please see
   27    * <http://www.apache.org/>.
   28    *
   29    */
   30   
   31   package org.apache.commons.httpclient;
   32   
   33   import java.io.IOException;
   34   import java.io.InputStream;
   35   import java.io.OutputStream;
   36   import java.lang.ref.Reference;
   37   import java.lang.ref.ReferenceQueue;
   38   import java.lang.ref.WeakReference;
   39   import java.net.InetAddress;
   40   import java.net.SocketException;
   41   import java.util.ArrayList;
   42   import java.util.HashMap;
   43   import java.util.Iterator;
   44   import java.util.LinkedList;
   45   import java.util.Map;
   46   import java.util.WeakHashMap;
   47   
   48   import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
   49   import org.apache.commons.httpclient.params.HttpConnectionParams;
   50   import org.apache.commons.httpclient.protocol.Protocol;
   51   import org.apache.commons.httpclient.util.IdleConnectionHandler;
   52   import org.apache.commons.logging.Log;
   53   import org.apache.commons.logging.LogFactory;
   54   
   55   /**
   56    * Manages a set of HttpConnections for various HostConfigurations.
   57    *
   58    * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
   59    * @author Eric Johnson
   60    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
   61    * @author Carl A. Dunham
   62    *
   63    * @since 2.0
   64    */
   65   public class MultiThreadedHttpConnectionManager implements HttpConnectionManager {
   66   
   67       // -------------------------------------------------------- Class Variables
   68   
   69       /** Log object for this class. */
   70       private static final Log LOG = LogFactory.getLog(MultiThreadedHttpConnectionManager.class);
   71   
   72       /** The default maximum number of connections allowed per host */
   73       public static final int DEFAULT_MAX_HOST_CONNECTIONS = 2;   // Per RFC 2616 sec 8.1.4
   74   
   75       /** The default maximum number of connections allowed overall */
   76       public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20;
   77   
   78       /**
   79        * A mapping from Reference to ConnectionSource.  Used to reclaim resources when connections
   80        * are lost to the garbage collector.
   81        */
   82       private static final Map REFERENCE_TO_CONNECTION_SOURCE = new HashMap();
   83       
   84       /**
   85        * The reference queue used to track when HttpConnections are lost to the
   86        * garbage collector
   87        */
   88       private static final ReferenceQueue REFERENCE_QUEUE = new ReferenceQueue();    
   89   
   90       /**
   91        * The thread responsible for handling lost connections.
   92        */
   93       private static ReferenceQueueThread REFERENCE_QUEUE_THREAD;
   94       
   95       /**
   96        * Holds references to all active instances of this class.
   97        */    
   98       private static WeakHashMap ALL_CONNECTION_MANAGERS = new WeakHashMap();
   99       
  100   
  101       // ---------------------------------------------------------- Class Methods
  102   
  103       /**
  104        * Shuts down and cleans up resources used by all instances of 
  105        * MultiThreadedHttpConnectionManager. All static resources are released, all threads are 
  106        * stopped, and {@link #shutdown()} is called on all live instances of 
  107        * MultiThreadedHttpConnectionManager.
  108        *
  109        * @see #shutdown()
  110        */
  111       public static void shutdownAll() {
  112   
  113           synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
  114               // shutdown all connection managers
  115               synchronized (ALL_CONNECTION_MANAGERS) {
  116                   // Don't use an iterator here. Iterators on WeakHashMap can
  117                   // get ConcurrentModificationException on garbage collection.
  118                   MultiThreadedHttpConnectionManager[]
  119                       connManagers = (MultiThreadedHttpConnectionManager[])
  120                       ALL_CONNECTION_MANAGERS.keySet().toArray(
  121                           new MultiThreadedHttpConnectionManager
  122                               [ALL_CONNECTION_MANAGERS.size()]
  123                           );
  124   
  125                   // The map may shrink after size() is called, or some entry
  126                   // may get GCed while the array is built, so expect null.
  127                   for (int i=0; i<connManagers.length; i++) {
  128                       if (connManagers[i] != null)
  129                           connManagers[i].shutdown();
  130                   }
  131               }
  132               
  133               // shutdown static resources
  134               if (REFERENCE_QUEUE_THREAD != null) {
  135                   REFERENCE_QUEUE_THREAD.shutdown();
  136                   REFERENCE_QUEUE_THREAD = null;
  137               }
  138               REFERENCE_TO_CONNECTION_SOURCE.clear();
  139           }        
  140       }    
  141       
  142       /**
  143        * Stores the reference to the given connection along with the host config and connection pool.  
  144        * These values will be used to reclaim resources if the connection is lost to the garbage 
  145        * collector.  This method should be called before a connection is released from the connection 
  146        * manager.
  147        * 
  148        * <p>A static reference to the connection manager will also be stored.  To ensure that
  149        * the connection manager can be GCed {@link #removeReferenceToConnection(HttpConnection)}
  150        * should be called for all connections that the connection manager is storing a reference
  151        * to.</p>
  152        * 
  153        * @param connection the connection to create a reference for
  154        * @param hostConfiguration the connection's host config
  155        * @param connectionPool the connection pool that created the connection
  156        * 
  157        * @see #removeReferenceToConnection(HttpConnection)
  158        */
  159       private static void storeReferenceToConnection(
  160           HttpConnectionWithReference connection,
  161           HostConfiguration hostConfiguration,
  162           ConnectionPool connectionPool
  163       ) {
  164           
  165           ConnectionSource source = new ConnectionSource();
  166           source.connectionPool = connectionPool;
  167           source.hostConfiguration = hostConfiguration;
  168           
  169           synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
  170               
  171               // start the reference queue thread if needed
  172               if (REFERENCE_QUEUE_THREAD == null) {
  173                   REFERENCE_QUEUE_THREAD = new ReferenceQueueThread();
  174                   REFERENCE_QUEUE_THREAD.start();
  175               }
  176               
  177               REFERENCE_TO_CONNECTION_SOURCE.put(
  178                   connection.reference,
  179                   source
  180               );
  181           }
  182       }
  183       
  184       /**
  185        * Closes and releases all connections currently checked out of the given connection pool.
  186        * @param connectionPool the connection pool to shutdown the connections for
  187        */
  188       private static void shutdownCheckedOutConnections(ConnectionPool connectionPool) {
  189   
  190           // keep a list of the connections to be closed
  191           ArrayList connectionsToClose = new ArrayList(); 
  192           
  193           synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
  194               
  195               Iterator referenceIter = REFERENCE_TO_CONNECTION_SOURCE.keySet().iterator();
  196               while (referenceIter.hasNext()) {
  197                   Reference ref = (Reference) referenceIter.next();
  198                   ConnectionSource source = 
  199                       (ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE.get(ref);
  200                   if (source.connectionPool == connectionPool) {
  201                       referenceIter.remove();
  202                       HttpConnection connection = (HttpConnection) ref.get();
  203                       if (connection != null) {
  204                           connectionsToClose.add(connection);
  205                       }
  206                   }
  207               }
  208           }
  209   
  210           // close and release the connections outside of the synchronized block to
  211           // avoid holding the lock for too long
  212           for (Iterator i = connectionsToClose.iterator(); i.hasNext();) {
  213               HttpConnection connection = (HttpConnection) i.next();
  214               connection.close();
  215               // remove the reference to the connection manager. this ensures
  216               // that the we don't accidentally end up here again
  217               connection.setHttpConnectionManager(null);
  218               connection.releaseConnection();
  219           }
  220       }
  221       
  222       /**
  223        * Removes the reference being stored for the given connection.  This method should be called
  224        * when the connection manager again has a direct reference to the connection.
  225        * 
  226        * @param connection the connection to remove the reference for
  227        * 
  228        * @see #storeReferenceToConnection(HttpConnection, HostConfiguration, ConnectionPool)
  229        */
  230       private static void removeReferenceToConnection(HttpConnectionWithReference connection) {
  231           
  232           synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
  233               REFERENCE_TO_CONNECTION_SOURCE.remove(connection.reference);
  234           }
  235       }    
  236       
  237   
  238       // ----------------------------------------------------- Instance Variables
  239   
  240       /**
  241        * Collection of parameters associated with this connection manager.
  242        */
  243       private HttpConnectionManagerParams params = new HttpConnectionManagerParams(); 
  244   
  245       /** Connection Pool */
  246       private ConnectionPool connectionPool;
  247   
  248       private volatile boolean shutdown = false;
  249       
  250   
  251       // ----------------------------------------------------------- Constructors
  252   
  253       /**
  254        * No-args constructor
  255        */
  256       public MultiThreadedHttpConnectionManager() {
  257           this.connectionPool = new ConnectionPool();
  258           synchronized(ALL_CONNECTION_MANAGERS) {
  259               ALL_CONNECTION_MANAGERS.put(this, null);
  260           }
  261       }
  262   
  263   
  264       // ------------------------------------------------------- Instance Methods
  265   
  266       /**
  267        * Shuts down the connection manager and releases all resources.  All connections associated 
  268        * with this class will be closed and released. 
  269        * 
  270        * <p>The connection manager can no longer be used once shut down.  
  271        * 
  272        * <p>Calling this method more than once will have no effect.
  273        */
  274       public synchronized void shutdown() {
  275           synchronized (connectionPool) {
  276               if (!shutdown) {
  277                   shutdown = true;
  278                   connectionPool.shutdown();
  279               }
  280           }
  281       }
  282       
  283       /**
  284        * Gets the staleCheckingEnabled value to be set on HttpConnections that are created.
  285        * 
  286        * @return <code>true</code> if stale checking will be enabled on HttpConnections
  287        * 
  288        * @see HttpConnection#isStaleCheckingEnabled()
  289        * 
  290        * @deprecated Use {@link HttpConnectionManagerParams#isStaleCheckingEnabled()},
  291        * {@link HttpConnectionManager#getParams()}.
  292        */
  293       public boolean isConnectionStaleCheckingEnabled() {
  294           return this.params.isStaleCheckingEnabled();
  295       }
  296   
  297       /**
  298        * Sets the staleCheckingEnabled value to be set on HttpConnections that are created.
  299        * 
  300        * @param connectionStaleCheckingEnabled <code>true</code> if stale checking will be enabled 
  301        * on HttpConnections
  302        * 
  303        * @see HttpConnection#setStaleCheckingEnabled(boolean)
  304        * 
  305        * @deprecated Use {@link HttpConnectionManagerParams#setStaleCheckingEnabled(boolean)},
  306        * {@link HttpConnectionManager#getParams()}.
  307        */
  308       public void setConnectionStaleCheckingEnabled(boolean connectionStaleCheckingEnabled) {
  309           this.params.setStaleCheckingEnabled(connectionStaleCheckingEnabled);
  310       }
  311   
  312       /**
  313        * Sets the maximum number of connections allowed for a given
  314        * HostConfiguration. Per RFC 2616 section 8.1.4, this value defaults to 2.
  315        *
  316        * @param maxHostConnections the number of connections allowed for each
  317        * hostConfiguration
  318        * 
  319        * @deprecated Use {@link HttpConnectionManagerParams#setDefaultMaxConnectionsPerHost(int)},
  320        * {@link HttpConnectionManager#getParams()}.
  321        */
  322       public void setMaxConnectionsPerHost(int maxHostConnections) {
  323           this.params.setDefaultMaxConnectionsPerHost(maxHostConnections);
  324       }
  325   
  326       /**
  327        * Gets the maximum number of connections allowed for a given
  328        * hostConfiguration.
  329        *
  330        * @return The maximum number of connections allowed for a given
  331        * hostConfiguration.
  332        * 
  333        * @deprecated Use {@link HttpConnectionManagerParams#getDefaultMaxConnectionsPerHost()},
  334        * {@link HttpConnectionManager#getParams()}.
  335        */
  336       public int getMaxConnectionsPerHost() {
  337           return this.params.getDefaultMaxConnectionsPerHost();
  338       }
  339   
  340       /**
  341        * Sets the maximum number of connections allowed for this connection manager.
  342        *
  343        * @param maxTotalConnections the maximum number of connections allowed
  344        * 
  345        * @deprecated Use {@link HttpConnectionManagerParams#setMaxTotalConnections(int)},
  346        * {@link HttpConnectionManager#getParams()}.
  347        */
  348       public void setMaxTotalConnections(int maxTotalConnections) {
  349           this.params.setMaxTotalConnections(maxTotalConnections);
  350       }
  351   
  352       /**
  353        * Gets the maximum number of connections allowed for this connection manager.
  354        *
  355        * @return The maximum number of connections allowed
  356        * 
  357        * @deprecated Use {@link HttpConnectionManagerParams#getMaxTotalConnections()},
  358        * {@link HttpConnectionManager#getParams()}.
  359        */
  360       public int getMaxTotalConnections() {
  361           return this.params.getMaxTotalConnections();
  362       }
  363   
  364       /**
  365        * @see HttpConnectionManager#getConnection(HostConfiguration)
  366        */
  367       public HttpConnection getConnection(HostConfiguration hostConfiguration) {
  368   
  369           while (true) {
  370               try {
  371                   return getConnectionWithTimeout(hostConfiguration, 0);
  372               } catch (ConnectionPoolTimeoutException e) {
  373                   // we'll go ahead and log this, but it should never happen. HttpExceptions
  374                   // are only thrown when the timeout occurs and since we have no timeout
  375                   // it should never happen.
  376                   LOG.debug(
  377                       "Unexpected exception while waiting for connection",
  378                       e
  379                   );
  380               }
  381           }
  382       }
  383   
  384       /**
  385        * Gets a connection or waits if one is not available.  A connection is
  386        * available if one exists that is not being used or if fewer than
  387        * maxHostConnections have been created in the connectionPool, and fewer
  388        * than maxTotalConnections have been created in all connectionPools.
  389        *
  390        * @param hostConfiguration The host configuration specifying the connection
  391        *        details.
  392        * @param timeout the number of milliseconds to wait for a connection, 0 to
  393        * wait indefinitely
  394        *
  395        * @return HttpConnection an available connection
  396        *
  397        * @throws HttpException if a connection does not become available in
  398        * 'timeout' milliseconds
  399        * 
  400        * @since 3.0
  401        */
  402       public HttpConnection getConnectionWithTimeout(HostConfiguration hostConfiguration, 
  403           long timeout) throws ConnectionPoolTimeoutException {
  404   
  405           LOG.trace("enter HttpConnectionManager.getConnectionWithTimeout(HostConfiguration, long)");
  406   
  407           if (hostConfiguration == null) {
  408               throw new IllegalArgumentException("hostConfiguration is null");
  409           }
  410   
  411           if (LOG.isDebugEnabled()) {
  412               LOG.debug("HttpConnectionManager.getConnection:  config = "
  413                   + hostConfiguration + ", timeout = " + timeout);
  414           }
  415   
  416           final HttpConnection conn = doGetConnection(hostConfiguration, timeout);
  417   
  418           // wrap the connection in an adapter so we can ensure it is used 
  419           // only once
  420           return new HttpConnectionAdapter(conn);
  421       }
  422   
  423       /**
  424        * @see HttpConnectionManager#getConnection(HostConfiguration, long)
  425        * 
  426        * @deprecated Use #getConnectionWithTimeout(HostConfiguration, long)
  427        */
  428       public HttpConnection getConnection(HostConfiguration hostConfiguration, 
  429           long timeout) throws HttpException {
  430   
  431           LOG.trace("enter HttpConnectionManager.getConnection(HostConfiguration, long)");
  432           try {
  433               return getConnectionWithTimeout(hostConfiguration, timeout);
  434           } catch(ConnectionPoolTimeoutException e) {
  435               throw new HttpException(e.getMessage());
  436           }
  437       }
  438   
  439       private HttpConnection doGetConnection(HostConfiguration hostConfiguration, 
  440           long timeout) throws ConnectionPoolTimeoutException {
  441   
  442           HttpConnection connection = null;
  443   
  444           int maxHostConnections = this.params.getMaxConnectionsPerHost(hostConfiguration);
  445           int maxTotalConnections = this.params.getMaxTotalConnections();
  446           
  447           synchronized (connectionPool) {
  448   
  449               // we clone the hostConfiguration
  450               // so that it cannot be changed once the connection has been retrieved
  451               hostConfiguration = new HostConfiguration(hostConfiguration);
  452               HostConnectionPool hostPool = connectionPool.getHostPool(hostConfiguration, true);
  453               WaitingThread waitingThread = null;
  454   
  455               boolean useTimeout = (timeout > 0);
  456               long timeToWait = timeout;
  457               long startWait = 0;
  458               long endWait = 0;
  459   
  460               while (connection == null) {
  461   
  462                   if (shutdown) {
  463                       throw new IllegalStateException("Connection factory has been shutdown.");
  464                   }
  465                   
  466                   // happen to have a free connection with the right specs
  467                   //
  468                   if (hostPool.freeConnections.size() > 0) {
  469                       connection = connectionPool.getFreeConnection(hostConfiguration);
  470   
  471                   // have room to make more
  472                   //
  473                   } else if ((hostPool.numConnections < maxHostConnections) 
  474                       && (connectionPool.numConnections < maxTotalConnections)) {
  475   
  476                       connection = connectionPool.createConnection(hostConfiguration);
  477   
  478                   // have room to add host connection, and there is at least one free
  479                   // connection that can be liberated to make overall room
  480                   //
  481                   } else if ((hostPool.numConnections < maxHostConnections) 
  482                       && (connectionPool.freeConnections.size() > 0)) {
  483   
  484                       connectionPool.deleteLeastUsedConnection();
  485                       connection = connectionPool.createConnection(hostConfiguration);
  486   
  487                   // otherwise, we have to wait for one of the above conditions to
  488                   // become true
  489                   //
  490                   } else {
  491                       // TODO: keep track of which hostConfigurations have waiting
  492                       // threads, so they avoid being sacrificed before necessary
  493   
  494                       try {
  495                           
  496                           if (useTimeout && timeToWait <= 0) {
  497                               throw new ConnectionPoolTimeoutException("Timeout waiting for connection");
  498                           }
  499                           
  500                           if (LOG.isDebugEnabled()) {
  501                               LOG.debug("Unable to get a connection, waiting..., hostConfig=" + hostConfiguration);
  502                           }
  503                           
  504                           if (waitingThread == null) {
  505                               waitingThread = new WaitingThread();
  506                               waitingThread.hostConnectionPool = hostPool;
  507                               waitingThread.thread = Thread.currentThread();
  508                           } else {
  509                               waitingThread.interruptedByConnectionPool = false;
  510                           }
  511                                       
  512                           if (useTimeout) {
  513                               startWait = System.currentTimeMillis();
  514                           }
  515                           
  516                           hostPool.waitingThreads.addLast(waitingThread);
  517                           connectionPool.waitingThreads.addLast(waitingThread);
  518                           connectionPool.wait(timeToWait);
  519                       } catch (InterruptedException e) {
  520                           if (!waitingThread.interruptedByConnectionPool) {
  521                               LOG.debug("Interrupted while waiting for connection", e);
  522                               throw new IllegalThreadStateException(
  523                                   "Interrupted while waiting in MultiThreadedHttpConnectionManager");
  524                           }
  525                           // Else, do nothing, we were interrupted by the connection pool
  526                           // and should now have a connection waiting for us, continue
  527                           // in the loop and let's get it.
  528                       } finally {
  529                           if (!waitingThread.interruptedByConnectionPool) {
  530                               // Either we timed out, experienced a "spurious wakeup", or were
  531                               // interrupted by an external thread.  Regardless we need to 
  532                               // cleanup for ourselves in the wait queue.
  533                               hostPool.waitingThreads.remove(waitingThread);
  534                               connectionPool.waitingThreads.remove(waitingThread);
  535                           }
  536                           
  537                           if (useTimeout) {
  538                               endWait = System.currentTimeMillis();
  539                               timeToWait -= (endWait - startWait);
  540                           }
  541                       }
  542                   }
  543               }
  544           }
  545           return connection;
  546       }
  547   
  548       /**
  549        * Gets the total number of pooled connections for the given host configuration.  This 
  550        * is the total number of connections that have been created and are still in use 
  551        * by this connection manager for the host configuration.  This value will
  552        * not exceed the {@link #getMaxConnectionsPerHost() maximum number of connections per
  553        * host}.
  554        * 
  555        * @param hostConfiguration The host configuration
  556        * @return The total number of pooled connections
  557        */
  558       public int getConnectionsInPool(HostConfiguration hostConfiguration) {
  559           synchronized (connectionPool) {
  560               HostConnectionPool hostPool = connectionPool.getHostPool(hostConfiguration, false);
  561               return (hostPool != null) ? hostPool.numConnections : 0;
  562           }
  563       }
  564   
  565       /**
  566        * Gets the total number of pooled connections.  This is the total number of 
  567        * connections that have been created and are still in use by this connection 
  568        * manager.  This value will not exceed the {@link #getMaxTotalConnections() 
  569        * maximum number of connections}.
  570        * 
  571        * @return the total number of pooled connections
  572        */
  573       public int getConnectionsInPool() {
  574           synchronized (connectionPool) {
  575               return connectionPool.numConnections;
  576           }
  577       }
  578       
  579       /**
  580        * Gets the number of connections in use for this configuration.
  581        *
  582        * @param hostConfiguration the key that connections are tracked on
  583        * @return the number of connections in use
  584        * 
  585        * @deprecated Use {@link #getConnectionsInPool(HostConfiguration)}
  586        */
  587       public int getConnectionsInUse(HostConfiguration hostConfiguration) {
  588           return getConnectionsInPool(hostConfiguration);
  589       }
  590   
  591       /**
  592        * Gets the total number of connections in use.
  593        * 
  594        * @return the total number of connections in use
  595        * 
  596        * @deprecated Use {@link #getConnectionsInPool()}
  597        */
  598       public int getConnectionsInUse() {
  599           return getConnectionsInPool();
  600       }
  601   
  602       /**
  603        * Deletes all closed connections.  Only connections currently owned by the connection
  604        * manager are processed.
  605        * 
  606        * @see HttpConnection#isOpen()
  607        * 
  608        * @since 3.0
  609        */
  610       public void deleteClosedConnections() {
  611           connectionPool.deleteClosedConnections();
  612       }
  613       
  614       /**
  615        * @since 3.0
  616        */
  617       public void closeIdleConnections(long idleTimeout) {
  618           connectionPool.closeIdleConnections(idleTimeout);
  619           deleteClosedConnections();
  620       }
  621       
  622       /**
  623        * Make the given HttpConnection available for use by other requests.
  624        * If another thread is blocked in getConnection() that could use this
  625        * connection, it will be woken up.
  626        *
  627        * @param conn the HttpConnection to make available.
  628        */
  629       public void releaseConnection(HttpConnection conn) {
  630           LOG.trace("enter HttpConnectionManager.releaseConnection(HttpConnection)");
  631   
  632           if (conn instanceof HttpConnectionAdapter) {
  633               // connections given out are wrapped in an HttpConnectionAdapter
  634               conn = ((HttpConnectionAdapter) conn).getWrappedConnection();
  635           } else {
  636               // this is okay, when an HttpConnectionAdapter is released
  637               // is releases the real connection
  638           }
  639   
  640           // make sure that the response has been read.
  641           SimpleHttpConnectionManager.finishLastResponse(conn);
  642   
  643           connectionPool.freeConnection(conn);
  644       }
  645   
  646       /**
  647        * Gets the host configuration for a connection.
  648        * @param conn the connection to get the configuration of
  649        * @return a new HostConfiguration
  650        */
  651       private HostConfiguration configurationForConnection(HttpConnection conn) {
  652   
  653           HostConfiguration connectionConfiguration = new HostConfiguration();
  654           
  655           connectionConfiguration.setHost(
  656               conn.getHost(), 
  657               conn.getPort(), 
  658               conn.getProtocol()
  659           );
  660           if (conn.getLocalAddress() != null) {
  661               connectionConfiguration.setLocalAddress(conn.getLocalAddress());
  662           }
  663           if (conn.getProxyHost() != null) {
  664               connectionConfiguration.setProxy(conn.getProxyHost(), conn.getProxyPort());
  665           }
  666   
  667           return connectionConfiguration;
  668       }
  669   
  670       /**
  671        * Returns {@link HttpConnectionManagerParams parameters} associated 
  672        * with this connection manager.
  673        * 
  674        * @since 3.0
  675        * 
  676        * @see HttpConnectionManagerParams
  677        */
  678       public HttpConnectionManagerParams getParams() {
  679           return this.params;
  680       }
  681   
  682       /**
  683        * Assigns {@link HttpConnectionManagerParams parameters} for this 
  684        * connection manager.
  685        * 
  686        * @since 3.0
  687        * 
  688        * @see HttpConnectionManagerParams
  689        */
  690       public void setParams(final HttpConnectionManagerParams params) {
  691           if (params == null) {
  692               throw new IllegalArgumentException("Parameters may not be null");
  693           }
  694           this.params = params;
  695       }
  696       
  697       /**
  698        * Global Connection Pool, including per-host pools
  699        */
  700       private class ConnectionPool {
  701           
  702           /** The list of free connections */
  703           private LinkedList freeConnections = new LinkedList();
  704   
  705           /** The list of WaitingThreads waiting for a connection */
  706           private LinkedList waitingThreads = new LinkedList();
  707   
  708           /**
  709            * Map where keys are {@link HostConfiguration}s and values are {@link
  710            * HostConnectionPool}s
  711            */
  712           private final Map mapHosts = new HashMap();
  713   
  714           private IdleConnectionHandler idleConnectionHandler = new IdleConnectionHandler();        
  715           
  716           /** The number of created connections */
  717           private int numConnections = 0;
  718   
  719           /**
  720            * Cleans up all connection pool resources.
  721            */
  722           public synchronized void shutdown() {
  723               
  724               // close all free connections
  725               Iterator iter = freeConnections.iterator();
  726               while (iter.hasNext()) {
  727                   HttpConnection conn = (HttpConnection) iter.next();
  728                   iter.remove();
  729                   conn.close();
  730               }
  731               
  732               // close all connections that have been checked out
  733               shutdownCheckedOutConnections(this);
  734               
  735               // interrupt all waiting threads
  736               iter = waitingThreads.iterator();
  737               while (iter.hasNext()) {
  738                   WaitingThread waiter = (WaitingThread) iter.next();
  739                   iter.remove();
  740                   waiter.interruptedByConnectionPool = true;
  741                   waiter.thread.interrupt();
  742               }
  743               
  744               // clear out map hosts
  745               mapHosts.clear();
  746               
  747               // remove all references to connections
  748               idleConnectionHandler.removeAll();
  749           }
  750           
  751           /**
  752            * Creates a new connection and returns it for use of the calling method.
  753            *
  754            * @param hostConfiguration the configuration for the connection
  755            * @return a new connection or <code>null</code> if none are available
  756            */
  757           public synchronized HttpConnection createConnection(HostConfiguration hostConfiguration) {
  758               HostConnectionPool hostPool = getHostPool(hostConfiguration, true);
  759               if (LOG.isDebugEnabled()) {
  760                   LOG.debug("Allocating new connection, hostConfig=" + hostConfiguration);
  761               }
  762               HttpConnectionWithReference connection = new HttpConnectionWithReference(
  763                       hostConfiguration);
  764               connection.getParams().setDefaults(MultiThreadedHttpConnectionManager.this.params);
  765               connection.setHttpConnectionManager(MultiThreadedHttpConnectionManager.this);
  766               numConnections++;
  767               hostPool.numConnections++;
  768       
  769               // store a reference to this connection so that it can be cleaned up
  770               // in the event it is not correctly released
  771               storeReferenceToConnection(connection, hostConfiguration, this);
  772               return connection;
  773           }
  774       
  775           /**
  776            * Handles cleaning up for a lost connection with the given config.  Decrements any 
  777            * connection counts and notifies waiting threads, if appropriate.
  778            * 
  779            * @param config the host configuration of the connection that was lost
  780            */
  781           public synchronized void handleLostConnection(HostConfiguration config) {
  782               HostConnectionPool hostPool = getHostPool(config, true);
  783               hostPool.numConnections--;
  784               if ((hostPool.numConnections == 0) &&
  785                   hostPool.waitingThreads.isEmpty()) {
  786   
  787                   mapHosts.remove(config);
  788               }
  789               
  790               numConnections--;
  791               notifyWaitingThread(config);
  792           }
  793   
  794           /**
  795            * Get the pool (list) of connections available for the given hostConfig.
  796            *
  797            * @param hostConfiguration the configuraton for the connection pool
  798            * @param create <code>true</code> to create a pool if not found,
  799            *               <code>false</code> to return <code>null</code>
  800            *
  801            * @return a pool (list) of connections available for the given config,
  802            *         or <code>null</code> if neither found nor created
  803            */
  804           public synchronized HostConnectionPool getHostPool(HostConfiguration hostConfiguration, boolean create) {
  805               LOG.trace("enter HttpConnectionManager.ConnectionPool.getHostPool(HostConfiguration)");
  806   
  807               // Look for a list of connections for the given config
  808               HostConnectionPool listConnections = (HostConnectionPool) 
  809                   mapHosts.get(hostConfiguration);
  810               if ((listConnections == null) && create) {
  811                   // First time for this config
  812                   listConnections = new HostConnectionPool();
  813                   listConnections.hostConfiguration = hostConfiguration;
  814                   mapHosts.put(hostConfiguration, listConnections);
  815               }
  816               
  817               return listConnections;
  818           }
  819   
  820           /**
  821            * If available, get a free connection for this host
  822            *
  823            * @param hostConfiguration the configuraton for the connection pool
  824            * @return an available connection for the given config
  825            */
  826           public synchronized HttpConnection getFreeConnection(HostConfiguration hostConfiguration) {
  827   
  828               HttpConnectionWithReference connection = null;
  829               
  830               HostConnectionPool hostPool = getHostPool(hostConfiguration, false);
  831   
  832               if ((hostPool != null) && (hostPool.freeConnections.size() > 0)) {
  833                   connection = (HttpConnectionWithReference) hostPool.freeConnections.removeLast();
  834                   freeConnections.remove(connection);
  835                   // store a reference to this connection so that it can be cleaned up
  836                   // in the event it is not correctly released
  837                   storeReferenceToConnection(connection, hostConfiguration, this);
  838                   if (LOG.isDebugEnabled()) {
  839                       LOG.debug("Getting free connection, hostConfig=" + hostConfiguration);
  840                   }
  841   
  842                   // remove the connection from the timeout handler
  843                   idleConnectionHandler.remove(connection);
  844               } else if (LOG.isDebugEnabled()) {
  845                   LOG.debug("There were no free connections to get, hostConfig=" 
  846                       + hostConfiguration);
  847               }
  848               return connection;
  849           }
  850           
  851           /**
  852            * Deletes all closed connections.
  853            */        
  854           public synchronized void deleteClosedConnections() {
  855               
  856               Iterator iter = freeConnections.iterator();
  857               
  858               while (iter.hasNext()) {
  859                   HttpConnection conn = (HttpConnection) iter.next();
  860                   if (!conn.isOpen()) {
  861                       iter.remove();
  862                       deleteConnection(conn);
  863                   }
  864               }
  865           }
  866   
  867           /**
  868            * Closes idle connections.
  869            * @param idleTimeout
  870            */
  871           public synchronized void closeIdleConnections(long idleTimeout) {
  872               idleConnectionHandler.closeIdleConnections(idleTimeout);
  873           }
  874           
  875           /**
  876            * Deletes the given connection.  This will remove all reference to the connection
  877            * so that it can be GCed.
  878            * 
  879            * <p><b>Note:</b> Does not remove the connection from the freeConnections list.  It
  880            * is assumed that the caller has already handled this case.</p>
  881            * 
  882            * @param connection The connection to delete
  883            */
  884           private synchronized void deleteConnection(HttpConnection connection) {
  885               
  886               HostConfiguration connectionConfiguration = configurationForConnection(connection);
  887   
  888               if (LOG.isDebugEnabled()) {
  889                   LOG.debug("Reclaiming connection, hostConfig=" + connectionConfiguration);
  890               }
  891   
  892               connection.close();
  893   
  894               HostConnectionPool hostPool = getHostPool(connectionConfiguration, true);
  895               
  896               hostPool.freeConnections.remove(connection);
  897               hostPool.numConnections--;
  898               numConnections--;
  899               if ((hostPool.numConnections == 0) &&
  900                   hostPool.waitingThreads.isEmpty()) {
  901   
  902                   mapHosts.remove(connectionConfiguration);
  903               }
  904               
  905               // remove the connection from the timeout handler
  906               idleConnectionHandler.remove(connection);            
  907           }
  908           
  909           /**
  910            * Close and delete an old, unused connection to make room for a new one.
  911            */
  912           public synchronized void deleteLeastUsedConnection() {
  913   
  914               HttpConnection connection = (HttpConnection) freeConnections.removeFirst();
  915   
  916               if (connection != null) {
  917                   deleteConnection(connection);
  918               } else if (LOG.isDebugEnabled()) {
  919                   LOG.debug("Attempted to reclaim an unused connection but there were none.");
  920               }
  921           }
  922   
  923           /**
  924            * Notifies a waiting thread that a connection for the given configuration is 
  925            * available.
  926            * @param configuration the host config to use for notifying
  927            * @see #notifyWaitingThread(HostConnectionPool)
  928            */
  929           public synchronized void notifyWaitingThread(HostConfiguration configuration) {
  930               notifyWaitingThread(getHostPool(configuration, true));
  931           }
  932   
  933           /**
  934            * Notifies a waiting thread that a connection for the given configuration is 
  935            * available.  This will wake a thread waiting in this host pool or if there is not
  936            * one a thread in the connection pool will be notified.
  937            * 
  938            * @param hostPool the host pool to use for notifying
  939            */
  940           public synchronized void notifyWaitingThread(HostConnectionPool hostPool) {
  941   
  942               // find the thread we are going to notify, we want to ensure that each
  943               // waiting thread is only interrupted once so we will remove it from 
  944               // all wait queues before interrupting it
  945               WaitingThread waitingThread = null;
  946                   
  947               if (hostPool.waitingThreads.size() > 0) {
  948                   if (LOG.isDebugEnabled()) {
  949                       LOG.debug("Notifying thread waiting on host pool, hostConfig=" 
  950                           + hostPool.hostConfiguration);
  951                   }
  952                   waitingThread = (WaitingThread) hostPool.waitingThreads.removeFirst();
  953                   waitingThreads.remove(waitingThread);
  954               } else if (waitingThreads.size() > 0) {
  955                   if (LOG.isDebugEnabled()) {
  956                       LOG.debug("No-one waiting on host pool, notifying next waiting thread.");
  957                   }
  958                   waitingThread = (WaitingThread) waitingThreads.removeFirst();
  959                   waitingThread.hostConnectionPool.waitingThreads.remove(waitingThread);
  960               } else if (LOG.isDebugEnabled()) {
  961                   LOG.debug("Notifying no-one, there are no waiting threads");
  962               }
  963                   
  964               if (waitingThread != null) {
  965                   waitingThread.interruptedByConnectionPool = true;
  966                   waitingThread.thread.interrupt();
  967               }
  968           }
  969   
  970           /**
  971            * Marks the given connection as free.
  972            * @param conn a connection that is no longer being used
  973            */
  974           public void freeConnection(HttpConnection conn) {
  975   
  976               HostConfiguration connectionConfiguration = configurationForConnection(conn);
  977   
  978               if (LOG.isDebugEnabled()) {
  979                   LOG.debug("Freeing connection, hostConfig=" + connectionConfiguration);
  980               }
  981   
  982               synchronized (this) {
  983                   
  984                   if (shutdown) {
  985                       // the connection manager has been shutdown, release the connection's
  986                       // resources and get out of here
  987                       conn.close();
  988                       return;
  989                   }
  990                   
  991                   HostConnectionPool hostPool = getHostPool(connectionConfiguration, true);
  992   
  993                   // Put the connect back in the available list and notify a waiter
  994                   hostPool.freeConnections.add(conn);
  995                   if (hostPool.numConnections == 0) {
  996                       // for some reason this connection pool didn't already exist
  997                       LOG.error("Host connection pool not found, hostConfig=" 
  998                                 + connectionConfiguration);
  999                       hostPool.numConnections = 1;
 1000                   }
 1001   
 1002                   freeConnections.add(conn);
 1003                   // we can remove the reference to this connection as we have control over
 1004                   // it again.  this also ensures that the connection manager can be GCed
 1005                   removeReferenceToConnection((HttpConnectionWithReference) conn);
 1006                   if (numConnections == 0) {
 1007                       // for some reason this connection pool didn't already exist
 1008                       LOG.error("Host connection pool not found, hostConfig=" 
 1009                                 + connectionConfiguration);
 1010                       numConnections = 1;
 1011                   }
 1012   
 1013                   // register the connection with the timeout handler
 1014                   idleConnectionHandler.add(conn);
 1015   
 1016                   notifyWaitingThread(hostPool);
 1017               }
 1018           }
 1019       }
 1020   
 1021       /**
 1022        * A simple struct-like class to combine the objects needed to release a connection's
 1023        * resources when claimed by the garbage collector.
 1024        */
 1025       private static class ConnectionSource {
 1026           
 1027           /** The connection pool that created the connection */
 1028           public ConnectionPool connectionPool;
 1029   
 1030           /** The connection's host configuration */
 1031           public HostConfiguration hostConfiguration;
 1032       }
 1033       
 1034       /**
 1035        * A simple struct-like class to combine the connection list and the count
 1036        * of created connections.
 1037        */
 1038       private static class HostConnectionPool {
 1039           /** The hostConfig this pool is for */
 1040           public HostConfiguration hostConfiguration;
 1041           
 1042           /** The list of free connections */
 1043           public LinkedList freeConnections = new LinkedList();
 1044           
 1045           /** The list of WaitingThreads for this host */
 1046           public LinkedList waitingThreads = new LinkedList();
 1047   
 1048           /** The number of created connections */
 1049           public int numConnections = 0;
 1050       }
 1051       
 1052       /**
 1053        * A simple struct-like class to combine the waiting thread and the connection 
 1054        * pool it is waiting on.
 1055        */
 1056       private static class WaitingThread {
 1057           /** The thread that is waiting for a connection */
 1058           public Thread thread;
 1059           
 1060           /** The connection pool the thread is waiting for */
 1061           public HostConnectionPool hostConnectionPool;
 1062           
 1063           /** Flag to indicate if the thread was interrupted by the ConnectionPool. Set
 1064            * to true inside {@link ConnectionPool#notifyWaitingThread(HostConnectionPool)} 
 1065            * before the thread is interrupted. */
 1066           public boolean interruptedByConnectionPool = false;
 1067       }
 1068   
 1069       /**
 1070        * A thread for listening for HttpConnections reclaimed by the garbage
 1071        * collector.
 1072        */
 1073       private static class ReferenceQueueThread extends Thread {
 1074   
 1075           private volatile boolean shutdown = false;
 1076           
 1077           /**
 1078            * Create an instance and make this a daemon thread.
 1079            */
 1080           public ReferenceQueueThread() {
 1081               setDaemon(true);
 1082               setName("MultiThreadedHttpConnectionManager cleanup");
 1083           }
 1084   
 1085           public void shutdown() {
 1086               this.shutdown = true;
 1087               this.interrupt();
 1088           }
 1089           
 1090           /**
 1091            * Handles cleaning up for the given connection reference.
 1092            * 
 1093            * @param ref the reference to clean up
 1094            */
 1095           private void handleReference(Reference ref) {
 1096               
 1097               ConnectionSource source = null;
 1098               
 1099               synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
 1100                   source = (ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE.remove(ref);
 1101               }
 1102               // only clean up for this reference if it is still associated with 
 1103               // a ConnectionSource
 1104               if (source != null) {
 1105                   if (LOG.isDebugEnabled()) {
 1106                       LOG.debug(
 1107                           "Connection reclaimed by garbage collector, hostConfig=" 
 1108                           + source.hostConfiguration);
 1109                   }
 1110                   
 1111                   source.connectionPool.handleLostConnection(source.hostConfiguration);
 1112               }
 1113           }
 1114   
 1115           /**
 1116            * Start execution.
 1117            */
 1118           public void run() {
 1119               while (!shutdown) {
 1120                   try {
 1121                       // remove the next reference and process it
 1122                       Reference ref = REFERENCE_QUEUE.remove();
 1123                       if (ref != null) {
 1124                           handleReference(ref);
 1125                       }
 1126                   } catch (InterruptedException e) {
 1127                       LOG.debug("ReferenceQueueThread interrupted", e);
 1128                   }
 1129               }
 1130           }
 1131   
 1132       }
 1133       
 1134       /**
 1135        * A connection that keeps a reference to itself.
 1136        */
 1137       private static class HttpConnectionWithReference extends HttpConnection {
 1138           
 1139           public WeakReference reference = new WeakReference(this, REFERENCE_QUEUE);
 1140           
 1141           /**
 1142            * @param hostConfiguration
 1143            */
 1144           public HttpConnectionWithReference(HostConfiguration hostConfiguration) {
 1145               super(hostConfiguration);
 1146           }
 1147   
 1148       }
 1149       
 1150       /**
 1151        * An HttpConnection wrapper that ensures a connection cannot be used
 1152        * once released.
 1153        */
 1154       private static class HttpConnectionAdapter extends HttpConnection {
 1155   
 1156           // the wrapped connection
 1157           private HttpConnection wrappedConnection;
 1158   
 1159           /**
 1160            * Creates a new HttpConnectionAdapter.
 1161            * @param connection the connection to be wrapped
 1162            */
 1163           public HttpConnectionAdapter(HttpConnection connection) {
 1164               super(connection.getHost(), connection.getPort(), connection.getProtocol());
 1165               this.wrappedConnection = connection;
 1166           }
 1167   
 1168           /**
 1169            * Tests if the wrapped connection is still available.
 1170            * @return boolean
 1171            */
 1172           protected boolean hasConnection() {
 1173               return wrappedConnection != null;
 1174           }
 1175   
 1176           /**
 1177            * @return HttpConnection
 1178            */
 1179           HttpConnection getWrappedConnection() {
 1180               return wrappedConnection;
 1181           }
 1182           
 1183           public void close() {
 1184               if (hasConnection()) {
 1185                   wrappedConnection.close();
 1186               } else {
 1187                   // do nothing
 1188               }
 1189           }
 1190   
 1191           public InetAddress getLocalAddress() {
 1192               if (hasConnection()) {
 1193                   return wrappedConnection.getLocalAddress();
 1194               } else {
 1195                   return null;
 1196               }
 1197           }
 1198   
 1199           /**
 1200            * @deprecated
 1201            */
 1202           public boolean isStaleCheckingEnabled() {
 1203               if (hasConnection()) {
 1204                   return wrappedConnection.isStaleCheckingEnabled();
 1205               } else {
 1206                   return false;
 1207               }
 1208           }
 1209   
 1210           public void setLocalAddress(InetAddress localAddress) {
 1211               if (hasConnection()) {
 1212                   wrappedConnection.setLocalAddress(localAddress);
 1213               } else {
 1214                   throw new IllegalStateException("Connection has been released");
 1215               }
 1216           }
 1217       
 1218           /**
 1219            * @deprecated 
 1220            */
 1221           public void setStaleCheckingEnabled(boolean staleCheckEnabled) {
 1222               if (hasConnection()) {
 1223                   wrappedConnection.setStaleCheckingEnabled(staleCheckEnabled);
 1224               } else {
 1225                   throw new IllegalStateException("Connection has been released");
 1226               }
 1227           }
 1228   
 1229           public String getHost() {
 1230               if (hasConnection()) {
 1231                   return wrappedConnection.getHost();
 1232               } else {
 1233                   return null;
 1234               }
 1235           }
 1236   
 1237           public HttpConnectionManager getHttpConnectionManager() {
 1238               if (hasConnection()) {
 1239                   return wrappedConnection.getHttpConnectionManager();
 1240               } else {
 1241                   return null;
 1242               }
 1243           }
 1244   
 1245           public InputStream getLastResponseInputStream() {
 1246               if (hasConnection()) {
 1247                   return wrappedConnection.getLastResponseInputStream();
 1248               } else {
 1249                   return null;
 1250               }
 1251           }
 1252   
 1253           public int getPort() {
 1254               if (hasConnection()) {
 1255                   return wrappedConnection.getPort();
 1256               } else {
 1257                   return -1;
 1258               }
 1259           }
 1260   
 1261           public Protocol getProtocol() {
 1262               if (hasConnection()) {
 1263                   return wrappedConnection.getProtocol();
 1264               } else {
 1265                   return null;
 1266               }
 1267           }
 1268   
 1269           public String getProxyHost() {
 1270               if (hasConnection()) {
 1271                   return wrappedConnection.getProxyHost();
 1272               } else {
 1273                   return null;
 1274               }
 1275           }
 1276   
 1277           public int getProxyPort() {
 1278               if (hasConnection()) {
 1279                   return wrappedConnection.getProxyPort();
 1280               } else {
 1281                   return -1;
 1282               }
 1283           }
 1284   
 1285           public OutputStream getRequestOutputStream()
 1286               throws IOException, IllegalStateException {
 1287               if (hasConnection()) {
 1288                   return wrappedConnection.getRequestOutputStream();
 1289               } else {
 1290                   return null;
 1291               }
 1292           }
 1293   
 1294           public InputStream getResponseInputStream()
 1295               throws IOException, IllegalStateException {
 1296               if (hasConnection()) {
 1297                   return wrappedConnection.getResponseInputStream();
 1298               } else {
 1299                   return null;
 1300               }
 1301           }
 1302   
 1303           public boolean isOpen() {
 1304               if (hasConnection()) {
 1305                   return wrappedConnection.isOpen();
 1306               } else {
 1307                   return false;
 1308               }
 1309           }
 1310   
 1311           public boolean closeIfStale() throws IOException {
 1312               if (hasConnection()) {
 1313                   return wrappedConnection.closeIfStale();
 1314               } else {
 1315                   return false;
 1316               }
 1317           }
 1318   
 1319           public boolean isProxied() {
 1320               if (hasConnection()) {
 1321                   return wrappedConnection.isProxied();
 1322               } else {
 1323                   return false;
 1324               }
 1325           }
 1326   
 1327           public boolean isResponseAvailable() throws IOException {
 1328               if (hasConnection()) {
 1329                   return  wrappedConnection.isResponseAvailable();
 1330               } else {
 1331                   return false;
 1332               }
 1333           }
 1334   
 1335           public boolean isResponseAvailable(int timeout) throws IOException {
 1336               if (hasConnection()) {
 1337                   return  wrappedConnection.isResponseAvailable(timeout);
 1338               } else {
 1339                   return false;
 1340               }
 1341           }
 1342   
 1343           public boolean isSecure() {
 1344               if (hasConnection()) {
 1345                   return wrappedConnection.isSecure();
 1346               } else {
 1347                   return false;
 1348               }
 1349           }
 1350   
 1351           public boolean isTransparent() {
 1352               if (hasConnection()) {
 1353                   return wrappedConnection.isTransparent();
 1354               } else {
 1355                   return false;
 1356               }
 1357           }
 1358   
 1359           public void open() throws IOException {
 1360               if (hasConnection()) {
 1361                   wrappedConnection.open();
 1362               } else {
 1363                   throw new IllegalStateException("Connection has been released");
 1364               }
 1365           }
 1366   
 1367           /**
 1368            * @deprecated
 1369            */
 1370           public void print(String data)
 1371               throws IOException, IllegalStateException {
 1372               if (hasConnection()) {
 1373                   wrappedConnection.print(data);
 1374               } else {
 1375                   throw new IllegalStateException("Connection has been released");
 1376               }
 1377           }
 1378   
 1379           public void printLine()
 1380               throws IOException, IllegalStateException {
 1381               if (hasConnection()) {
 1382                   wrappedConnection.printLine();
 1383               } else {
 1384                   throw new IllegalStateException("Connection has been released");
 1385               }
 1386           }
 1387   
 1388           /**
 1389            * @deprecated
 1390            */
 1391           public void printLine(String data)
 1392               throws IOException, IllegalStateException {
 1393               if (hasConnection()) {
 1394                   wrappedConnection.printLine(data);
 1395               } else {
 1396                   throw new IllegalStateException("Connection has been released");
 1397               }
 1398           }
 1399   
 1400           /**
 1401            * @deprecated
 1402            */
 1403           public String readLine() throws IOException, IllegalStateException {
 1404               if (hasConnection()) {
 1405                   return wrappedConnection.readLine();
 1406               } else {
 1407                   throw new IllegalStateException("Connection has been released");
 1408               }
 1409           }
 1410   
 1411           public String readLine(String charset) throws IOException, IllegalStateException {
 1412               if (hasConnection()) {
 1413                   return wrappedConnection.readLine(charset);
 1414               } else {
 1415                   throw new IllegalStateException("Connection has been released");
 1416               }
 1417           }
 1418   
 1419           public void releaseConnection() {
 1420               if (!isLocked() && hasConnection()) {
 1421                   HttpConnection wrappedConnection = this.wrappedConnection;
 1422                   this.wrappedConnection = null;
 1423                   wrappedConnection.releaseConnection();
 1424               } else {
 1425                   // do nothing
 1426               }
 1427           }
 1428   
 1429           /**
 1430            * @deprecated
 1431            */
 1432           public void setConnectionTimeout(int timeout) {
 1433               if (hasConnection()) {
 1434                   wrappedConnection.setConnectionTimeout(timeout);
 1435               } else {
 1436                   // do nothing
 1437               }
 1438           }
 1439   
 1440           public void setHost(String host) throws IllegalStateException {
 1441               if (hasConnection()) {
 1442                   wrappedConnection.setHost(host);
 1443               } else {
 1444                   // do nothing
 1445               }
 1446           }
 1447   
 1448           public void setHttpConnectionManager(HttpConnectionManager httpConnectionManager) {
 1449               if (hasConnection()) {
 1450                   wrappedConnection.setHttpConnectionManager(httpConnectionManager);
 1451               } else {
 1452                   // do nothing
 1453               }
 1454           }
 1455   
 1456           public void setLastResponseInputStream(InputStream inStream) {
 1457               if (hasConnection()) {
 1458                   wrappedConnection.setLastResponseInputStream(inStream);
 1459               } else {
 1460                   // do nothing
 1461               }
 1462           }
 1463   
 1464           public void setPort(int port) throws IllegalStateException {
 1465               if (hasConnection()) {
 1466                   wrappedConnection.setPort(port);
 1467               } else {
 1468                   // do nothing
 1469               }
 1470           }
 1471   
 1472           public void setProtocol(Protocol protocol) {
 1473               if (hasConnection()) {
 1474                   wrappedConnection.setProtocol(protocol);
 1475               } else {
 1476                   // do nothing
 1477               }
 1478           }
 1479   
 1480           public void setProxyHost(String host) throws IllegalStateException {
 1481               if (hasConnection()) {
 1482                   wrappedConnection.setProxyHost(host);
 1483               } else {
 1484                   // do nothing
 1485               }
 1486           }
 1487   
 1488           public void setProxyPort(int port) throws IllegalStateException {
 1489               if (hasConnection()) {
 1490                   wrappedConnection.setProxyPort(port);
 1491               } else {
 1492                   // do nothing
 1493               }
 1494           }
 1495   
 1496           /**
 1497            * @deprecated
 1498            */
 1499           public void setSoTimeout(int timeout)
 1500               throws SocketException, IllegalStateException {
 1501               if (hasConnection()) {
 1502                   wrappedConnection.setSoTimeout(timeout);
 1503               } else {
 1504                   // do nothing
 1505               }
 1506           }
 1507   
 1508           /**
 1509            * @deprecated
 1510            */
 1511           public void shutdownOutput() {
 1512               if (hasConnection()) {
 1513                   wrappedConnection.shutdownOutput();
 1514               } else {
 1515                   // do nothing
 1516               }
 1517           }
 1518   
 1519           public void tunnelCreated() throws IllegalStateException, IOException {
 1520               if (hasConnection()) {
 1521                   wrappedConnection.tunnelCreated();
 1522               } else {
 1523                   // do nothing
 1524               }
 1525           }
 1526   
 1527           public void write(byte[] data, int offset, int length)
 1528               throws IOException, IllegalStateException {
 1529               if (hasConnection()) {
 1530                   wrappedConnection.write(data, offset, length);
 1531               } else {
 1532                   throw new IllegalStateException("Connection has been released");
 1533               }
 1534           }
 1535   
 1536           public void write(byte[] data)
 1537               throws IOException, IllegalStateException {
 1538               if (hasConnection()) {
 1539                   wrappedConnection.write(data);
 1540               } else {
 1541                   throw new IllegalStateException("Connection has been released");
 1542               }
 1543           }
 1544   
 1545           public void writeLine()
 1546               throws IOException, IllegalStateException {
 1547               if (hasConnection()) {
 1548                   wrappedConnection.writeLine();
 1549               } else {
 1550                   throw new IllegalStateException("Connection has been released");
 1551               }
 1552           }
 1553   
 1554           public void writeLine(byte[] data)
 1555               throws IOException, IllegalStateException {
 1556               if (hasConnection()) {
 1557                   wrappedConnection.writeLine(data);
 1558               } else {
 1559                   throw new IllegalStateException("Connection has been released");
 1560               }
 1561           }
 1562   
 1563           public void flushRequestOutputStream() throws IOException {
 1564               if (hasConnection()) {
 1565                   wrappedConnection.flushRequestOutputStream();
 1566               } else {
 1567                   throw new IllegalStateException("Connection has been released");
 1568               }
 1569           }
 1570   
 1571           /**
 1572            * @deprecated
 1573            */
 1574           public int getSoTimeout() throws SocketException {
 1575               if (hasConnection()) {
 1576                   return wrappedConnection.getSoTimeout();
 1577               } else {
 1578                   throw new IllegalStateException("Connection has been released");
 1579               }
 1580           }
 1581   
 1582           /**
 1583            * @deprecated
 1584            */
 1585           public String getVirtualHost() {
 1586               if (hasConnection()) {
 1587                   return wrappedConnection.getVirtualHost();
 1588               } else {
 1589                   throw new IllegalStateException("Connection has been released");
 1590               }
 1591           }
 1592   
 1593           /**
 1594            * @deprecated
 1595            */
 1596           public void setVirtualHost(String host) throws IllegalStateException {
 1597               if (hasConnection()) {
 1598                   wrappedConnection.setVirtualHost(host);
 1599               } else {
 1600                   throw new IllegalStateException("Connection has been released");
 1601               }
 1602           }
 1603   
 1604           public int getSendBufferSize() throws SocketException {
 1605               if (hasConnection()) {
 1606                   return wrappedConnection.getSendBufferSize();
 1607               } else {
 1608                   throw new IllegalStateException("Connection has been released");
 1609               }
 1610           }
 1611   
 1612           /**
 1613            * @deprecated
 1614            */
 1615           public void setSendBufferSize(int sendBufferSize) throws SocketException {
 1616               if (hasConnection()) {
 1617                   wrappedConnection.setSendBufferSize(sendBufferSize);
 1618               } else {
 1619                   throw new IllegalStateException("Connection has been released");
 1620               }
 1621           }
 1622   
 1623           public HttpConnectionParams getParams() {
 1624               if (hasConnection()) {
 1625                   return wrappedConnection.getParams();
 1626               } else {
 1627                   throw new IllegalStateException("Connection has been released");
 1628               }
 1629           }
 1630   
 1631           public void setParams(final HttpConnectionParams params) {
 1632               if (hasConnection()) {
 1633                   wrappedConnection.setParams(params);
 1634               } else {
 1635                   throw new IllegalStateException("Connection has been released");
 1636               }
 1637           }
 1638   
 1639           /* (non-Javadoc)
 1640            * @see org.apache.commons.httpclient.HttpConnection#print(java.lang.String, java.lang.String)
 1641            */
 1642           public void print(String data, String charset) throws IOException, IllegalStateException {
 1643               if (hasConnection()) {
 1644                   wrappedConnection.print(data, charset);
 1645               } else {
 1646                   throw new IllegalStateException("Connection has been released");
 1647               }
 1648           }
 1649   
 1650           /* (non-Javadoc)
 1651            * @see org.apache.commons.httpclient.HttpConnection#printLine(java.lang.String, java.lang.String)
 1652            */
 1653           public void printLine(String data, String charset)
 1654               throws IOException, IllegalStateException {
 1655               if (hasConnection()) {
 1656                   wrappedConnection.printLine(data, charset);
 1657               } else {
 1658                   throw new IllegalStateException("Connection has been released");
 1659               }
 1660           }
 1661   
 1662           /* (non-Javadoc)
 1663            * @see org.apache.commons.httpclient.HttpConnection#setSocketTimeout(int)
 1664            */
 1665           public void setSocketTimeout(int timeout) throws SocketException, IllegalStateException {
 1666               if (hasConnection()) {
 1667                   wrappedConnection.setSocketTimeout(timeout);
 1668               } else {
 1669                   throw new IllegalStateException("Connection has been released");
 1670               }
 1671           }
 1672   
 1673       }
 1674   
 1675   }
 1676   

Home » commons-httpclient-3.1-src » org.apache.commons » httpclient » [javadoc | source]