Home | History | Annotate | Download | only in tsccm
      1 /*
      2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java $
      3  * $Revision: 673450 $
      4  * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
      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.http.impl.conn.tsccm;
     32 
     33 import java.io.IOException;
     34 import java.util.concurrent.TimeUnit;
     35 
     36 import org.apache.commons.logging.Log;
     37 import org.apache.commons.logging.LogFactory;
     38 import org.apache.http.conn.routing.HttpRoute;
     39 import org.apache.http.conn.scheme.SchemeRegistry;
     40 import org.apache.http.conn.ClientConnectionManager;
     41 import org.apache.http.conn.ClientConnectionOperator;
     42 import org.apache.http.conn.ClientConnectionRequest;
     43 import org.apache.http.conn.ConnectionPoolTimeoutException;
     44 import org.apache.http.conn.ManagedClientConnection;
     45 import org.apache.http.conn.OperatedClientConnection;
     46 import org.apache.http.params.HttpParams;
     47 import org.apache.http.impl.conn.DefaultClientConnectionOperator;
     48 
     49 
     50 
     51 /**
     52  * Manages a pool of {@link OperatedClientConnection client connections}.
     53  * <p>
     54  * This class is derived from <code>MultiThreadedHttpConnectionManager</code>
     55  * in HttpClient 3. See there for original authors.
     56  * </p>
     57  *
     58  * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
     59  * @author <a href="mailto:becke (at) u.washington.edu">Michael Becke</a>
     60  *
     61  *
     62  * <!-- empty lines to avoid svn diff problems -->
     63  * @version $Revision: 673450 $ $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
     64  *
     65  * @since 4.0
     66  */
     67 public class ThreadSafeClientConnManager implements ClientConnectionManager {
     68 
     69     private final Log log = LogFactory.getLog(getClass());
     70 
     71     /** The schemes supported by this connection manager. */
     72     protected SchemeRegistry schemeRegistry;
     73 
     74     /** The pool of connections being managed. */
     75     protected final AbstractConnPool connectionPool;
     76 
     77     /** The operator for opening and updating connections. */
     78     protected ClientConnectionOperator connOperator;
     79 
     80 
     81 
     82     /**
     83      * Creates a new thread safe connection manager.
     84      *
     85      * @param params    the parameters for this manager
     86      * @param schreg    the scheme registry, or
     87      *                  <code>null</code> for the default registry
     88      */
     89     public ThreadSafeClientConnManager(HttpParams params,
     90                                        SchemeRegistry schreg) {
     91 
     92         if (params == null) {
     93             throw new IllegalArgumentException("HTTP parameters may not be null");
     94         }
     95         this.schemeRegistry = schreg;
     96         this.connOperator   = createConnectionOperator(schreg);
     97         this.connectionPool = createConnectionPool(params);
     98 
     99     } // <constructor>
    100 
    101 
    102     @Override
    103     protected void finalize() throws Throwable {
    104         shutdown();
    105         super.finalize();
    106     }
    107 
    108 
    109     /**
    110      * Hook for creating the connection pool.
    111      *
    112      * @return  the connection pool to use
    113      */
    114     protected AbstractConnPool createConnectionPool(final HttpParams params) {
    115 
    116         AbstractConnPool acp = new ConnPoolByRoute(connOperator, params);
    117         boolean conngc = true; //@@@ check parameters to decide
    118         if (conngc) {
    119             acp.enableConnectionGC();
    120         }
    121         return acp;
    122     }
    123 
    124 
    125     /**
    126      * Hook for creating the connection operator.
    127      * It is called by the constructor.
    128      * Derived classes can override this method to change the
    129      * instantiation of the operator.
    130      * The default implementation here instantiates
    131      * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
    132      *
    133      * @param schreg    the scheme registry to use, or <code>null</code>
    134      *
    135      * @return  the connection operator to use
    136      */
    137     protected ClientConnectionOperator
    138         createConnectionOperator(SchemeRegistry schreg) {
    139 
    140         return new DefaultClientConnectionOperator(schreg);
    141     }
    142 
    143 
    144     // non-javadoc, see interface ClientConnectionManager
    145     public SchemeRegistry getSchemeRegistry() {
    146         return this.schemeRegistry;
    147     }
    148 
    149 
    150     public ClientConnectionRequest requestConnection(
    151             final HttpRoute route,
    152             final Object state) {
    153 
    154         final PoolEntryRequest poolRequest = connectionPool.requestPoolEntry(
    155                 route, state);
    156 
    157         return new ClientConnectionRequest() {
    158 
    159             public void abortRequest() {
    160                 poolRequest.abortRequest();
    161             }
    162 
    163             public ManagedClientConnection getConnection(
    164                     long timeout, TimeUnit tunit) throws InterruptedException,
    165                     ConnectionPoolTimeoutException {
    166                 if (route == null) {
    167                     throw new IllegalArgumentException("Route may not be null.");
    168                 }
    169 
    170                 if (log.isDebugEnabled()) {
    171                     log.debug("ThreadSafeClientConnManager.getConnection: "
    172                         + route + ", timeout = " + timeout);
    173                 }
    174 
    175                 BasicPoolEntry entry = poolRequest.getPoolEntry(timeout, tunit);
    176                 return new BasicPooledConnAdapter(ThreadSafeClientConnManager.this, entry);
    177             }
    178 
    179         };
    180 
    181     }
    182 
    183 
    184     // non-javadoc, see interface ClientConnectionManager
    185     public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
    186 
    187         if (!(conn instanceof BasicPooledConnAdapter)) {
    188             throw new IllegalArgumentException
    189                 ("Connection class mismatch, " +
    190                  "connection not obtained from this manager.");
    191         }
    192         BasicPooledConnAdapter hca = (BasicPooledConnAdapter) conn;
    193         if ((hca.getPoolEntry() != null) && (hca.getManager() != this)) {
    194             throw new IllegalArgumentException
    195                 ("Connection not obtained from this manager.");
    196         }
    197 
    198         try {
    199             // make sure that the response has been read completely
    200             if (hca.isOpen() && !hca.isMarkedReusable()) {
    201                 if (log.isDebugEnabled()) {
    202                     log.debug
    203                         ("Released connection open but not marked reusable.");
    204                 }
    205                 // In MTHCM, there would be a call to
    206                 // SimpleHttpConnectionManager.finishLastResponse(conn);
    207                 // Consuming the response is handled outside in 4.0.
    208 
    209                 // make sure this connection will not be re-used
    210                 // Shut down rather than close, we might have gotten here
    211                 // because of a shutdown trigger.
    212                 // Shutdown of the adapter also clears the tracked route.
    213                 hca.shutdown();
    214             }
    215         } catch (IOException iox) {
    216             //@@@ log as warning? let pass?
    217             if (log.isDebugEnabled())
    218                 log.debug("Exception shutting down released connection.",
    219                           iox);
    220         } finally {
    221             BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
    222             boolean reusable = hca.isMarkedReusable();
    223             hca.detach();
    224             if (entry != null) {
    225                 connectionPool.freeEntry(entry, reusable, validDuration, timeUnit);
    226             }
    227         }
    228     }
    229 
    230 
    231     // non-javadoc, see interface ClientConnectionManager
    232     public void shutdown() {
    233         connectionPool.shutdown();
    234     }
    235 
    236 
    237     /**
    238      * Gets the total number of pooled connections for the given route.
    239      * This is the total number of connections that have been created and
    240      * are still in use by this connection manager for the route.
    241      * This value will not exceed the maximum number of connections per host.
    242      *
    243      * @param route     the route in question
    244      *
    245      * @return  the total number of pooled connections for that route
    246      */
    247     public int getConnectionsInPool(HttpRoute route) {
    248         return ((ConnPoolByRoute)connectionPool).getConnectionsInPool(
    249                 route);
    250     }
    251 
    252 
    253     /**
    254      * Gets the total number of pooled connections.  This is the total number of
    255      * connections that have been created and are still in use by this connection
    256      * manager.  This value will not exceed the maximum number of connections
    257      * in total.
    258      *
    259      * @return the total number of pooled connections
    260      */
    261     public int getConnectionsInPool() {
    262         synchronized (connectionPool) {
    263             return connectionPool.numConnections; //@@@
    264         }
    265     }
    266 
    267 
    268     // non-javadoc, see interface ClientConnectionManager
    269     public void closeIdleConnections(long idleTimeout, TimeUnit tunit) {
    270         // combine these two in a single call?
    271         connectionPool.closeIdleConnections(idleTimeout, tunit);
    272         connectionPool.deleteClosedConnections();
    273     }
    274 
    275     public void closeExpiredConnections() {
    276         connectionPool.closeExpiredConnections();
    277         connectionPool.deleteClosedConnections();
    278     }
    279 
    280 
    281 } // class ThreadSafeClientConnManager
    282 
    283