1 /* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/AbstractConnPool.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.lang.ref.Reference; 35 import java.lang.ref.ReferenceQueue; 36 import java.util.Set; 37 import java.util.HashSet; 38 import java.util.Iterator; 39 import java.util.concurrent.TimeUnit; 40 import java.util.concurrent.locks.Lock; 41 import java.util.concurrent.locks.ReentrantLock; 42 43 import org.apache.commons.logging.Log; 44 import org.apache.commons.logging.LogFactory; 45 import org.apache.http.conn.ConnectionPoolTimeoutException; 46 import org.apache.http.conn.OperatedClientConnection; 47 import org.apache.http.conn.routing.HttpRoute; 48 import org.apache.http.impl.conn.IdleConnectionHandler; 49 50 51 /** 52 * An abstract connection pool. 53 * It is used by the {@link ThreadSafeClientConnManager}. 54 * The abstract pool includes a {@link #poolLock}, which is used to 55 * synchronize access to the internal pool datastructures. 56 * Don't use <code>synchronized</code> for that purpose! 57 * 58 * @deprecated Please use {@link java.net.URL#openConnection} instead. 59 * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> 60 * for further details. 61 */ 62 @Deprecated 63 public abstract class AbstractConnPool implements RefQueueHandler { 64 65 private final Log log = LogFactory.getLog(getClass()); 66 67 /** 68 * The global lock for this pool. 69 */ 70 protected final Lock poolLock; 71 72 73 /** 74 * References to issued connections. 75 * Objects in this set are of class 76 * {@link BasicPoolEntryRef BasicPoolEntryRef}, 77 * and point to the pool entry for the issued connection. 78 * GCed connections are detected by the missing pool entries. 79 */ 80 protected Set<BasicPoolEntryRef> issuedConnections; 81 82 /** The handler for idle connections. */ 83 protected IdleConnectionHandler idleConnHandler; 84 85 /** The current total number of connections. */ 86 protected int numConnections; 87 88 /** 89 * A reference queue to track loss of pool entries to GC. 90 * The same queue is used to track loss of the connection manager, 91 * so we cannot specialize the type. 92 */ 93 protected ReferenceQueue<Object> refQueue; 94 95 /** A worker (thread) to track loss of pool entries to GC. */ 96 private RefQueueWorker refWorker; 97 98 99 /** Indicates whether this pool is shut down. */ 100 protected volatile boolean isShutDown; 101 102 /** 103 * Creates a new connection pool. 104 */ AbstractConnPool()105 protected AbstractConnPool() { 106 issuedConnections = new HashSet<BasicPoolEntryRef>(); 107 idleConnHandler = new IdleConnectionHandler(); 108 109 boolean fair = false; //@@@ check parameters to decide 110 poolLock = new ReentrantLock(fair); 111 } 112 113 114 /** 115 * Enables connection garbage collection (GC). 116 * This method must be called immediately after creating the 117 * connection pool. It is not possible to enable connection GC 118 * after pool entries have been created. Neither is it possible 119 * to disable connection GC. 120 * 121 * @throws IllegalStateException 122 * if connection GC is already enabled, or if it cannot be 123 * enabled because there already are pool entries 124 */ enableConnectionGC()125 public void enableConnectionGC() 126 throws IllegalStateException { 127 128 if (refQueue != null) { 129 throw new IllegalStateException("Connection GC already enabled."); 130 } 131 poolLock.lock(); 132 try { 133 if (numConnections > 0) { //@@@ is this check sufficient? 134 throw new IllegalStateException("Pool already in use."); 135 } 136 } finally { 137 poolLock.unlock(); 138 } 139 140 refQueue = new ReferenceQueue<Object>(); 141 refWorker = new RefQueueWorker(refQueue, this); 142 Thread t = new Thread(refWorker); //@@@ use a thread factory 143 t.setDaemon(true); 144 t.setName("RefQueueWorker@" + this); 145 t.start(); 146 } 147 148 149 /** 150 * Obtains a pool entry with a connection within the given timeout. 151 * 152 * @param route the route for which to get the connection 153 * @param timeout the timeout, 0 or negative for no timeout 154 * @param tunit the unit for the <code>timeout</code>, 155 * may be <code>null</code> only if there is no timeout 156 * 157 * @return pool entry holding a connection for the route 158 * 159 * @throws ConnectionPoolTimeoutException 160 * if the timeout expired 161 * @throws InterruptedException 162 * if the calling thread was interrupted 163 */ 164 public final getEntry( HttpRoute route, Object state, long timeout, TimeUnit tunit)165 BasicPoolEntry getEntry( 166 HttpRoute route, 167 Object state, 168 long timeout, 169 TimeUnit tunit) 170 throws ConnectionPoolTimeoutException, InterruptedException { 171 return requestPoolEntry(route, state).getPoolEntry(timeout, tunit); 172 } 173 174 /** 175 * Returns a new {@link PoolEntryRequest}, from which a {@link BasicPoolEntry} 176 * can be obtained, or the request can be aborted. 177 */ requestPoolEntry(HttpRoute route, Object state)178 public abstract PoolEntryRequest requestPoolEntry(HttpRoute route, Object state); 179 180 181 /** 182 * Returns an entry into the pool. 183 * The connection of the entry is expected to be in a suitable state, 184 * either open and re-usable, or closed. The pool will not make any 185 * attempt to determine whether it can be re-used or not. 186 * 187 * @param entry the entry for the connection to release 188 * @param reusable <code>true</code> if the entry is deemed 189 * reusable, <code>false</code> otherwise. 190 * @param validDuration The duration that the entry should remain free and reusable. 191 * @param timeUnit The unit of time the duration is measured in. 192 */ freeEntry(BasicPoolEntry entry, boolean reusable, long validDuration, TimeUnit timeUnit)193 public abstract void freeEntry(BasicPoolEntry entry, boolean reusable, long validDuration, TimeUnit timeUnit) 194 ; 195 196 197 198 // non-javadoc, see interface RefQueueHandler 199 // BEGIN android-changed handleReference(Reference ref)200 public void handleReference(Reference ref) { 201 // END android-changed 202 poolLock.lock(); 203 try { 204 205 if (ref instanceof BasicPoolEntryRef) { 206 // check if the GCed pool entry was still in use 207 //@@@ find a way to detect this without lookup 208 //@@@ flag in the BasicPoolEntryRef, to be reset when freed? 209 final boolean lost = issuedConnections.remove(ref); 210 if (lost) { 211 final HttpRoute route = 212 ((BasicPoolEntryRef)ref).getRoute(); 213 if (log.isDebugEnabled()) { 214 log.debug("Connection garbage collected. " + route); 215 } 216 handleLostEntry(route); 217 } 218 } 219 220 } finally { 221 poolLock.unlock(); 222 } 223 } 224 225 226 /** 227 * Handles cleaning up for a lost pool entry with the given route. 228 * A lost pool entry corresponds to a connection that was 229 * garbage collected instead of being properly released. 230 * 231 * @param route the route of the pool entry that was lost 232 */ handleLostEntry(HttpRoute route)233 protected abstract void handleLostEntry(HttpRoute route) 234 ; 235 236 237 /** 238 * Closes idle connections. 239 * 240 * @param idletime the time the connections should have been idle 241 * in order to be closed now 242 * @param tunit the unit for the <code>idletime</code> 243 */ closeIdleConnections(long idletime, TimeUnit tunit)244 public void closeIdleConnections(long idletime, TimeUnit tunit) { 245 246 // idletime can be 0 or negative, no problem there 247 if (tunit == null) { 248 throw new IllegalArgumentException("Time unit must not be null."); 249 } 250 251 poolLock.lock(); 252 try { 253 idleConnHandler.closeIdleConnections(tunit.toMillis(idletime)); 254 } finally { 255 poolLock.unlock(); 256 } 257 } 258 closeExpiredConnections()259 public void closeExpiredConnections() { 260 poolLock.lock(); 261 try { 262 idleConnHandler.closeExpiredConnections(); 263 } finally { 264 poolLock.unlock(); 265 } 266 } 267 268 269 //@@@ revise this cleanup stuff (closeIdle+deleteClosed), it's not good 270 271 /** 272 * Deletes all entries for closed connections. 273 */ deleteClosedConnections()274 public abstract void deleteClosedConnections() 275 ; 276 277 278 /** 279 * Shuts down this pool and all associated resources. 280 * Overriding methods MUST call the implementation here! 281 */ shutdown()282 public void shutdown() { 283 284 poolLock.lock(); 285 try { 286 287 if (isShutDown) 288 return; 289 290 // no point in monitoring GC anymore 291 if (refWorker != null) 292 refWorker.shutdown(); 293 294 // close all connections that are issued to an application 295 Iterator<BasicPoolEntryRef> iter = issuedConnections.iterator(); 296 while (iter.hasNext()) { 297 BasicPoolEntryRef per = iter.next(); 298 iter.remove(); 299 BasicPoolEntry entry = per.get(); 300 if (entry != null) { 301 closeConnection(entry.getConnection()); 302 } 303 } 304 305 // remove all references to connections 306 //@@@ use this for shutting them down instead? 307 idleConnHandler.removeAll(); 308 309 isShutDown = true; 310 311 } finally { 312 poolLock.unlock(); 313 } 314 } 315 316 317 /** 318 * Closes a connection from this pool. 319 * 320 * @param conn the connection to close, or <code>null</code> 321 */ closeConnection(final OperatedClientConnection conn)322 protected void closeConnection(final OperatedClientConnection conn) { 323 if (conn != null) { 324 try { 325 conn.close(); 326 } catch (IOException ex) { 327 log.debug("I/O error closing connection", ex); 328 } 329 } 330 } 331 332 333 334 335 336 } // class AbstractConnPool 337 338