mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/conn/tsccm/ThreadSafeClientConnManager.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial