Home | History | Annotate | Download | only in conn
      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 
     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      */
     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      */
     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      */
    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?
    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 
    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          */
    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