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
     89      */
     90     public ThreadSafeClientConnManager(HttpParams params,
     91                                        SchemeRegistry schreg) {
     92 
     93         if (params == null) {
     94             throw new IllegalArgumentException("HTTP parameters may not be null");
     95         }
     96         this.schemeRegistry = schreg;
     97         this.connOperator   = createConnectionOperator(schreg);
     98         this.connectionPool = createConnectionPool(params);
     99 
    100     } // <constructor>
    101 
    102 
    103     @Override
    104     protected void finalize() throws Throwable {
    105         shutdown();
    106         super.finalize();
    107     }
    108 
    109 
    110     /**
    111      * Hook for creating the connection pool.
    112      *
    113      * @return  the connection pool to use
    114      */
    115     protected AbstractConnPool createConnectionPool(final HttpParams params) {
    116 
    117         AbstractConnPool acp = new ConnPoolByRoute(connOperator, params);
    118         boolean conngc = true; //@@@ check parameters to decide
    119         if (conngc) {
    120             acp.enableConnectionGC();
    121         }
    122         return acp;
    123     }
    124 
    125 
    126     /**
    127      * Hook for creating the connection operator.
    128      * It is called by the constructor.
    129      * Derived classes can override this method to change the
    130      * instantiation of the operator.
    131      * The default implementation here instantiates
    132      * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
    133      *
    134      * @param schreg    the scheme registry to use, or <code>null</code>
    135      *
    136      * @return  the connection operator to use
    137      */
    138     protected ClientConnectionOperator
    139         createConnectionOperator(SchemeRegistry schreg) {
    140 
    141         return new DefaultClientConnectionOperator(schreg);
    142     }
    143 
    144 
    145     // non-javadoc, see interface ClientConnectionManager
    146     public SchemeRegistry getSchemeRegistry() {
    147         return this.schemeRegistry;
    148     }
    149 
    150 
    151     public ClientConnectionRequest requestConnection(
    152             final HttpRoute route,
    153             final Object state) {
    154 
    155         final PoolEntryRequest poolRequest = connectionPool.requestPoolEntry(
    156                 route, state);
    157 
    158         return new ClientConnectionRequest() {
    159 
    160             public void abortRequest() {
    161                 poolRequest.abortRequest();
    162             }
    163 
    164             public ManagedClientConnection getConnection(
    165                     long timeout, TimeUnit tunit) throws InterruptedException,
    166                     ConnectionPoolTimeoutException {
    167                 if (route == null) {
    168                     throw new IllegalArgumentException("Route may not be null.");
    169                 }
    170 
    171                 if (log.isDebugEnabled()) {
    172                     log.debug("ThreadSafeClientConnManager.getConnection: "
    173                         + route + ", timeout = " + timeout);
    174                 }
    175 
    176                 BasicPoolEntry entry = poolRequest.getPoolEntry(timeout, tunit);
    177                 // BEGIN android-changed
    178                 // When using a recycled Socket, we need to re-tag it with any
    179                 // updated statistics options.
    180                 try {
    181                     final Socket socket = entry.getConnection().getSocket();
    182                     if (socket != null) {
    183                         SocketTagger.get().tag(socket);
    184                     }
    185                 } catch (IOException iox) {
    186                     log.debug("Problem tagging socket.", iox);
    187                 }
    188                 // END android-changed
    189                 return new BasicPooledConnAdapter(ThreadSafeClientConnManager.this, entry);
    190             }
    191 
    192         };
    193 
    194     }
    195 
    196 
    197     // non-javadoc, see interface ClientConnectionManager
    198     public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
    199 
    200         if (!(conn instanceof BasicPooledConnAdapter)) {
    201             throw new IllegalArgumentException
    202                 ("Connection class mismatch, " +
    203                  "connection not obtained from this manager.");
    204         }
    205         BasicPooledConnAdapter hca = (BasicPooledConnAdapter) conn;
    206         if ((hca.getPoolEntry() != null) && (hca.getManager() != this)) {
    207             throw new IllegalArgumentException
    208                 ("Connection not obtained from this manager.");
    209         }
    210 
    211         try {
    212             // BEGIN android-changed
    213             // When recycling a Socket, we un-tag it to avoid collecting
    214             // statistics from future users.
    215             final BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
    216             final Socket socket = entry.getConnection().getSocket();
    217             if (socket != null) {
    218                 SocketTagger.get().untag(socket);
    219             }
    220             // END android-changed
    221 
    222             // make sure that the response has been read completely
    223             if (hca.isOpen() && !hca.isMarkedReusable()) {
    224                 if (log.isDebugEnabled()) {
    225                     log.debug
    226                         ("Released connection open but not marked reusable.");
    227                 }
    228                 // In MTHCM, there would be a call to
    229                 // SimpleHttpConnectionManager.finishLastResponse(conn);
    230                 // Consuming the response is handled outside in 4.0.
    231 
    232                 // make sure this connection will not be re-used
    233                 // Shut down rather than close, we might have gotten here
    234                 // because of a shutdown trigger.
    235                 // Shutdown of the adapter also clears the tracked route.
    236                 hca.shutdown();
    237             }
    238         } catch (IOException iox) {
    239             //@@@ log as warning? let pass?
    240             if (log.isDebugEnabled())
    241                 log.debug("Exception shutting down released connection.",
    242                           iox);
    243         } finally {
    244             BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
    245             boolean reusable = hca.isMarkedReusable();
    246             hca.detach();
    247             if (entry != null) {
    248                 connectionPool.freeEntry(entry, reusable, validDuration, timeUnit);
    249             }
    250         }
    251     }
    252 
    253 
    254     // non-javadoc, see interface ClientConnectionManager
    255     public void shutdown() {
    256         connectionPool.shutdown();
    257     }
    258 
    259 
    260     /**
    261      * Gets the total number of pooled connections for the given route.
    262      * This is the total number of connections that have been created and
    263      * are still in use by this connection manager for the route.
    264      * This value will not exceed the maximum number of connections per host.
    265      *
    266      * @param route     the route in question
    267      *
    268      * @return  the total number of pooled connections for that route
    269      */
    270     public int getConnectionsInPool(HttpRoute route) {
    271         return ((ConnPoolByRoute)connectionPool).getConnectionsInPool(
    272                 route);
    273     }
    274 
    275 
    276     /**
    277      * Gets the total number of pooled connections.  This is the total number of
    278      * connections that have been created and are still in use by this connection
    279      * manager.  This value will not exceed the maximum number of connections
    280      * in total.
    281      *
    282      * @return the total number of pooled connections
    283      */
    284     public int getConnectionsInPool() {
    285         synchronized (connectionPool) {
    286             return connectionPool.numConnections; //@@@
    287         }
    288     }
    289 
    290 
    291     // non-javadoc, see interface ClientConnectionManager
    292     public void closeIdleConnections(long idleTimeout, TimeUnit tunit) {
    293         // combine these two in a single call?
    294         connectionPool.closeIdleConnections(idleTimeout, tunit);
    295         connectionPool.deleteClosedConnections();
    296     }
    297 
    298     public void closeExpiredConnections() {
    299         connectionPool.closeExpiredConnections();
    300         connectionPool.deleteClosedConnections();
    301     }
    302 
    303 
    304 } // class ThreadSafeClientConnManager
    305 
    306