1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/IdleConnectionHandler.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 */
30package org.apache.http.impl.conn;
31
32import java.io.IOException;
33import java.util.HashMap;
34import java.util.Iterator;
35import java.util.Map;
36import java.util.concurrent.TimeUnit;
37
38import org.apache.commons.logging.Log;
39import org.apache.commons.logging.LogFactory;
40import org.apache.http.HttpConnection;
41
42
43/**
44 * A helper class for connection managers to track idle connections.
45 *
46 * <p>This class is not synchronized.</p>
47 *
48 * @see org.apache.http.conn.ClientConnectionManager#closeIdleConnections
49 *
50 * @since 4.0
51 *
52 * @deprecated Please use {@link java.net.URL#openConnection} instead.
53 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
54 *     for further details.
55 */
56@Deprecated
57public class IdleConnectionHandler {
58
59    private final Log log = LogFactory.getLog(getClass());
60
61    /** Holds connections and the time they were added. */
62    private final Map<HttpConnection,TimeValues> connectionToTimes;
63
64
65    public IdleConnectionHandler() {
66        super();
67        connectionToTimes = new HashMap<HttpConnection,TimeValues>();
68    }
69
70    /**
71     * Registers the given connection with this handler.  The connection will be held until
72     * {@link #remove} or {@link #closeIdleConnections} is called.
73     *
74     * @param connection the connection to add
75     *
76     * @see #remove
77     */
78    public void add(HttpConnection connection, long validDuration, TimeUnit unit) {
79
80        Long timeAdded = Long.valueOf(System.currentTimeMillis());
81
82        if (log.isDebugEnabled()) {
83            log.debug("Adding connection at: " + timeAdded);
84        }
85
86        connectionToTimes.put(connection, new TimeValues(timeAdded, validDuration, unit));
87    }
88
89    /**
90     * Removes the given connection from the list of connections to be closed when idle.
91     * This will return true if the connection is still valid, and false
92     * if the connection should be considered expired and not used.
93     *
94     * @param connection
95     * @return True if the connection is still valid.
96     */
97    public boolean remove(HttpConnection connection) {
98        TimeValues times = connectionToTimes.remove(connection);
99        if(times == null) {
100            log.warn("Removing a connection that never existed!");
101            return true;
102        } else {
103            return System.currentTimeMillis() <= times.timeExpires;
104        }
105    }
106
107    /**
108     * Removes all connections referenced by this handler.
109     */
110    public void removeAll() {
111        this.connectionToTimes.clear();
112    }
113
114    /**
115     * Closes connections that have been idle for at least the given amount of time.
116     *
117     * @param idleTime the minimum idle time, in milliseconds, for connections to be closed
118     */
119    //@@@ add TimeUnit argument here?
120    public void closeIdleConnections(long idleTime) {
121
122        // the latest time for which connections will be closed
123        long idleTimeout = System.currentTimeMillis() - idleTime;
124
125        if (log.isDebugEnabled()) {
126            log.debug("Checking for connections, idleTimeout: "  + idleTimeout);
127        }
128
129        Iterator<HttpConnection> connectionIter =
130            connectionToTimes.keySet().iterator();
131
132        while (connectionIter.hasNext()) {
133            HttpConnection conn = connectionIter.next();
134            TimeValues times = connectionToTimes.get(conn);
135            Long connectionTime = times.timeAdded;
136            if (connectionTime.longValue() <= idleTimeout) {
137                if (log.isDebugEnabled()) {
138                    log.debug("Closing connection, connection time: "  + connectionTime);
139                }
140                connectionIter.remove();
141                try {
142                    conn.close();
143                } catch (IOException ex) {
144                    log.debug("I/O error closing connection", ex);
145                }
146            }
147        }
148    }
149
150
151    public void closeExpiredConnections() {
152        long now = System.currentTimeMillis();
153        if (log.isDebugEnabled()) {
154            log.debug("Checking for expired connections, now: "  + now);
155        }
156
157        Iterator<HttpConnection> connectionIter =
158            connectionToTimes.keySet().iterator();
159
160        while (connectionIter.hasNext()) {
161            HttpConnection conn = connectionIter.next();
162            TimeValues times = connectionToTimes.get(conn);
163            if(times.timeExpires <= now) {
164                if (log.isDebugEnabled()) {
165                    log.debug("Closing connection, expired @: "  + times.timeExpires);
166                }
167                connectionIter.remove();
168                try {
169                    conn.close();
170                } catch (IOException ex) {
171                    log.debug("I/O error closing connection", ex);
172                }
173            }
174        }
175    }
176
177    private static class TimeValues {
178        private final long timeAdded;
179        private final long timeExpires;
180
181        /**
182         * @param now The current time in milliseconds
183         * @param validDuration The duration this connection is valid for
184         * @param validUnit The unit of time the duration is specified in.
185         */
186        TimeValues(long now, long validDuration, TimeUnit validUnit) {
187            this.timeAdded = now;
188            if(validDuration > 0) {
189                this.timeExpires = now + validUnit.toMillis(validDuration);
190            } else {
191                this.timeExpires = Long.MAX_VALUE;
192            }
193        }
194    }
195}
196