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/AbstractConnPool.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.lang.ref.Reference;
     35 import java.lang.ref.ReferenceQueue;
     36 import java.util.Set;
     37 import java.util.HashSet;
     38 import java.util.Iterator;
     39 import java.util.concurrent.TimeUnit;
     40 import java.util.concurrent.locks.Lock;
     41 import java.util.concurrent.locks.ReentrantLock;
     42 
     43 import org.apache.commons.logging.Log;
     44 import org.apache.commons.logging.LogFactory;
     45 import org.apache.http.conn.ConnectionPoolTimeoutException;
     46 import org.apache.http.conn.OperatedClientConnection;
     47 import org.apache.http.conn.routing.HttpRoute;
     48 import org.apache.http.impl.conn.IdleConnectionHandler;
     49 
     50 
     51 /**
     52  * An abstract connection pool.
     53  * It is used by the {@link ThreadSafeClientConnManager}.
     54  * The abstract pool includes a {@link #poolLock}, which is used to
     55  * synchronize access to the internal pool datastructures.
     56  * Don't use <code>synchronized</code> for that purpose!
     57  *
     58  * @deprecated Please use {@link java.net.URL#openConnection} instead.
     59  *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
     60  *     for further details.
     61  */
     62 @Deprecated
     63 public abstract class AbstractConnPool implements RefQueueHandler {
     64 
     65     private final Log log = LogFactory.getLog(getClass());
     66 
     67     /**
     68      * The global lock for this pool.
     69      */
     70     protected final Lock poolLock;
     71 
     72 
     73     /**
     74      * References to issued connections.
     75      * Objects in this set are of class
     76      * {@link BasicPoolEntryRef BasicPoolEntryRef},
     77      * and point to the pool entry for the issued connection.
     78      * GCed connections are detected by the missing pool entries.
     79      */
     80     protected Set<BasicPoolEntryRef> issuedConnections;
     81 
     82     /** The handler for idle connections. */
     83     protected IdleConnectionHandler idleConnHandler;
     84 
     85     /** The current total number of connections. */
     86     protected int numConnections;
     87 
     88     /**
     89      * A reference queue to track loss of pool entries to GC.
     90      * The same queue is used to track loss of the connection manager,
     91      * so we cannot specialize the type.
     92      */
     93     protected ReferenceQueue<Object> refQueue;
     94 
     95     /** A worker (thread) to track loss of pool entries to GC. */
     96     private RefQueueWorker refWorker;
     97 
     98 
     99     /** Indicates whether this pool is shut down. */
    100     protected volatile boolean isShutDown;
    101 
    102     /**
    103      * Creates a new connection pool.
    104      */
    105     protected AbstractConnPool() {
    106         issuedConnections = new HashSet<BasicPoolEntryRef>();
    107         idleConnHandler = new IdleConnectionHandler();
    108 
    109         boolean fair = false; //@@@ check parameters to decide
    110         poolLock = new ReentrantLock(fair);
    111     }
    112 
    113 
    114     /**
    115      * Enables connection garbage collection (GC).
    116      * This method must be called immediately after creating the
    117      * connection pool. It is not possible to enable connection GC
    118      * after pool entries have been created. Neither is it possible
    119      * to disable connection GC.
    120      *
    121      * @throws IllegalStateException
    122      *         if connection GC is already enabled, or if it cannot be
    123      *         enabled because there already are pool entries
    124      */
    125     public void enableConnectionGC()
    126         throws IllegalStateException {
    127 
    128         if (refQueue != null) {
    129             throw new IllegalStateException("Connection GC already enabled.");
    130         }
    131         poolLock.lock();
    132         try {
    133             if (numConnections > 0) { //@@@ is this check sufficient?
    134                 throw new IllegalStateException("Pool already in use.");
    135             }
    136         } finally {
    137             poolLock.unlock();
    138         }
    139 
    140         refQueue  = new ReferenceQueue<Object>();
    141         refWorker = new RefQueueWorker(refQueue, this);
    142         Thread t = new Thread(refWorker); //@@@ use a thread factory
    143         t.setDaemon(true);
    144         t.setName("RefQueueWorker@" + this);
    145         t.start();
    146     }
    147 
    148 
    149     /**
    150      * Obtains a pool entry with a connection within the given timeout.
    151      *
    152      * @param route     the route for which to get the connection
    153      * @param timeout   the timeout, 0 or negative for no timeout
    154      * @param tunit     the unit for the <code>timeout</code>,
    155      *                  may be <code>null</code> only if there is no timeout
    156      *
    157      * @return  pool entry holding a connection for the route
    158      *
    159      * @throws ConnectionPoolTimeoutException
    160      *         if the timeout expired
    161      * @throws InterruptedException
    162      *         if the calling thread was interrupted
    163      */
    164     public final
    165         BasicPoolEntry getEntry(
    166                 HttpRoute route,
    167                 Object state,
    168                 long timeout,
    169                 TimeUnit tunit)
    170                     throws ConnectionPoolTimeoutException, InterruptedException {
    171         return requestPoolEntry(route, state).getPoolEntry(timeout, tunit);
    172     }
    173 
    174     /**
    175      * Returns a new {@link PoolEntryRequest}, from which a {@link BasicPoolEntry}
    176      * can be obtained, or the request can be aborted.
    177      */
    178     public abstract PoolEntryRequest requestPoolEntry(HttpRoute route, Object state);
    179 
    180 
    181     /**
    182      * Returns an entry into the pool.
    183      * The connection of the entry is expected to be in a suitable state,
    184      * either open and re-usable, or closed. The pool will not make any
    185      * attempt to determine whether it can be re-used or not.
    186      *
    187      * @param entry     the entry for the connection to release
    188      * @param reusable  <code>true</code> if the entry is deemed
    189      *                  reusable, <code>false</code> otherwise.
    190      * @param validDuration The duration that the entry should remain free and reusable.
    191      * @param timeUnit The unit of time the duration is measured in.
    192      */
    193     public abstract void freeEntry(BasicPoolEntry entry, boolean reusable, long validDuration, TimeUnit timeUnit)
    194         ;
    195 
    196 
    197 
    198     // non-javadoc, see interface RefQueueHandler
    199 // BEGIN android-changed
    200     public void handleReference(Reference ref) {
    201 // END android-changed
    202         poolLock.lock();
    203         try {
    204 
    205             if (ref instanceof BasicPoolEntryRef) {
    206                 // check if the GCed pool entry was still in use
    207                 //@@@ find a way to detect this without lookup
    208                 //@@@ flag in the BasicPoolEntryRef, to be reset when freed?
    209                 final boolean lost = issuedConnections.remove(ref);
    210                 if (lost) {
    211                     final HttpRoute route =
    212                         ((BasicPoolEntryRef)ref).getRoute();
    213                     if (log.isDebugEnabled()) {
    214                         log.debug("Connection garbage collected. " + route);
    215                     }
    216                     handleLostEntry(route);
    217                 }
    218             }
    219 
    220         } finally {
    221             poolLock.unlock();
    222         }
    223     }
    224 
    225 
    226     /**
    227      * Handles cleaning up for a lost pool entry with the given route.
    228      * A lost pool entry corresponds to a connection that was
    229      * garbage collected instead of being properly released.
    230      *
    231      * @param route     the route of the pool entry that was lost
    232      */
    233     protected abstract void handleLostEntry(HttpRoute route)
    234         ;
    235 
    236 
    237     /**
    238      * Closes idle connections.
    239      *
    240      * @param idletime  the time the connections should have been idle
    241      *                  in order to be closed now
    242      * @param tunit     the unit for the <code>idletime</code>
    243      */
    244     public void closeIdleConnections(long idletime, TimeUnit tunit) {
    245 
    246         // idletime can be 0 or negative, no problem there
    247         if (tunit == null) {
    248             throw new IllegalArgumentException("Time unit must not be null.");
    249         }
    250 
    251         poolLock.lock();
    252         try {
    253             idleConnHandler.closeIdleConnections(tunit.toMillis(idletime));
    254         } finally {
    255             poolLock.unlock();
    256         }
    257     }
    258 
    259     public void closeExpiredConnections() {
    260         poolLock.lock();
    261         try {
    262             idleConnHandler.closeExpiredConnections();
    263         } finally {
    264             poolLock.unlock();
    265         }
    266     }
    267 
    268 
    269     //@@@ revise this cleanup stuff (closeIdle+deleteClosed), it's not good
    270 
    271     /**
    272      * Deletes all entries for closed connections.
    273      */
    274     public abstract void deleteClosedConnections()
    275         ;
    276 
    277 
    278     /**
    279      * Shuts down this pool and all associated resources.
    280      * Overriding methods MUST call the implementation here!
    281      */
    282     public void shutdown() {
    283 
    284         poolLock.lock();
    285         try {
    286 
    287             if (isShutDown)
    288                 return;
    289 
    290             // no point in monitoring GC anymore
    291             if (refWorker != null)
    292                 refWorker.shutdown();
    293 
    294             // close all connections that are issued to an application
    295             Iterator<BasicPoolEntryRef> iter = issuedConnections.iterator();
    296             while (iter.hasNext()) {
    297                 BasicPoolEntryRef per = iter.next();
    298                 iter.remove();
    299                 BasicPoolEntry entry = per.get();
    300                 if (entry != null) {
    301                     closeConnection(entry.getConnection());
    302                 }
    303             }
    304 
    305             // remove all references to connections
    306             //@@@ use this for shutting them down instead?
    307             idleConnHandler.removeAll();
    308 
    309             isShutDown = true;
    310 
    311         } finally {
    312             poolLock.unlock();
    313         }
    314     }
    315 
    316 
    317     /**
    318      * Closes a connection from this pool.
    319      *
    320      * @param conn      the connection to close, or <code>null</code>
    321      */
    322     protected void closeConnection(final OperatedClientConnection conn) {
    323         if (conn != null) {
    324             try {
    325                 conn.close();
    326             } catch (IOException ex) {
    327                 log.debug("I/O error closing connection", ex);
    328             }
    329         }
    330     }
    331 
    332 
    333 
    334 
    335 
    336 } // class AbstractConnPool
    337 
    338