• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
AbstractConnPool()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      */
enableConnectionGC()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
getEntry( HttpRoute route, Object state, long timeout, TimeUnit tunit)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      */
requestPoolEntry(HttpRoute route, Object state)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      */
freeEntry(BasicPoolEntry entry, boolean reusable, long validDuration, TimeUnit timeUnit)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
handleReference(Reference ref)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      */
handleLostEntry(HttpRoute route)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      */
closeIdleConnections(long idletime, TimeUnit tunit)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 
closeExpiredConnections()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      */
deleteClosedConnections()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      */
shutdown()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      */
closeConnection(final OperatedClientConnection conn)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