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  */
30 package org.apache.http.impl.conn;
31 
32 import java.io.IOException;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.Map;
36 import java.util.concurrent.TimeUnit;
37 
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import 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
57 public 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 
IdleConnectionHandler()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      */
add(HttpConnection connection, long validDuration, TimeUnit unit)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      */
remove(HttpConnection connection)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      */
removeAll()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?
closeIdleConnections(long idleTime)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 
closeExpiredConnections()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          */
TimeValues(long now, long validDuration, TimeUnit validUnit)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