• 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/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@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      */
ThreadSafeClientConnManager(HttpParams params, SchemeRegistry schreg)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
finalize()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      */
createConnectionPool(final HttpParams params)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
createConnectionOperator(SchemeRegistry schreg)139         createConnectionOperator(SchemeRegistry schreg) {
140 
141         return new DefaultClientConnectionOperator(schreg);
142     }
143 
144 
145     // non-javadoc, see interface ClientConnectionManager
getSchemeRegistry()146     public SchemeRegistry getSchemeRegistry() {
147         return this.schemeRegistry;
148     }
149 
150 
requestConnection( final HttpRoute route, final Object state)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