• 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 java.io.IOException;
34 import java.util.concurrent.TimeUnit;
35 
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.http.conn.routing.HttpRoute;
39 import org.apache.http.conn.scheme.SchemeRegistry;
40 import org.apache.http.conn.ClientConnectionManager;
41 import org.apache.http.conn.ClientConnectionOperator;
42 import org.apache.http.conn.ClientConnectionRequest;
43 import org.apache.http.conn.ConnectionPoolTimeoutException;
44 import org.apache.http.conn.ManagedClientConnection;
45 import org.apache.http.conn.OperatedClientConnection;
46 import org.apache.http.params.HttpParams;
47 import org.apache.http.impl.conn.DefaultClientConnectionOperator;
48 
49 
50 
51 /**
52  * Manages a pool of {@link OperatedClientConnection client connections}.
53  * <p>
54  * This class is derived from <code>MultiThreadedHttpConnectionManager</code>
55  * in HttpClient 3. See there for original authors.
56  * </p>
57  *
58  * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
59  * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
60  *
61  *
62  * <!-- empty lines to avoid svn diff problems -->
63  * @version $Revision: 673450 $ $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
64  *
65  * @since 4.0
66  */
67 public class ThreadSafeClientConnManager implements ClientConnectionManager {
68 
69     private final Log log = LogFactory.getLog(getClass());
70 
71     /** The schemes supported by this connection manager. */
72     protected SchemeRegistry schemeRegistry;
73 
74     /** The pool of connections being managed. */
75     protected final AbstractConnPool connectionPool;
76 
77     /** The operator for opening and updating connections. */
78     protected ClientConnectionOperator connOperator;
79 
80 
81 
82     /**
83      * Creates a new thread safe connection manager.
84      *
85      * @param params    the parameters for this manager
86      * @param schreg    the scheme registry, or
87      *                  <code>null</code> for the default registry
88      */
ThreadSafeClientConnManager(HttpParams params, SchemeRegistry schreg)89     public ThreadSafeClientConnManager(HttpParams params,
90                                        SchemeRegistry schreg) {
91 
92         if (params == null) {
93             throw new IllegalArgumentException("HTTP parameters may not be null");
94         }
95         this.schemeRegistry = schreg;
96         this.connOperator   = createConnectionOperator(schreg);
97         this.connectionPool = createConnectionPool(params);
98 
99     } // <constructor>
100 
101 
102     @Override
finalize()103     protected void finalize() throws Throwable {
104         shutdown();
105         super.finalize();
106     }
107 
108 
109     /**
110      * Hook for creating the connection pool.
111      *
112      * @return  the connection pool to use
113      */
createConnectionPool(final HttpParams params)114     protected AbstractConnPool createConnectionPool(final HttpParams params) {
115 
116         AbstractConnPool acp = new ConnPoolByRoute(connOperator, params);
117         boolean conngc = true; //@@@ check parameters to decide
118         if (conngc) {
119             acp.enableConnectionGC();
120         }
121         return acp;
122     }
123 
124 
125     /**
126      * Hook for creating the connection operator.
127      * It is called by the constructor.
128      * Derived classes can override this method to change the
129      * instantiation of the operator.
130      * The default implementation here instantiates
131      * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
132      *
133      * @param schreg    the scheme registry to use, or <code>null</code>
134      *
135      * @return  the connection operator to use
136      */
137     protected ClientConnectionOperator
createConnectionOperator(SchemeRegistry schreg)138         createConnectionOperator(SchemeRegistry schreg) {
139 
140         return new DefaultClientConnectionOperator(schreg);
141     }
142 
143 
144     // non-javadoc, see interface ClientConnectionManager
getSchemeRegistry()145     public SchemeRegistry getSchemeRegistry() {
146         return this.schemeRegistry;
147     }
148 
149 
requestConnection( final HttpRoute route, final Object state)150     public ClientConnectionRequest requestConnection(
151             final HttpRoute route,
152             final Object state) {
153 
154         final PoolEntryRequest poolRequest = connectionPool.requestPoolEntry(
155                 route, state);
156 
157         return new ClientConnectionRequest() {
158 
159             public void abortRequest() {
160                 poolRequest.abortRequest();
161             }
162 
163             public ManagedClientConnection getConnection(
164                     long timeout, TimeUnit tunit) throws InterruptedException,
165                     ConnectionPoolTimeoutException {
166                 if (route == null) {
167                     throw new IllegalArgumentException("Route may not be null.");
168                 }
169 
170                 if (log.isDebugEnabled()) {
171                     log.debug("ThreadSafeClientConnManager.getConnection: "
172                         + route + ", timeout = " + timeout);
173                 }
174 
175                 BasicPoolEntry entry = poolRequest.getPoolEntry(timeout, tunit);
176                 return new BasicPooledConnAdapter(ThreadSafeClientConnManager.this, entry);
177             }
178 
179         };
180 
181     }
182 
183 
184     // non-javadoc, see interface ClientConnectionManager
185     public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
186 
187         if (!(conn instanceof BasicPooledConnAdapter)) {
188             throw new IllegalArgumentException
189                 ("Connection class mismatch, " +
190                  "connection not obtained from this manager.");
191         }
192         BasicPooledConnAdapter hca = (BasicPooledConnAdapter) conn;
193         if ((hca.getPoolEntry() != null) && (hca.getManager() != this)) {
194             throw new IllegalArgumentException
195                 ("Connection not obtained from this manager.");
196         }
197 
198         try {
199             // make sure that the response has been read completely
200             if (hca.isOpen() && !hca.isMarkedReusable()) {
201                 if (log.isDebugEnabled()) {
202                     log.debug
203                         ("Released connection open but not marked reusable.");
204                 }
205                 // In MTHCM, there would be a call to
206                 // SimpleHttpConnectionManager.finishLastResponse(conn);
207                 // Consuming the response is handled outside in 4.0.
208 
209                 // make sure this connection will not be re-used
210                 // Shut down rather than close, we might have gotten here
211                 // because of a shutdown trigger.
212                 // Shutdown of the adapter also clears the tracked route.
213                 hca.shutdown();
214             }
215         } catch (IOException iox) {
216             //@@@ log as warning? let pass?
217             if (log.isDebugEnabled())
218                 log.debug("Exception shutting down released connection.",
219                           iox);
220         } finally {
221             BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
222             boolean reusable = hca.isMarkedReusable();
223             hca.detach();
224             if (entry != null) {
225                 connectionPool.freeEntry(entry, reusable, validDuration, timeUnit);
226             }
227         }
228     }
229 
230 
231     // non-javadoc, see interface ClientConnectionManager
232     public void shutdown() {
233         connectionPool.shutdown();
234     }
235 
236 
237     /**
238      * Gets the total number of pooled connections for the given route.
239      * This is the total number of connections that have been created and
240      * are still in use by this connection manager for the route.
241      * This value will not exceed the maximum number of connections per host.
242      *
243      * @param route     the route in question
244      *
245      * @return  the total number of pooled connections for that route
246      */
247     public int getConnectionsInPool(HttpRoute route) {
248         return ((ConnPoolByRoute)connectionPool).getConnectionsInPool(
249                 route);
250     }
251 
252 
253     /**
254      * Gets the total number of pooled connections.  This is the total number of
255      * connections that have been created and are still in use by this connection
256      * manager.  This value will not exceed the maximum number of connections
257      * in total.
258      *
259      * @return the total number of pooled connections
260      */
261     public int getConnectionsInPool() {
262         synchronized (connectionPool) {
263             return connectionPool.numConnections; //@@@
264         }
265     }
266 
267 
268     // non-javadoc, see interface ClientConnectionManager
269     public void closeIdleConnections(long idleTimeout, TimeUnit tunit) {
270         // combine these two in a single call?
271         connectionPool.closeIdleConnections(idleTimeout, tunit);
272         connectionPool.deleteClosedConnections();
273     }
274 
275     public void closeExpiredConnections() {
276         connectionPool.closeExpiredConnections();
277         connectionPool.deleteClosedConnections();
278     }
279 
280 
281 } // class ThreadSafeClientConnManager
282 
283