| /* |
| * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/AbstractConnPool.java $ |
| * $Revision: 673450 $ |
| * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $ |
| * |
| * ==================================================================== |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| * |
| */ |
| |
| package org.apache.http.impl.conn.tsccm; |
| |
| import java.io.IOException; |
| import java.lang.ref.Reference; |
| import java.lang.ref.ReferenceQueue; |
| import java.util.Set; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.locks.Lock; |
| import java.util.concurrent.locks.ReentrantLock; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.http.conn.ConnectionPoolTimeoutException; |
| import org.apache.http.conn.OperatedClientConnection; |
| import org.apache.http.conn.routing.HttpRoute; |
| import org.apache.http.impl.conn.IdleConnectionHandler; |
| |
| |
| /** |
| * An abstract connection pool. |
| * It is used by the {@link ThreadSafeClientConnManager}. |
| * The abstract pool includes a {@link #poolLock}, which is used to |
| * synchronize access to the internal pool datastructures. |
| * Don't use <code>synchronized</code> for that purpose! |
| * |
| * @deprecated Please use {@link java.net.URL#openConnection} instead. |
| * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> |
| * for further details. |
| */ |
| @Deprecated |
| public abstract class AbstractConnPool implements RefQueueHandler { |
| |
| private final Log log = LogFactory.getLog(getClass()); |
| |
| /** |
| * The global lock for this pool. |
| */ |
| protected final Lock poolLock; |
| |
| |
| /** |
| * References to issued connections. |
| * Objects in this set are of class |
| * {@link BasicPoolEntryRef BasicPoolEntryRef}, |
| * and point to the pool entry for the issued connection. |
| * GCed connections are detected by the missing pool entries. |
| */ |
| protected Set<BasicPoolEntryRef> issuedConnections; |
| |
| /** The handler for idle connections. */ |
| protected IdleConnectionHandler idleConnHandler; |
| |
| /** The current total number of connections. */ |
| protected int numConnections; |
| |
| /** |
| * A reference queue to track loss of pool entries to GC. |
| * The same queue is used to track loss of the connection manager, |
| * so we cannot specialize the type. |
| */ |
| protected ReferenceQueue<Object> refQueue; |
| |
| /** A worker (thread) to track loss of pool entries to GC. */ |
| private RefQueueWorker refWorker; |
| |
| |
| /** Indicates whether this pool is shut down. */ |
| protected volatile boolean isShutDown; |
| |
| /** |
| * Creates a new connection pool. |
| */ |
| protected AbstractConnPool() { |
| issuedConnections = new HashSet<BasicPoolEntryRef>(); |
| idleConnHandler = new IdleConnectionHandler(); |
| |
| boolean fair = false; //@@@ check parameters to decide |
| poolLock = new ReentrantLock(fair); |
| } |
| |
| |
| /** |
| * Enables connection garbage collection (GC). |
| * This method must be called immediately after creating the |
| * connection pool. It is not possible to enable connection GC |
| * after pool entries have been created. Neither is it possible |
| * to disable connection GC. |
| * |
| * @throws IllegalStateException |
| * if connection GC is already enabled, or if it cannot be |
| * enabled because there already are pool entries |
| */ |
| public void enableConnectionGC() |
| throws IllegalStateException { |
| |
| if (refQueue != null) { |
| throw new IllegalStateException("Connection GC already enabled."); |
| } |
| poolLock.lock(); |
| try { |
| if (numConnections > 0) { //@@@ is this check sufficient? |
| throw new IllegalStateException("Pool already in use."); |
| } |
| } finally { |
| poolLock.unlock(); |
| } |
| |
| refQueue = new ReferenceQueue<Object>(); |
| refWorker = new RefQueueWorker(refQueue, this); |
| Thread t = new Thread(refWorker); //@@@ use a thread factory |
| t.setDaemon(true); |
| t.setName("RefQueueWorker@" + this); |
| t.start(); |
| } |
| |
| |
| /** |
| * Obtains a pool entry with a connection within the given timeout. |
| * |
| * @param route the route for which to get the connection |
| * @param timeout the timeout, 0 or negative for no timeout |
| * @param tunit the unit for the <code>timeout</code>, |
| * may be <code>null</code> only if there is no timeout |
| * |
| * @return pool entry holding a connection for the route |
| * |
| * @throws ConnectionPoolTimeoutException |
| * if the timeout expired |
| * @throws InterruptedException |
| * if the calling thread was interrupted |
| */ |
| public final |
| BasicPoolEntry getEntry( |
| HttpRoute route, |
| Object state, |
| long timeout, |
| TimeUnit tunit) |
| throws ConnectionPoolTimeoutException, InterruptedException { |
| return requestPoolEntry(route, state).getPoolEntry(timeout, tunit); |
| } |
| |
| /** |
| * Returns a new {@link PoolEntryRequest}, from which a {@link BasicPoolEntry} |
| * can be obtained, or the request can be aborted. |
| */ |
| public abstract PoolEntryRequest requestPoolEntry(HttpRoute route, Object state); |
| |
| |
| /** |
| * Returns an entry into the pool. |
| * The connection of the entry is expected to be in a suitable state, |
| * either open and re-usable, or closed. The pool will not make any |
| * attempt to determine whether it can be re-used or not. |
| * |
| * @param entry the entry for the connection to release |
| * @param reusable <code>true</code> if the entry is deemed |
| * reusable, <code>false</code> otherwise. |
| * @param validDuration The duration that the entry should remain free and reusable. |
| * @param timeUnit The unit of time the duration is measured in. |
| */ |
| public abstract void freeEntry(BasicPoolEntry entry, boolean reusable, long validDuration, TimeUnit timeUnit) |
| ; |
| |
| |
| |
| // non-javadoc, see interface RefQueueHandler |
| // BEGIN android-changed |
| public void handleReference(Reference ref) { |
| // END android-changed |
| poolLock.lock(); |
| try { |
| |
| if (ref instanceof BasicPoolEntryRef) { |
| // check if the GCed pool entry was still in use |
| //@@@ find a way to detect this without lookup |
| //@@@ flag in the BasicPoolEntryRef, to be reset when freed? |
| final boolean lost = issuedConnections.remove(ref); |
| if (lost) { |
| final HttpRoute route = |
| ((BasicPoolEntryRef)ref).getRoute(); |
| if (log.isDebugEnabled()) { |
| log.debug("Connection garbage collected. " + route); |
| } |
| handleLostEntry(route); |
| } |
| } |
| |
| } finally { |
| poolLock.unlock(); |
| } |
| } |
| |
| |
| /** |
| * Handles cleaning up for a lost pool entry with the given route. |
| * A lost pool entry corresponds to a connection that was |
| * garbage collected instead of being properly released. |
| * |
| * @param route the route of the pool entry that was lost |
| */ |
| protected abstract void handleLostEntry(HttpRoute route) |
| ; |
| |
| |
| /** |
| * Closes idle connections. |
| * |
| * @param idletime the time the connections should have been idle |
| * in order to be closed now |
| * @param tunit the unit for the <code>idletime</code> |
| */ |
| public void closeIdleConnections(long idletime, TimeUnit tunit) { |
| |
| // idletime can be 0 or negative, no problem there |
| if (tunit == null) { |
| throw new IllegalArgumentException("Time unit must not be null."); |
| } |
| |
| poolLock.lock(); |
| try { |
| idleConnHandler.closeIdleConnections(tunit.toMillis(idletime)); |
| } finally { |
| poolLock.unlock(); |
| } |
| } |
| |
| public void closeExpiredConnections() { |
| poolLock.lock(); |
| try { |
| idleConnHandler.closeExpiredConnections(); |
| } finally { |
| poolLock.unlock(); |
| } |
| } |
| |
| |
| //@@@ revise this cleanup stuff (closeIdle+deleteClosed), it's not good |
| |
| /** |
| * Deletes all entries for closed connections. |
| */ |
| public abstract void deleteClosedConnections() |
| ; |
| |
| |
| /** |
| * Shuts down this pool and all associated resources. |
| * Overriding methods MUST call the implementation here! |
| */ |
| public void shutdown() { |
| |
| poolLock.lock(); |
| try { |
| |
| if (isShutDown) |
| return; |
| |
| // no point in monitoring GC anymore |
| if (refWorker != null) |
| refWorker.shutdown(); |
| |
| // close all connections that are issued to an application |
| Iterator<BasicPoolEntryRef> iter = issuedConnections.iterator(); |
| while (iter.hasNext()) { |
| BasicPoolEntryRef per = iter.next(); |
| iter.remove(); |
| BasicPoolEntry entry = per.get(); |
| if (entry != null) { |
| closeConnection(entry.getConnection()); |
| } |
| } |
| |
| // remove all references to connections |
| //@@@ use this for shutting them down instead? |
| idleConnHandler.removeAll(); |
| |
| isShutDown = true; |
| |
| } finally { |
| poolLock.unlock(); |
| } |
| } |
| |
| |
| /** |
| * Closes a connection from this pool. |
| * |
| * @param conn the connection to close, or <code>null</code> |
| */ |
| protected void closeConnection(final OperatedClientConnection conn) { |
| if (conn != null) { |
| try { |
| conn.close(); |
| } catch (IOException ex) { |
| log.debug("I/O error closing connection", ex); |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| } // class AbstractConnPool |
| |