1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.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
31package org.apache.http.impl.conn.tsccm;
32
33import java.io.IOException;
34import java.net.Socket;
35import java.util.concurrent.TimeUnit;
36
37import android.net.TrafficStats;
38import org.apache.commons.logging.Log;
39import org.apache.commons.logging.LogFactory;
40import org.apache.http.conn.routing.HttpRoute;
41import org.apache.http.conn.scheme.SchemeRegistry;
42import org.apache.http.conn.ClientConnectionManager;
43import org.apache.http.conn.ClientConnectionOperator;
44import org.apache.http.conn.ClientConnectionRequest;
45import org.apache.http.conn.ConnectionPoolTimeoutException;
46import org.apache.http.conn.ManagedClientConnection;
47import org.apache.http.conn.OperatedClientConnection;
48import org.apache.http.params.HttpParams;
49import org.apache.http.impl.conn.DefaultClientConnectionOperator;
50
51
52
53/**
54 * Manages a pool of {@link OperatedClientConnection client connections}.
55 * <p>
56 * This class is derived from <code>MultiThreadedHttpConnectionManager</code>
57 * in HttpClient 3. See there for original authors.
58 * </p>
59 *
60 * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
61 * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
62 *
63 *
64 * <!-- empty lines to avoid svn diff problems -->
65 * @version $Revision: 673450 $ $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
66 *
67 * @since 4.0
68 *
69 * @deprecated Please use {@link java.net.URL#openConnection} instead.
70 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
71 *     for further details.
72 */
73@Deprecated
74public class ThreadSafeClientConnManager implements ClientConnectionManager {
75
76    private final Log log = LogFactory.getLog(getClass());
77
78    /** The schemes supported by this connection manager. */
79    protected SchemeRegistry schemeRegistry;
80
81    /** The pool of connections being managed. */
82    protected final AbstractConnPool connectionPool;
83
84    /** The operator for opening and updating connections. */
85    protected ClientConnectionOperator connOperator;
86
87
88
89    /**
90     * Creates a new thread safe connection manager.
91     *
92     * @param params    the parameters for this manager
93     * @param schreg    the scheme registry
94     */
95    public ThreadSafeClientConnManager(HttpParams params,
96                                       SchemeRegistry schreg) {
97
98        if (params == null) {
99            throw new IllegalArgumentException("HTTP parameters may not be null");
100        }
101        this.schemeRegistry = schreg;
102        this.connOperator   = createConnectionOperator(schreg);
103        this.connectionPool = createConnectionPool(params);
104
105    } // <constructor>
106
107
108    @Override
109    protected void finalize() throws Throwable {
110        shutdown();
111        super.finalize();
112    }
113
114
115    /**
116     * Hook for creating the connection pool.
117     *
118     * @return  the connection pool to use
119     */
120    protected AbstractConnPool createConnectionPool(final HttpParams params) {
121
122        AbstractConnPool acp = new ConnPoolByRoute(connOperator, params);
123        boolean conngc = true; //@@@ check parameters to decide
124        if (conngc) {
125            acp.enableConnectionGC();
126        }
127        return acp;
128    }
129
130
131    /**
132     * Hook for creating the connection operator.
133     * It is called by the constructor.
134     * Derived classes can override this method to change the
135     * instantiation of the operator.
136     * The default implementation here instantiates
137     * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
138     *
139     * @param schreg    the scheme registry to use, or <code>null</code>
140     *
141     * @return  the connection operator to use
142     */
143    protected ClientConnectionOperator
144        createConnectionOperator(SchemeRegistry schreg) {
145
146        return new DefaultClientConnectionOperator(schreg);
147    }
148
149
150    // non-javadoc, see interface ClientConnectionManager
151    public SchemeRegistry getSchemeRegistry() {
152        return this.schemeRegistry;
153    }
154
155
156    public ClientConnectionRequest requestConnection(
157            final HttpRoute route,
158            final Object state) {
159
160        final PoolEntryRequest poolRequest = connectionPool.requestPoolEntry(
161                route, state);
162
163        return new ClientConnectionRequest() {
164
165            public void abortRequest() {
166                poolRequest.abortRequest();
167            }
168
169            public ManagedClientConnection getConnection(
170                    long timeout, TimeUnit tunit) throws InterruptedException,
171                    ConnectionPoolTimeoutException {
172                if (route == null) {
173                    throw new IllegalArgumentException("Route may not be null.");
174                }
175
176                if (log.isDebugEnabled()) {
177                    log.debug("ThreadSafeClientConnManager.getConnection: "
178                        + route + ", timeout = " + timeout);
179                }
180
181                BasicPoolEntry entry = poolRequest.getPoolEntry(timeout, tunit);
182                // BEGIN android-changed
183                // When using a recycled Socket, we need to re-tag it with any
184                // updated statistics options.
185                try {
186                    final Socket socket = entry.getConnection().getSocket();
187                    if (socket != null) {
188                        TrafficStats.tagSocket(socket);
189                    }
190                } catch (IOException iox) {
191                    log.debug("Problem tagging socket.", iox);
192                }
193                // END android-changed
194                return new BasicPooledConnAdapter(ThreadSafeClientConnManager.this, entry);
195            }
196
197        };
198
199    }
200
201
202    // non-javadoc, see interface ClientConnectionManager
203    public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
204
205        if (!(conn instanceof BasicPooledConnAdapter)) {
206            throw new IllegalArgumentException
207                ("Connection class mismatch, " +
208                 "connection not obtained from this manager.");
209        }
210        BasicPooledConnAdapter hca = (BasicPooledConnAdapter) conn;
211        if ((hca.getPoolEntry() != null) && (hca.getManager() != this)) {
212            throw new IllegalArgumentException
213                ("Connection not obtained from this manager.");
214        }
215
216        try {
217            // BEGIN android-changed
218            // When recycling a Socket, we un-tag it to avoid collecting
219            // statistics from future users.
220            final BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
221            final Socket socket = entry.getConnection().getSocket();
222            if (socket != null) {
223                TrafficStats.untagSocket(socket);
224            }
225            // END android-changed
226
227            // make sure that the response has been read completely
228            if (hca.isOpen() && !hca.isMarkedReusable()) {
229                if (log.isDebugEnabled()) {
230                    log.debug
231                        ("Released connection open but not marked reusable.");
232                }
233                // In MTHCM, there would be a call to
234                // SimpleHttpConnectionManager.finishLastResponse(conn);
235                // Consuming the response is handled outside in 4.0.
236
237                // make sure this connection will not be re-used
238                // Shut down rather than close, we might have gotten here
239                // because of a shutdown trigger.
240                // Shutdown of the adapter also clears the tracked route.
241                hca.shutdown();
242            }
243        } catch (IOException iox) {
244            //@@@ log as warning? let pass?
245            if (log.isDebugEnabled())
246                log.debug("Exception shutting down released connection.",
247                          iox);
248        } finally {
249            BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
250            boolean reusable = hca.isMarkedReusable();
251            hca.detach();
252            if (entry != null) {
253                connectionPool.freeEntry(entry, reusable, validDuration, timeUnit);
254            }
255        }
256    }
257
258
259    // non-javadoc, see interface ClientConnectionManager
260    public void shutdown() {
261        connectionPool.shutdown();
262    }
263
264
265    /**
266     * Gets the total number of pooled connections for the given route.
267     * This is the total number of connections that have been created and
268     * are still in use by this connection manager for the route.
269     * This value will not exceed the maximum number of connections per host.
270     *
271     * @param route     the route in question
272     *
273     * @return  the total number of pooled connections for that route
274     */
275    public int getConnectionsInPool(HttpRoute route) {
276        return ((ConnPoolByRoute)connectionPool).getConnectionsInPool(
277                route);
278    }
279
280
281    /**
282     * Gets the total number of pooled connections.  This is the total number of
283     * connections that have been created and are still in use by this connection
284     * manager.  This value will not exceed the maximum number of connections
285     * in total.
286     *
287     * @return the total number of pooled connections
288     */
289    public int getConnectionsInPool() {
290        synchronized (connectionPool) {
291            return connectionPool.numConnections; //@@@
292        }
293    }
294
295
296    // non-javadoc, see interface ClientConnectionManager
297    public void closeIdleConnections(long idleTimeout, TimeUnit tunit) {
298        // combine these two in a single call?
299        connectionPool.closeIdleConnections(idleTimeout, tunit);
300        connectionPool.deleteClosedConnections();
301    }
302
303    public void closeExpiredConnections() {
304        connectionPool.closeExpiredConnections();
305        connectionPool.deleteClosedConnections();
306    }
307
308
309} // class ThreadSafeClientConnManager
310
311