001: package org.apache.commons.vfs.provider.http;
002:
003: import org.apache.commons.httpclient.HostConfiguration;
004: import org.apache.commons.httpclient.HttpConnection;
005: import org.apache.commons.httpclient.HttpConnectionManager;
006:
007: import java.io.IOException;
008: import java.io.InputStream;
009:
010: /**
011: * A connection manager that provides access to a single HttpConnection. This
012: * manager makes no attempt to provide exclusive access to the contained
013: * HttpConnection.
014: * <p/>
015: * imario@apache.org: Keep connection in ThreadLocal.
016: *
017: * @author <a href="mailto:imario@apache.org">Mario Ivankovits</a>
018: * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
019: * @author Eric Johnson
020: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
021: * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
022: * @author Laura Werner
023: * @since 2.0
024: */
025: public class ThreadLocalHttpConnectionManager implements
026: HttpConnectionManager {
027: private static class ConnectionParameters {
028: private boolean staleCheck;
029:
030: public boolean isStaleCheckingEnabled() {
031: return staleCheck;
032: }
033:
034: public void setStaleCheckingEnabled(boolean b) {
035: staleCheck = b;
036: }
037:
038: public void populateParameters(HttpConnection connection) {
039: connection.setStaleCheckingEnabled(staleCheck);
040: }
041: }
042:
043: /**
044: * Since the same connection is about to be reused, make sure the
045: * previous request was completely processed, and if not
046: * consume it now.
047: *
048: * @param conn The connection
049: */
050: static void finishLastResponse(HttpConnection conn) {
051: InputStream lastResponse = conn.getLastResponseInputStream();
052: if (lastResponse != null) {
053: conn.setLastResponseInputStream(null);
054: try {
055: lastResponse.close();
056: } catch (IOException ioe) {
057: //FIXME: badness - close to force reconnect.
058: conn.close();
059: }
060: }
061: }
062:
063: /**
064: * The thread data
065: */
066: protected ThreadLocal localHttpConnection = new ThreadLocal() {
067: protected Object initialValue() {
068: return new Entry();
069: }
070: };
071:
072: /**
073: * Collection of parameters associated with this connection manager.
074: */
075: private ConnectionParameters params = new ConnectionParameters();
076:
077: /**
078: * release the connection of the current thread
079: */
080: public void releaseLocalConnection() {
081: if (getLocalHttpConnection() != null) {
082: releaseConnection(getLocalHttpConnection());
083: }
084: }
085:
086: private static class Entry {
087: /**
088: * The http connection
089: */
090: private HttpConnection conn = null;
091:
092: /**
093: * The time the connection was made idle.
094: */
095: private long idleStartTime = Long.MAX_VALUE;
096: }
097:
098: public ThreadLocalHttpConnectionManager() {
099: }
100:
101: protected HttpConnection getLocalHttpConnection() {
102: return ((Entry) localHttpConnection.get()).conn;
103: }
104:
105: protected void setLocalHttpConnection(HttpConnection conn) {
106: ((Entry) localHttpConnection.get()).conn = conn;
107: }
108:
109: protected long getIdleStartTime() {
110: return ((Entry) localHttpConnection.get()).idleStartTime;
111: }
112:
113: protected void setIdleStartTime(long idleStartTime) {
114: ((Entry) localHttpConnection.get()).idleStartTime = idleStartTime;
115: }
116:
117: /**
118: * @see HttpConnectionManager#getConnection(org.apache.commons.httpclient.HostConfiguration)
119: */
120: public HttpConnection getConnection(
121: HostConfiguration hostConfiguration) {
122: return getConnection(hostConfiguration, 0);
123: }
124:
125: /**
126: * Gets the staleCheckingEnabled value to be set on HttpConnections that are created.
127: *
128: * @return <code>true</code> if stale checking will be enabled on HttpConections
129: * @see HttpConnection#isStaleCheckingEnabled()
130: */
131: public boolean isConnectionStaleCheckingEnabled() {
132: return this .params.isStaleCheckingEnabled();
133: }
134:
135: /**
136: * Sets the staleCheckingEnabled value to be set on HttpConnections that are created.
137: *
138: * @param connectionStaleCheckingEnabled <code>true</code> if stale checking will be enabled
139: * on HttpConections
140: * @see HttpConnection#setStaleCheckingEnabled(boolean)
141: */
142: public void setConnectionStaleCheckingEnabled(
143: boolean connectionStaleCheckingEnabled) {
144: this .params
145: .setStaleCheckingEnabled(connectionStaleCheckingEnabled);
146: }
147:
148: /**
149: * @see HttpConnectionManager#getConnection(HostConfiguration, long)
150: * @since 3.0
151: */
152: public HttpConnection getConnectionWithTimeout(
153: HostConfiguration hostConfiguration, long timeout) {
154:
155: HttpConnection httpConnection = getLocalHttpConnection();
156: if (httpConnection == null) {
157: httpConnection = new HttpConnection(hostConfiguration);
158: setLocalHttpConnection(httpConnection);
159: httpConnection.setHttpConnectionManager(this );
160: this .params.populateParameters(httpConnection);
161: } else {
162:
163: // make sure the host and proxy are correct for this connection
164: // close it and set the values if they are not
165: if (!hostConfiguration.hostEquals(httpConnection)
166: || !hostConfiguration.proxyEquals(httpConnection)) {
167:
168: if (httpConnection.isOpen()) {
169: httpConnection.close();
170: }
171:
172: httpConnection.setHost(hostConfiguration.getHost());
173: httpConnection.setPort(hostConfiguration.getPort());
174: httpConnection.setProtocol(hostConfiguration
175: .getProtocol());
176: httpConnection.setLocalAddress(hostConfiguration
177: .getLocalAddress());
178:
179: httpConnection.setProxyHost(hostConfiguration
180: .getProxyHost());
181: httpConnection.setProxyPort(hostConfiguration
182: .getProxyPort());
183: } else {
184: finishLastResponse(httpConnection);
185: }
186: }
187:
188: // remove the connection from the timeout handler
189: setIdleStartTime(Long.MAX_VALUE);
190:
191: return httpConnection;
192: }
193:
194: /**
195: * @see HttpConnectionManager#getConnection(HostConfiguration, long)
196: * @deprecated Use #getConnectionWithTimeout(HostConfiguration, long)
197: */
198: public HttpConnection getConnection(
199: HostConfiguration hostConfiguration, long timeout) {
200: return getConnectionWithTimeout(hostConfiguration, timeout);
201: }
202:
203: /**
204: * @see HttpConnectionManager#releaseConnection(org.apache.commons.httpclient.HttpConnection)
205: */
206: public void releaseConnection(HttpConnection conn) {
207: if (conn != getLocalHttpConnection()) {
208: throw new IllegalStateException(
209: "Unexpected release of an unknown connection.");
210: }
211:
212: finishLastResponse(getLocalHttpConnection());
213:
214: // track the time the connection was made idle
215: setIdleStartTime(System.currentTimeMillis());
216: }
217:
218: /**
219: * @since 3.0
220: */
221: public void closeIdleConnections(long idleTimeout) {
222: long maxIdleTime = System.currentTimeMillis() - idleTimeout;
223: if (getIdleStartTime() <= maxIdleTime) {
224: getLocalHttpConnection().close();
225: }
226: }
227: }
|