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