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