SingleClientConnManager.java revision 069490a5ca2fd1988d29daf45d892f47ad665115
1069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/*
2069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/SingleClientConnManager.java $
3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Revision: 673450 $
4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
5069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
6069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
7069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one
8069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * or more contributor license agreements.  See the NOTICE file
9069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * distributed with this work for additional information
10069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * regarding copyright ownership.  The ASF licenses this file
11069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * to you under the Apache License, Version 2.0 (the
12069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "License"); you may not use this file except in compliance
13069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * with the License.  You may obtain a copy of the License at
14069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
15069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *   http://www.apache.org/licenses/LICENSE-2.0
16069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
17069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Unless required by applicable law or agreed to in writing,
18069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * software distributed under the License is distributed on an
19069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * KIND, either express or implied.  See the License for the
21069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * specific language governing permissions and limitations
22069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * under the License.
23069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
24069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
25069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This software consists of voluntary contributions made by many
26069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * individuals on behalf of the Apache Software Foundation.  For more
27069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * information on the Apache Software Foundation, please see
28069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <http://www.apache.org/>.
29069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
30069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
31069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
32069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpackage org.apache.http.impl.conn;
33069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
34069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.io.IOException;
35069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.concurrent.TimeUnit;
36069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
37069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.commons.logging.Log;
38069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.commons.logging.LogFactory;
39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.conn.ClientConnectionManager;
40069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.conn.ClientConnectionOperator;
41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.conn.ClientConnectionRequest;
42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.conn.ManagedClientConnection;
43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.conn.routing.HttpRoute;
44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.conn.routing.RouteTracker;
45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.conn.scheme.SchemeRegistry;
46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.params.HttpParams;
47069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
48069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
49069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/**
50069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * A connection "manager" for a single connection.
51069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This manager is good only for single-threaded use.
52069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Allocation <i>always</i> returns the connection immediately,
53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * even if it has not been released after the previous allocation.
54069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * In that case, a {@link #MISUSE_MESSAGE warning} is logged
55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * and the previously issued connection is revoked.
56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <p>
57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This class is derived from <code>SimpleHttpConnectionManager</code>
58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * in HttpClient 3. See there for original authors.
59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * </p>
60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <!-- empty lines to avoid svn diff problems -->
66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @version   $Revision: 673450 $
67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @since 4.0
69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic class SingleClientConnManager implements ClientConnectionManager {
71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private final Log log = LogFactory.getLog(getClass());
73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The message to be logged on multiple allocation. */
75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final static String MISUSE_MESSAGE =
76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    "Invalid use of SingleClientConnManager: connection still allocated.\n" +
77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    "Make sure to release the connection before allocating another one.";
78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The schemes supported by this connection manager. */
81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected SchemeRegistry schemeRegistry;
82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The operator for opening and updating connections. */
84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected ClientConnectionOperator connOperator;
85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The one and only entry in this pool. */
87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected PoolEntry uniquePoolEntry;
88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The currently issued managed connection, if any. */
90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected ConnAdapter managedConn;
91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The time of the last connection release, or -1. */
93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected long lastReleaseTime;
94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The time the last released connection expires and shouldn't be reused. */
96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected long connectionExpiresTime;
97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** Whether the connection should be shut down  on release. */
99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected boolean alwaysShutDown;
100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** Indicates whether this connection manager is shut down. */
102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected volatile boolean isShutDown;
103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Creates a new simple connection manager.
109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param params    the parameters for this manager
111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param schreg    the scheme registry, or
112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  <code>null</code> for the default registry
113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public SingleClientConnManager(HttpParams params,
115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                                   SchemeRegistry schreg) {
116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (schreg == null) {
118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Scheme registry must not be null.");
120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.schemeRegistry  = schreg;
122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.connOperator    = createConnectionOperator(schreg);
123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.uniquePoolEntry = new PoolEntry();
124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.managedConn     = null;
125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.lastReleaseTime = -1L;
126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.alwaysShutDown  = false; //@@@ from params? as argument?
127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.isShutDown      = false;
128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    } // <constructor>
130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    @Override
133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected void finalize() throws Throwable {
134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        shutdown();
135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        super.finalize();
136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-javadoc, see interface ClientConnectionManager
140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public SchemeRegistry getSchemeRegistry() {
141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return this.schemeRegistry;
142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Hook for creating the connection operator.
147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * It is called by the constructor.
148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Derived classes can override this method to change the
149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * instantiation of the operator.
150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The default implementation here instantiates
151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param schreg    the scheme registry to use, or <code>null</code>
154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the connection operator to use
156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected ClientConnectionOperator
158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        createConnectionOperator(SchemeRegistry schreg) {
159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return new DefaultClientConnectionOperator(schreg);
161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Asserts that this manager is not shut down.
166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws IllegalStateException    if this manager is shut down
168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected final void assertStillUp()
170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throws IllegalStateException {
171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.isShutDown)
173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalStateException("Manager is shut down.");
174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final ClientConnectionRequest requestConnection(
178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            final HttpRoute route,
179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            final Object state) {
180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return new ClientConnectionRequest() {
182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            public void abortRequest() {
184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                // Nothing to abort, since requests are immediate.
185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            public ManagedClientConnection getConnection(
188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    long timeout, TimeUnit tunit) {
189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                return SingleClientConnManager.this.getConnection(
190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        route, state);
191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        };
194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
197069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
198069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Obtains a connection.
199069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * This method does not block.
200069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
201069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param route     where the connection should point to
202069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
203069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  a connection that can be used to communicate
204069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          along the given route
205069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
206069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public ManagedClientConnection getConnection(HttpRoute route, Object state) {
207069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
208069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (route == null) {
209069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException("Route may not be null.");
210069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
211069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        assertStillUp();
212069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
213069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (log.isDebugEnabled()) {
214069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            log.debug("Get connection for route " + route);
215069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
216069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
217069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (managedConn != null)
218069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            revokeConnection();
219069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
220069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // check re-usability of the connection
221069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean recreate = false;
222069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean shutdown = false;
223069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
224069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // Kill the connection if it expired.
225069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        closeExpiredConnections();
226069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
227069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (uniquePoolEntry.connection.isOpen()) {
228069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            RouteTracker tracker = uniquePoolEntry.tracker;
229069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            shutdown = (tracker == null || // can happen if method is aborted
230069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        !tracker.toRoute().equals(route));
231069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } else {
232069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // If the connection is not open, create a new PoolEntry,
233069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // as the connection may have been marked not reusable,
234069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // due to aborts -- and the PoolEntry should not be reused
235069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // either.  There's no harm in recreating an entry if
236069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // the connection is closed.
237069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            recreate = true;
238069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
239069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
240069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (shutdown) {
241069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            recreate = true;
242069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            try {
243069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                uniquePoolEntry.shutdown();
244069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } catch (IOException iox) {
245069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                log.debug("Problem shutting down connection.", iox);
246069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
247069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
248069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
249069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (recreate)
250069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            uniquePoolEntry = new PoolEntry();
251069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
252069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        managedConn = new ConnAdapter(uniquePoolEntry, route);
253069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
254069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return managedConn;
255069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
256069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
257069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
258069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-javadoc, see interface ClientConnectionManager
259069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
260069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        assertStillUp();
261069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
262069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (!(conn instanceof ConnAdapter)) {
263069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
264069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Connection class mismatch, " +
265069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                 "connection not obtained from this manager.");
266069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
267069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
268069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (log.isDebugEnabled()) {
269069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            log.debug("Releasing connection " + conn);
270069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
271069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
272069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        ConnAdapter sca = (ConnAdapter) conn;
273069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (sca.poolEntry == null)
274069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return; // already released
275069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        ClientConnectionManager manager = sca.getManager();
276069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (manager != null && manager != this) {
277069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
278069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Connection not obtained from this manager.");
279069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
280069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
281069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        try {
282069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // make sure that the response has been read completely
283069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (sca.isOpen() && (this.alwaysShutDown ||
284069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                                 !sca.isMarkedReusable())
285069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ) {
286069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                if (log.isDebugEnabled()) {
287069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    log.debug
288069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        ("Released connection open but not reusable.");
289069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                }
290069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
291069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                // make sure this connection will not be re-used
292069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                // we might have gotten here because of a shutdown trigger
293069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                // shutdown of the adapter also clears the tracked route
294069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                sca.shutdown();
295069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
296069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } catch (IOException iox) {
297069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            //@@@ log as warning? let pass?
298069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (log.isDebugEnabled())
299069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                log.debug("Exception shutting down released connection.",
300069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                          iox);
301069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } finally {
302069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            sca.detach();
303069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            managedConn = null;
304069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            lastReleaseTime = System.currentTimeMillis();
305069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if(validDuration > 0)
306069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                connectionExpiresTime = timeUnit.toMillis(validDuration) + lastReleaseTime;
307069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            else
308069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                connectionExpiresTime = Long.MAX_VALUE;
309069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
310069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    } // releaseConnection
311069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
312069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public void closeExpiredConnections() {
313069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if(System.currentTimeMillis() >= connectionExpiresTime) {
314069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            closeIdleConnections(0, TimeUnit.MILLISECONDS);
315069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
316069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
317069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
318069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
319069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-javadoc, see interface ClientConnectionManager
320069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public void closeIdleConnections(long idletime, TimeUnit tunit) {
321069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        assertStillUp();
322069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
323069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // idletime can be 0 or negative, no problem there
324069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (tunit == null) {
325069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException("Time unit must not be null.");
326069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
327069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
328069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if ((managedConn == null) && uniquePoolEntry.connection.isOpen()) {
329069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            final long cutoff =
330069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                System.currentTimeMillis() - tunit.toMillis(idletime);
331069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (lastReleaseTime <= cutoff) {
332069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                try {
333069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    uniquePoolEntry.close();
334069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                } catch (IOException iox) {
335069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    // ignore
336069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    log.debug("Problem closing idle connection.", iox);
337069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                }
338069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
339069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
340069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
341069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
342069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
343069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-javadoc, see interface ClientConnectionManager
344069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public void shutdown() {
345069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
346069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.isShutDown = true;
347069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
348069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (managedConn != null)
349069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            managedConn.detach();
350069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
351069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        try {
352069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (uniquePoolEntry != null) // and connection open?
353069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                uniquePoolEntry.shutdown();
354069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } catch (IOException iox) {
355069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // ignore
356069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            log.debug("Problem while shutting down manager.", iox);
357069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } finally {
358069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            uniquePoolEntry = null;
359069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
360069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
361069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
362069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
363069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
364069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Revokes the currently issued connection.
365069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The adapter gets disconnected, the connection will be shut down.
366069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
367069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected void revokeConnection() {
368069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (managedConn == null)
369069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return;
370069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
371069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        log.warn(MISUSE_MESSAGE);
372069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
373069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        managedConn.detach();
374069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
375069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        try {
376069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            uniquePoolEntry.shutdown();
377069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } catch (IOException iox) {
378069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // ignore
379069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            log.debug("Problem while shutting down connection.", iox);
380069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
381069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
382069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
383069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
384069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
385069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The pool entry for this connection manager.
386069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
387069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected class PoolEntry extends AbstractPoolEntry {
388069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
389069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        /**
390069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * Creates a new pool entry.
391069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *
392069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         */
393069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        protected PoolEntry() {
394069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            super(SingleClientConnManager.this.connOperator, null);
395069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
396069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
397069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        /**
398069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * Closes the connection in this pool entry.
399069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         */
400069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        protected void close()
401069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throws IOException {
402069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
403069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            shutdownEntry();
404069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (connection.isOpen())
405069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                connection.close();
406069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
407069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
408069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
409069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        /**
410069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * Shuts down the connection in this pool entry.
411069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         */
412069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        protected void shutdown()
413069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throws IOException {
414069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
415069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            shutdownEntry();
416069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (connection.isOpen())
417069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                connection.shutdown();
418069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
419069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
420069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    } // class PoolEntry
421069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
422069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
423069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
424069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
425069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The connection adapter used by this manager.
426069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
427069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected class ConnAdapter extends AbstractPooledConnAdapter {
428069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
429069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        /**
430069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * Creates a new connection adapter.
431069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *
432069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * @param entry   the pool entry for the connection being wrapped
433069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * @param route   the planned route for this connection
434069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         */
435069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        protected ConnAdapter(PoolEntry entry, HttpRoute route) {
436069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            super(SingleClientConnManager.this, entry);
437069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            markReusable();
438069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            entry.route = route;
439069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
440069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
441069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
442069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
443069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
444069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project} // class SingleClientConnManager
445