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