/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.vfs.provider.http; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpConnection; import org.apache.commons.httpclient.HttpConnectionManager; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import java.io.IOException; import java.io.InputStream; /** * A connection manager that provides access to a single HttpConnection. This * manager makes no attempt to provide exclusive access to the contained * HttpConnection. *

* imario@apache.org: Keep connection in ThreadLocal. * * @author Mario Ivankovits * @author Michael Becke * @author Eric Johnson * @author Mike Bowler * @author Oleg Kalnichevski * @author Laura Werner * @since 2.0 */ public class ThreadLocalHttpConnectionManager implements HttpConnectionManager { /** * The thread data. */ protected ThreadLocal localHttpConnection = new ThreadLocal() { protected Object initialValue() { return new Entry(); } }; /** * Collection of parameters associated with this connection manager. */ private HttpConnectionManagerParams params = new HttpConnectionManagerParams(); public ThreadLocalHttpConnectionManager() { } /** * Since the same connection is about to be reused, make sure the * previous request was completely processed, and if not * consume it now. * * @param conn The connection */ static void finishLastResponse(HttpConnection conn) { InputStream lastResponse = conn.getLastResponseInputStream(); if (lastResponse != null) { conn.setLastResponseInputStream(null); try { lastResponse.close(); } catch (IOException ioe) { //FIXME: badness - close to force reconnect. conn.close(); } } } /** * release the connection of the current thread. */ public void releaseLocalConnection() { if (getLocalHttpConnection() != null) { releaseConnection(getLocalHttpConnection()); } } /** * A connection entry. */ private static class Entry { /** * The http connection. */ private HttpConnection conn = null; /** * The time the connection was made idle. */ private long idleStartTime = Long.MAX_VALUE; private Entry() { } } protected HttpConnection getLocalHttpConnection() { return ((Entry) localHttpConnection.get()).conn; } protected void setLocalHttpConnection(HttpConnection conn) { ((Entry) localHttpConnection.get()).conn = conn; } protected long getIdleStartTime() { return ((Entry) localHttpConnection.get()).idleStartTime; } protected void setIdleStartTime(long idleStartTime) { ((Entry) localHttpConnection.get()).idleStartTime = idleStartTime; } /** * @param hostConfiguration The host configuration. * @return the HttpConnection. * @see HttpConnectionManager#getConnection(org.apache.commons.httpclient.HostConfiguration) */ public HttpConnection getConnection(HostConfiguration hostConfiguration) { return getConnection(hostConfiguration, 0); } /** * Gets the staleCheckingEnabled value to be set on HttpConnections that are created. * * @return true if stale checking will be enabled on HttpConections * @see HttpConnection#isStaleCheckingEnabled() */ public boolean isConnectionStaleCheckingEnabled() { return this.params.isStaleCheckingEnabled(); } /** * Sets the staleCheckingEnabled value to be set on HttpConnections that are created. * * @param connectionStaleCheckingEnabled true if stale checking will be enabled * on HttpConections * @see HttpConnection#setStaleCheckingEnabled(boolean) */ public void setConnectionStaleCheckingEnabled(boolean connectionStaleCheckingEnabled) { this.params.setStaleCheckingEnabled(connectionStaleCheckingEnabled); } /** * @param hostConfiguration The host configuration. * @param timeout The timeout value. * @return The HttpConnection. * @see HttpConnectionManager#getConnection(HostConfiguration, long) * @since 3.0 */ public HttpConnection getConnectionWithTimeout( HostConfiguration hostConfiguration, long timeout) { HttpConnection httpConnection = getLocalHttpConnection(); if (httpConnection == null) { httpConnection = new HttpConnection(hostConfiguration); setLocalHttpConnection(httpConnection); httpConnection.setHttpConnectionManager(this); httpConnection.getParams().setStaleCheckingEnabled(params.isStaleCheckingEnabled()); } else { // make sure the host and proxy are correct for this connection // close it and set the values if they are not if (!hostConfiguration.hostEquals(httpConnection) || !hostConfiguration.proxyEquals(httpConnection)) { if (httpConnection.isOpen()) { httpConnection.close(); } httpConnection.setHost(hostConfiguration.getHost()); httpConnection.setPort(hostConfiguration.getPort()); httpConnection.setProtocol(hostConfiguration.getProtocol()); httpConnection.setLocalAddress(hostConfiguration.getLocalAddress()); httpConnection.setProxyHost(hostConfiguration.getProxyHost()); httpConnection.setProxyPort(hostConfiguration.getProxyPort()); } else { finishLastResponse(httpConnection); } } // remove the connection from the timeout handler setIdleStartTime(Long.MAX_VALUE); return httpConnection; } /** * @param hostConfiguration The host configuration. * @param timeout The timeout value. * @return The HttpConnection. * @see HttpConnectionManager#getConnection(HostConfiguration, long) * @deprecated Use #getConnectionWithTimeout(HostConfiguration, long) */ public HttpConnection getConnection( HostConfiguration hostConfiguration, long timeout) { return getConnectionWithTimeout(hostConfiguration, timeout); } /** * @param conn The HttpConnection. * @see HttpConnectionManager#releaseConnection(org.apache.commons.httpclient.HttpConnection) */ public void releaseConnection(HttpConnection conn) { if (conn != getLocalHttpConnection()) { throw new IllegalStateException("Unexpected release of an unknown connection."); } finishLastResponse(getLocalHttpConnection()); // track the time the connection was made idle setIdleStartTime(System.currentTimeMillis()); } /** * @param idleTimeout The timeout value. * @since 3.0 */ public void closeIdleConnections(long idleTimeout) { long maxIdleTime = System.currentTimeMillis() - idleTimeout; if (getIdleStartTime() <= maxIdleTime) { getLocalHttpConnection().close(); } } public HttpConnectionManagerParams getParams() { return this.params; } public void setParams(HttpConnectionManagerParams params) { if (params == null) { throw new IllegalArgumentException("Parameters may not be null"); } this.params = params; } }