View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.impl.conn.tsccm;
28  
29  import java.io.IOException;
30  import java.util.concurrent.TimeUnit;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.http.annotation.ThreadSafe;
35  import org.apache.http.conn.ClientConnectionManager;
36  import org.apache.http.conn.ClientConnectionOperator;
37  import org.apache.http.conn.ClientConnectionRequest;
38  import org.apache.http.conn.ConnectionPoolTimeoutException;
39  import org.apache.http.conn.ManagedClientConnection;
40  import org.apache.http.conn.OperatedClientConnection;
41  import org.apache.http.conn.params.ConnPerRouteBean;
42  import org.apache.http.conn.routing.HttpRoute;
43  import org.apache.http.conn.scheme.SchemeRegistry;
44  import org.apache.http.impl.conn.DefaultClientConnectionOperator;
45  import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
46  import org.apache.http.impl.conn.SchemeRegistryFactory;
47  import org.apache.http.params.HttpParams;
48  import org.apache.http.util.Args;
49  import org.apache.http.util.Asserts;
50  
51  /**
52   * Manages a pool of {@link OperatedClientConnection client connections} and
53   * is able to service connection requests from multiple execution threads.
54   * Connections are pooled on a per route basis. A request for a route which
55   * already the manager has persistent connections for available in the pool
56   * will be services by leasing a connection from the pool rather than
57   * creating a brand new connection.
58   * <p>
59   * ThreadSafeClientConnManager maintains a maximum limit of connection on
60   * a per route basis and in total. Per default this implementation will
61   * create no more than than 2 concurrent connections per given route
62   * and no more 20 connections in total. For many real-world applications
63   * these limits may prove too constraining, especially if they use HTTP
64   * as a transport protocol for their services. Connection limits, however,
65   * can be adjusted using HTTP parameters.
66   *
67   * @since 4.0
68   *
69   * @deprecated (4.2)  use {@link PoolingHttpClientConnectionManager}
70   */
71  @ThreadSafe
72  @Deprecated
73  public class ThreadSafeClientConnManager implements ClientConnectionManager {
74  
75      private final Log log;
76  
77      /** The schemes supported by this connection manager. */
78      protected final SchemeRegistry schemeRegistry; // @ThreadSafe
79  
80      protected final AbstractConnPool connectionPool;
81  
82      /** The pool of connections being managed. */
83      protected final ConnPoolByRoute pool;
84  
85      /** The operator for opening and updating connections. */
86      protected final ClientConnectionOperator connOperator; // DefaultClientConnectionOperator is @ThreadSafe
87  
88      protected final ConnPerRouteBean connPerRoute;
89  
90      /**
91       * Creates a new thread safe connection manager.
92       *
93       * @param schreg    the scheme registry.
94       */
95      public ThreadSafeClientConnManager(final SchemeRegistry schreg) {
96          this(schreg, -1, TimeUnit.MILLISECONDS);
97      }
98  
99      /**
100      * @since 4.1
101      */
102     public ThreadSafeClientConnManager() {
103         this(SchemeRegistryFactory.createDefault());
104     }
105 
106     /**
107      * Creates a new thread safe connection manager.
108      *
109      * @param schreg    the scheme registry.
110      * @param connTTL   max connection lifetime, <=0 implies "infinity"
111      * @param connTTLTimeUnit   TimeUnit of connTTL
112      *
113      * @since 4.1
114      */
115     public ThreadSafeClientConnManager(final SchemeRegistry schreg,
116             final long connTTL, final TimeUnit connTTLTimeUnit) {
117         this(schreg, connTTL, connTTLTimeUnit, new ConnPerRouteBean());
118     }
119 
120     /**
121      * Creates a new thread safe connection manager.
122      *
123      * @param schreg    the scheme registry.
124      * @param connTTL   max connection lifetime, <=0 implies "infinity"
125      * @param connTTLTimeUnit   TimeUnit of connTTL
126      * @param connPerRoute    mapping of maximum connections per route,
127      *   provided as a dependency so it can be managed externally, e.g.
128      *   for dynamic connection pool size management.
129      *
130      * @since 4.2
131      */
132     public ThreadSafeClientConnManager(final SchemeRegistry schreg,
133             final long connTTL, final TimeUnit connTTLTimeUnit, final ConnPerRouteBean connPerRoute) {
134         super();
135         Args.notNull(schreg, "Scheme registry");
136         this.log = LogFactory.getLog(getClass());
137         this.schemeRegistry = schreg;
138         this.connPerRoute = connPerRoute;
139         this.connOperator = createConnectionOperator(schreg);
140         this.pool = createConnectionPool(connTTL, connTTLTimeUnit) ;
141         this.connectionPool = this.pool;
142     }
143 
144     /**
145      * Creates a new thread safe connection manager.
146      *
147      * @param params    the parameters for this manager.
148      * @param schreg    the scheme registry.
149      *
150      * @deprecated (4.1)  use {@link ThreadSafeClientConnManager#ThreadSafeClientConnManager(SchemeRegistry)}
151      */
152     @Deprecated
153     public ThreadSafeClientConnManager(final HttpParams params,
154                                        final SchemeRegistry schreg) {
155         Args.notNull(schreg, "Scheme registry");
156         this.log = LogFactory.getLog(getClass());
157         this.schemeRegistry = schreg;
158         this.connPerRoute = new ConnPerRouteBean();
159         this.connOperator = createConnectionOperator(schreg);
160         this.pool = (ConnPoolByRoute) createConnectionPool(params) ;
161         this.connectionPool = this.pool;
162     }
163 
164     @Override
165     protected void finalize() throws Throwable {
166         try {
167             shutdown();
168         } finally {
169             super.finalize();
170         }
171     }
172 
173     /**
174      * Hook for creating the connection pool.
175      *
176      * @return  the connection pool to use
177      *
178      * @deprecated (4.1)  use #createConnectionPool(long, TimeUnit))
179      */
180     @Deprecated
181     protected AbstractConnPool createConnectionPool(final HttpParams params) {
182         return new ConnPoolByRoute(connOperator, params);
183     }
184 
185     /**
186      * Hook for creating the connection pool.
187      *
188      * @return  the connection pool to use
189      *
190      * @since 4.1
191      */
192     protected ConnPoolByRoute createConnectionPool(final long connTTL, final TimeUnit connTTLTimeUnit) {
193         return new ConnPoolByRoute(connOperator, connPerRoute, 20, connTTL, connTTLTimeUnit);
194     }
195 
196     /**
197      * Hook for creating the connection operator.
198      * It is called by the constructor.
199      * Derived classes can override this method to change the
200      * instantiation of the operator.
201      * The default implementation here instantiates
202      * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
203      *
204      * @param schreg    the scheme registry.
205      *
206      * @return  the connection operator to use
207      */
208     protected ClientConnectionOperator
209         createConnectionOperator(final SchemeRegistry schreg) {
210 
211         return new DefaultClientConnectionOperator(schreg);// @ThreadSafe
212     }
213 
214     public SchemeRegistry getSchemeRegistry() {
215         return this.schemeRegistry;
216     }
217 
218     public ClientConnectionRequest requestConnection(
219             final HttpRoute route,
220             final Object state) {
221 
222         final PoolEntryRequest poolRequest = pool.requestPoolEntry(
223                 route, state);
224 
225         return new ClientConnectionRequest() {
226 
227             public void abortRequest() {
228                 poolRequest.abortRequest();
229             }
230 
231             public ManagedClientConnection getConnection(
232                     final long timeout, final TimeUnit tunit) throws InterruptedException,
233                     ConnectionPoolTimeoutException {
234                 Args.notNull(route, "Route");
235 
236                 if (log.isDebugEnabled()) {
237                     log.debug("Get connection: " + route + ", timeout = " + timeout);
238                 }
239 
240                 final BasicPoolEntry entry = poolRequest.getPoolEntry(timeout, tunit);
241                 return new BasicPooledConnAdapter(ThreadSafeClientConnManager.this, entry);
242             }
243 
244         };
245 
246     }
247 
248     public void releaseConnection(final ManagedClientConnection conn, final long validDuration, final TimeUnit timeUnit) {
249         Args.check(conn instanceof BasicPooledConnAdapter, "Connection class mismatch, " +
250                 "connection not obtained from this manager");
251         final BasicPooledConnAdapter hca = (BasicPooledConnAdapter) conn;
252         if (hca.getPoolEntry() != null) {
253             Asserts.check(hca.getManager() == this, "Connection not obtained from this manager");
254         }
255         synchronized (hca) {
256             final BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
257             if (entry == null) {
258                 return;
259             }
260             try {
261                 // make sure that the response has been read completely
262                 if (hca.isOpen() && !hca.isMarkedReusable()) {
263                     // In MTHCM, there would be a call to
264                     // SimpleHttpConnectionManager.finishLastResponse(conn);
265                     // Consuming the response is handled outside in 4.0.
266 
267                     // make sure this connection will not be re-used
268                     // Shut down rather than close, we might have gotten here
269                     // because of a shutdown trigger.
270                     // Shutdown of the adapter also clears the tracked route.
271                     hca.shutdown();
272                 }
273             } catch (final IOException iox) {
274                 if (log.isDebugEnabled()) {
275                     log.debug("Exception shutting down released connection.",
276                               iox);
277                 }
278             } finally {
279                 final boolean reusable = hca.isMarkedReusable();
280                 if (log.isDebugEnabled()) {
281                     if (reusable) {
282                         log.debug("Released connection is reusable.");
283                     } else {
284                         log.debug("Released connection is not reusable.");
285                     }
286                 }
287                 hca.detach();
288                 pool.freeEntry(entry, reusable, validDuration, timeUnit);
289             }
290         }
291     }
292 
293     public void shutdown() {
294         log.debug("Shutting down");
295         pool.shutdown();
296     }
297 
298     /**
299      * Gets the total number of pooled connections for the given route.
300      * This is the total number of connections that have been created and
301      * are still in use by this connection manager for the route.
302      * This value will not exceed the maximum number of connections per host.
303      *
304      * @param route     the route in question
305      *
306      * @return  the total number of pooled connections for that route
307      */
308     public int getConnectionsInPool(final HttpRoute route) {
309         return pool.getConnectionsInPool(route);
310     }
311 
312     /**
313      * Gets the total number of pooled connections.  This is the total number of
314      * connections that have been created and are still in use by this connection
315      * manager.  This value will not exceed the maximum number of connections
316      * in total.
317      *
318      * @return the total number of pooled connections
319      */
320     public int getConnectionsInPool() {
321         return pool.getConnectionsInPool();
322     }
323 
324     public void closeIdleConnections(final long idleTimeout, final TimeUnit tunit) {
325         if (log.isDebugEnabled()) {
326             log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit);
327         }
328         pool.closeIdleConnections(idleTimeout, tunit);
329     }
330 
331     public void closeExpiredConnections() {
332         log.debug("Closing expired connections");
333         pool.closeExpiredConnections();
334     }
335 
336     /**
337      * since 4.1
338      */
339     public int getMaxTotal() {
340         return pool.getMaxTotalConnections();
341     }
342 
343     /**
344      * since 4.1
345      */
346     public void setMaxTotal(final int max) {
347         pool.setMaxTotalConnections(max);
348     }
349 
350     /**
351      * @since 4.1
352      */
353     public int getDefaultMaxPerRoute() {
354         return connPerRoute.getDefaultMaxPerRoute();
355     }
356 
357     /**
358      * @since 4.1
359      */
360     public void setDefaultMaxPerRoute(final int max) {
361         connPerRoute.setDefaultMaxPerRoute(max);
362     }
363 
364     /**
365      * @since 4.1
366      */
367     public int getMaxForRoute(final HttpRoute route) {
368         return connPerRoute.getMaxForRoute(route);
369     }
370 
371     /**
372      * @since 4.1
373      */
374     public void setMaxForRoute(final HttpRoute route, final int max) {
375         connPerRoute.setMaxForRoute(route, max);
376     }
377 
378 }
379