/ org.apache.commons.httpclient / src / org / apache / commons / httpclient / SimpleHttpConnectionManager.java
SimpleHttpConnectionManager.java
  1  /*
  2   * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/SimpleHttpConnectionManager.java,v 1.23 2004/10/16 22:40:08 mbecke Exp $
  3   * $Revision: 480424 $
  4   * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
  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  
 31  package org.apache.commons.httpclient;
 32  
 33  import java.io.IOException;
 34  import java.io.InputStream;
 35  
 36  import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
 37  import org.apache.commons.logging.Log;
 38  import org.apache.commons.logging.LogFactory;
 39  
 40  /**
 41   * A connection manager that provides access to a single HttpConnection.  This
 42   * manager makes no attempt to provide exclusive access to the contained
 43   * HttpConnection.
 44   *
 45   * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
 46   * @author Eric Johnson
 47   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 48   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
 49   * @author Laura Werner
 50   * 
 51   * @since 2.0
 52   */
 53  public class SimpleHttpConnectionManager implements HttpConnectionManager {
 54  
 55      private static final Log LOG = LogFactory.getLog(SimpleHttpConnectionManager.class);
 56  
 57      private static final String MISUSE_MESSAGE = 
 58          "SimpleHttpConnectionManager being used incorrectly.  Be sure that"
 59          + " HttpMethod.releaseConnection() is always called and that only one thread"
 60          + " and/or method is using this connection manager at a time.";
 61      
 62      /**
 63       * Since the same connection is about to be reused, make sure the
 64       * previous request was completely processed, and if not
 65       * consume it now.
 66       * @param conn The connection
 67       */
 68      static void finishLastResponse(HttpConnection conn) {
 69          InputStream lastResponse = conn.getLastResponseInputStream();
 70          if (lastResponse != null) {
 71              conn.setLastResponseInputStream(null);
 72              try {
 73                  lastResponse.close();
 74              } catch (IOException ioe) {
 75                  conn.close();
 76              }
 77          }
 78      }
 79      
 80      /** The http connection */
 81      protected HttpConnection httpConnection;
 82  
 83      /**
 84       * Collection of parameters associated with this connection manager.
 85       */
 86      private HttpConnectionManagerParams params = new HttpConnectionManagerParams(); 
 87  
 88      /**
 89       * The time the connection was made idle.
 90       */
 91      private long idleStartTime = Long.MAX_VALUE;
 92      
 93      /**
 94       * Used to test if {@link #httpConnection} is currently in use 
 95       * (i.e. checked out).  This is only used as a sanity check to help
 96       * debug cases where this connection manager is being used incorrectly.
 97       * It will not be used to enforce thread safety.
 98       */
 99      private volatile boolean inUse = false;
100  
101      private boolean alwaysClose = false;
102  
103      /**
104       * The connection manager created with this constructor will try to keep the 
105       * connection open (alive) between consecutive requests if the alwaysClose 
106       * parameter is set to <tt>false</tt>. Otherwise the connection manager will 
107       * always close connections upon release.
108       * 
109       * @param alwaysClose if set <tt>true</tt>, the connection manager will always
110       *    close connections upon release.
111       */
112      public SimpleHttpConnectionManager(boolean alwaysClose) {
113          super();
114          this.alwaysClose = alwaysClose;
115      }
116      
117      /**
118       * The connection manager created with this constructor will always try to keep 
119       * the connection open (alive) between consecutive requests.
120       */
121      public SimpleHttpConnectionManager() {
122          super();
123      }
124      
125      /**
126       * @see HttpConnectionManager#getConnection(HostConfiguration)
127       */
128      public HttpConnection getConnection(HostConfiguration hostConfiguration) {
129          return getConnection(hostConfiguration, 0);
130      }
131  
132      /**
133       * Gets the staleCheckingEnabled value to be set on HttpConnections that are created.
134       * 
135       * @return <code>true</code> if stale checking will be enabled on HttpConections
136       * 
137       * @see HttpConnection#isStaleCheckingEnabled()
138       * 
139       * @deprecated Use {@link HttpConnectionManagerParams#isStaleCheckingEnabled()},
140       * {@link HttpConnectionManager#getParams()}.
141       */
142      public boolean isConnectionStaleCheckingEnabled() {
143          return this.params.isStaleCheckingEnabled();
144      }
145  
146      /**
147       * Sets the staleCheckingEnabled value to be set on HttpConnections that are created.
148       * 
149       * @param connectionStaleCheckingEnabled <code>true</code> if stale checking will be enabled 
150       * on HttpConections
151       * 
152       * @see HttpConnection#setStaleCheckingEnabled(boolean)
153       * 
154       * @deprecated Use {@link HttpConnectionManagerParams#setStaleCheckingEnabled(boolean)},
155       * {@link HttpConnectionManager#getParams()}.
156       */
157      public void setConnectionStaleCheckingEnabled(boolean connectionStaleCheckingEnabled) {
158          this.params.setStaleCheckingEnabled(connectionStaleCheckingEnabled);
159      }
160      
161      /**
162       * This method always returns the same connection object. If the connection is already
163       * open, it will be closed and the new host configuration will be applied.
164       * 
165       * @param hostConfiguration The host configuration specifying the connection
166       *        details.
167       * @param timeout this parameter has no effect. The connection is always returned
168       *        immediately.
169       * @since 3.0
170       */
171      public HttpConnection getConnectionWithTimeout(
172          HostConfiguration hostConfiguration, long timeout) {
173  
174          if (httpConnection == null) {
175              httpConnection = new HttpConnection(hostConfiguration);
176              httpConnection.setHttpConnectionManager(this);
177              httpConnection.getParams().setDefaults(this.params);
178          } else {
179  
180              // make sure the host and proxy are correct for this connection
181              // close it and set the values if they are not
182              if (!hostConfiguration.hostEquals(httpConnection)
183                  || !hostConfiguration.proxyEquals(httpConnection)) {
184                      
185                  if (httpConnection.isOpen()) {
186                      httpConnection.close();
187                  }
188  
189                  httpConnection.setHost(hostConfiguration.getHost());
190                  httpConnection.setPort(hostConfiguration.getPort());
191                  httpConnection.setProtocol(hostConfiguration.getProtocol());
192                  httpConnection.setLocalAddress(hostConfiguration.getLocalAddress());
193  
194                  httpConnection.setProxyHost(hostConfiguration.getProxyHost());
195                  httpConnection.setProxyPort(hostConfiguration.getProxyPort());
196              } else {
197                  finishLastResponse(httpConnection);
198              }
199          }
200  
201          // remove the connection from the timeout handler
202          idleStartTime = Long.MAX_VALUE;
203  
204          if (inUse) LOG.warn(MISUSE_MESSAGE);
205          inUse = true;
206          
207          return httpConnection;
208      }
209  
210      /**
211       * @see HttpConnectionManager#getConnection(HostConfiguration, long)
212       * 
213       * @deprecated Use #getConnectionWithTimeout(HostConfiguration, long)
214       */
215      public HttpConnection getConnection(
216          HostConfiguration hostConfiguration, long timeout) {
217          return getConnectionWithTimeout(hostConfiguration, timeout);
218      }
219  
220      /**
221       * @see HttpConnectionManager#releaseConnection(org.apache.commons.httpclient.HttpConnection)
222       */
223      public void releaseConnection(HttpConnection conn) {
224          if (conn != httpConnection) {
225              throw new IllegalStateException("Unexpected release of an unknown connection.");
226          }
227          if (this.alwaysClose) {
228              httpConnection.close();
229          } else {
230              // make sure the connection is reuseable
231              finishLastResponse(httpConnection);
232          }
233          
234          inUse = false;
235  
236          // track the time the connection was made idle
237          idleStartTime = System.currentTimeMillis();
238      }
239  
240      /**
241       * Returns {@link HttpConnectionManagerParams parameters} associated 
242       * with this connection manager.
243       * 
244       * @since 2.1
245       * 
246       * @see HttpConnectionManagerParams
247       */
248      public HttpConnectionManagerParams getParams() {
249          return this.params;
250      }
251  
252      /**
253       * Assigns {@link HttpConnectionManagerParams parameters} for this 
254       * connection manager.
255       * 
256       * @since 2.1
257       * 
258       * @see HttpConnectionManagerParams
259       */
260      public void setParams(final HttpConnectionManagerParams params) {
261          if (params == null) {
262              throw new IllegalArgumentException("Parameters may not be null");
263          }
264          this.params = params;
265      }
266      
267      /**
268       * @since 3.0
269       */
270      public void closeIdleConnections(long idleTimeout) {
271          long maxIdleTime = System.currentTimeMillis() - idleTimeout;
272          if (idleStartTime <= maxIdleTime) {
273              httpConnection.close();
274          }
275      }
276      
277      /**
278       * since 3.1
279       */
280      public void shutdown() {
281          httpConnection.close();
282      }
283      
284  }