• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 public class IdleConnectionHandler {
53 
54     private final Log log = LogFactory.getLog(getClass());
55 
56     /** Holds connections and the time they were added. */
57     private final Map<HttpConnection,TimeValues> connectionToTimes;
58 
59 
IdleConnectionHandler()60     public IdleConnectionHandler() {
61         super();
62         connectionToTimes = new HashMap<HttpConnection,TimeValues>();
63     }
64 
65     /**
66      * Registers the given connection with this handler.  The connection will be held until
67      * {@link #remove} or {@link #closeIdleConnections} is called.
68      *
69      * @param connection the connection to add
70      *
71      * @see #remove
72      */
add(HttpConnection connection, long validDuration, TimeUnit unit)73     public void add(HttpConnection connection, long validDuration, TimeUnit unit) {
74 
75         Long timeAdded = Long.valueOf(System.currentTimeMillis());
76 
77         if (log.isDebugEnabled()) {
78             log.debug("Adding connection at: " + timeAdded);
79         }
80 
81         connectionToTimes.put(connection, new TimeValues(timeAdded, validDuration, unit));
82     }
83 
84     /**
85      * Removes the given connection from the list of connections to be closed when idle.
86      * This will return true if the connection is still valid, and false
87      * if the connection should be considered expired and not used.
88      *
89      * @param connection
90      * @return True if the connection is still valid.
91      */
remove(HttpConnection connection)92     public boolean remove(HttpConnection connection) {
93         TimeValues times = connectionToTimes.remove(connection);
94         if(times == null) {
95             log.warn("Removing a connection that never existed!");
96             return true;
97         } else {
98             return System.currentTimeMillis() <= times.timeExpires;
99         }
100     }
101 
102     /**
103      * Removes all connections referenced by this handler.
104      */
removeAll()105     public void removeAll() {
106         this.connectionToTimes.clear();
107     }
108 
109     /**
110      * Closes connections that have been idle for at least the given amount of time.
111      *
112      * @param idleTime the minimum idle time, in milliseconds, for connections to be closed
113      */
114     //@@@ add TimeUnit argument here?
closeIdleConnections(long idleTime)115     public void closeIdleConnections(long idleTime) {
116 
117         // the latest time for which connections will be closed
118         long idleTimeout = System.currentTimeMillis() - idleTime;
119 
120         if (log.isDebugEnabled()) {
121             log.debug("Checking for connections, idleTimeout: "  + idleTimeout);
122         }
123 
124         Iterator<HttpConnection> connectionIter =
125             connectionToTimes.keySet().iterator();
126 
127         while (connectionIter.hasNext()) {
128             HttpConnection conn = connectionIter.next();
129             TimeValues times = connectionToTimes.get(conn);
130             Long connectionTime = times.timeAdded;
131             if (connectionTime.longValue() <= idleTimeout) {
132                 if (log.isDebugEnabled()) {
133                     log.debug("Closing connection, connection time: "  + connectionTime);
134                 }
135                 connectionIter.remove();
136                 try {
137                     conn.close();
138                 } catch (IOException ex) {
139                     log.debug("I/O error closing connection", ex);
140                 }
141             }
142         }
143     }
144 
145 
closeExpiredConnections()146     public void closeExpiredConnections() {
147         long now = System.currentTimeMillis();
148         if (log.isDebugEnabled()) {
149             log.debug("Checking for expired connections, now: "  + now);
150         }
151 
152         Iterator<HttpConnection> connectionIter =
153             connectionToTimes.keySet().iterator();
154 
155         while (connectionIter.hasNext()) {
156             HttpConnection conn = connectionIter.next();
157             TimeValues times = connectionToTimes.get(conn);
158             if(times.timeExpires <= now) {
159                 if (log.isDebugEnabled()) {
160                     log.debug("Closing connection, expired @: "  + times.timeExpires);
161                 }
162                 connectionIter.remove();
163                 try {
164                     conn.close();
165                 } catch (IOException ex) {
166                     log.debug("I/O error closing connection", ex);
167                 }
168             }
169         }
170     }
171 
172     private static class TimeValues {
173         private final long timeAdded;
174         private final long timeExpires;
175 
176         /**
177          * @param now The current time in milliseconds
178          * @param validDuration The duration this connection is valid for
179          * @param validUnit The unit of time the duration is specified in.
180          */
TimeValues(long now, long validDuration, TimeUnit validUnit)181         TimeValues(long now, long validDuration, TimeUnit validUnit) {
182             this.timeAdded = now;
183             if(validDuration > 0) {
184                 this.timeExpires = now + validUnit.toMillis(validDuration);
185             } else {
186                 this.timeExpires = Long.MAX_VALUE;
187             }
188         }
189     }
190 }
191