You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by mb...@apache.org on 2004/04/25 23:49:35 UTC
cvs commit: jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util IdleConnectionHandler.java IdleConnectionTimeoutThread.java
mbecke 2004/04/25 14:49:35
Modified: httpclient/src/java/org/apache/commons/httpclient
SimpleHttpConnectionManager.java ProxyClient.java
HttpConnectionManager.java
MultiThreadedHttpConnectionManager.java
httpclient/src/test/org/apache/commons/httpclient
NoHostHttpConnectionManager.java TestNoHost.java
Added: httpclient/src/test/org/apache/commons/httpclient
TestIdleConnectionTimeout.java
httpclient/src/java/org/apache/commons/httpclient/util
IdleConnectionHandler.java
IdleConnectionTimeoutThread.java
Log:
Adds support for closing idle connections.
PR: 25372
Submitted by: Michael Becke
Reviewed by: Oleg Kalnichevski
Revision Changes Path
1.19 +46 -22 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/SimpleHttpConnectionManager.java
Index: SimpleHttpConnectionManager.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/SimpleHttpConnectionManager.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- SimpleHttpConnectionManager.java 18 Apr 2004 23:51:35 -0000 1.18
+++ SimpleHttpConnectionManager.java 25 Apr 2004 21:49:34 -0000 1.19
@@ -49,6 +49,25 @@
*/
public class SimpleHttpConnectionManager implements HttpConnectionManager {
+ /**
+ * 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();
+ }
+ }
+ }
+
/** The http connection */
private HttpConnection httpConnection;
@@ -58,6 +77,14 @@
private HttpConnectionManagerParams params = new HttpConnectionManagerParams();
/**
+ * The time the connection was made idle.
+ */
+ private long idleStartTime = Long.MAX_VALUE;
+
+ public SimpleHttpConnectionManager() {
+ }
+
+ /**
* @see HttpConnectionManager#getConnection(HostConfiguration)
*/
public HttpConnection getConnection(HostConfiguration hostConfiguration) {
@@ -127,6 +154,9 @@
}
}
+ // remove the connection from the timeout handler
+ idleStartTime = Long.MAX_VALUE;
+
return httpConnection;
}
@@ -149,25 +179,9 @@
}
finishLastResponse(httpConnection);
- }
-
- /**
- * 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();
- }
- }
+
+ // track the time the connection was made idle
+ idleStartTime = System.currentTimeMillis();
}
/**
@@ -195,5 +209,15 @@
throw new IllegalArgumentException("Parameters may not be null");
}
this.params = params;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.commons.httpclient.HttpConnectionManager#closeIdleConnections(long)
+ */
+ public void closeIdleConnections(long idleTimeout) {
+ long maxIdleTime = System.currentTimeMillis() - idleTimeout;
+ if (idleStartTime <= maxIdleTime) {
+ httpConnection.close();
+ }
}
}
1.3 +7 -4 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ProxyClient.java
Index: ProxyClient.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ProxyClient.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ProxyClient.java 18 Apr 2004 23:51:35 -0000 1.2
+++ ProxyClient.java 25 Apr 2004 21:49:34 -0000 1.3
@@ -267,6 +267,9 @@
private HttpParams connectionParams;
+ public void closeIdleConnections(long idleTimeout) {
+ }
+
public HttpConnection getConnection() {
return httpConnection;
}
1.20 +15 -7 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnectionManager.java
Index: HttpConnectionManager.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnectionManager.java,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- HttpConnectionManager.java 18 Apr 2004 23:51:35 -0000 1.19
+++ HttpConnectionManager.java 25 Apr 2004 21:49:34 -0000 1.20
@@ -117,22 +117,30 @@
void releaseConnection(HttpConnection conn);
/**
+ * Closes connections that have been idle for at least the given amount of time. Only
+ * connections that are currently owned, not checked out, are subject to idle timeouts.
+ *
+ * @param idleTime the minimum idle time, in milliseconds, for connections to be closed
+ */
+ void closeIdleConnections(long idleTimeout);
+
+ /**
* Returns {@link HttpConnectionManagerParams parameters} associated
* with this connection manager.
*
- * @since 2.1
+ * @since 3.0
*
* @see HttpConnectionManagerParams
*/
- public HttpConnectionManagerParams getParams();
+ HttpConnectionManagerParams getParams();
/**
* Assigns {@link HttpConnectionManagerParams parameters} for this
* connection manager.
*
- * @since 2.1
+ * @since 3.0
*
* @see HttpConnectionManagerParams
*/
- public void setParams(final HttpConnectionManagerParams params);
+ void setParams(final HttpConnectionManagerParams params);
}
1.36 +35 -4 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java
Index: MultiThreadedHttpConnectionManager.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- MultiThreadedHttpConnectionManager.java 18 Apr 2004 23:51:35 -0000 1.35
+++ MultiThreadedHttpConnectionManager.java 25 Apr 2004 21:49:34 -0000 1.36
@@ -47,6 +47,7 @@
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.util.IdleConnectionHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -547,6 +548,13 @@
}
}
+ /* (non-Javadoc)
+ * @see org.apache.commons.httpclient.HttpConnectionManager#closeIdleConnections(long)
+ */
+ public void closeIdleConnections(long idleTimeout) {
+ connectionPool.closeIdleConnections(idleTimeout);
+ }
+
/**
* Make the given HttpConnection available for use by other requests.
* If another thread is blocked in getConnection() that could use this
@@ -640,6 +648,8 @@
*/
private final Map mapHosts = new HashMap();
+ private IdleConnectionHandler idleConnectionHandler = new IdleConnectionHandler();
+
/** The number of created connections */
private int numConnections = 0;
@@ -669,6 +679,9 @@
// clear out map hosts
mapHosts.clear();
+
+ // remove all references to connections
+ idleConnectionHandler.removeAll();
}
/**
@@ -770,6 +783,9 @@
if (LOG.isDebugEnabled()) {
LOG.debug("Getting free connection, hostConfig=" + hostConfiguration);
}
+
+ // remove the connection from the timeout handler
+ idleConnectionHandler.remove(connection);
} else if (LOG.isDebugEnabled()) {
LOG.debug("There were no free connections to get, hostConfig="
+ hostConfiguration);
@@ -778,6 +794,14 @@
}
/**
+ * Closes idle connections.
+ * @param idleTimeout
+ */
+ public synchronized void closeIdleConnections(long idleTimeout) {
+ idleConnectionHandler.closeIdleConnections(idleTimeout);
+ }
+
+ /**
* Close and delete an old, unused connection to make room for a new one.
*/
public synchronized void deleteLeastUsedConnection() {
@@ -799,6 +823,10 @@
hostPool.freeConnections.remove(connection);
hostPool.numConnections--;
numConnections--;
+
+ // remove the connection from the timeout handler
+ idleConnectionHandler.remove(connection);
+
} else if (LOG.isDebugEnabled()) {
LOG.debug("Attempted to reclaim an unused connection but there were none.");
}
@@ -892,7 +920,10 @@
+ connectionConfiguration);
numConnections = 1;
}
-
+
+ // register the connection with the timeout handler
+ idleConnectionHandler.add(conn);
+
notifyWaitingThread(hostPool);
}
}
1.6 +10 -4 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/NoHostHttpConnectionManager.java
Index: NoHostHttpConnectionManager.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/NoHostHttpConnectionManager.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- NoHostHttpConnectionManager.java 22 Feb 2004 18:08:49 -0000 1.5
+++ NoHostHttpConnectionManager.java 25 Apr 2004 21:49:35 -0000 1.6
@@ -45,9 +45,15 @@
private boolean connectionReleased = false;
private HttpConnectionManagerParams params = new HttpConnectionManagerParams();
-
+
public NoHostHttpConnectionManager() {
setConnection(new SimpleHttpConnection());
+ }
+
+ /**
+ * This method currently does nothing.
+ */
+ public void closeIdleConnections(long idleTimeout) {
}
/**
1.36 +5 -4 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java
Index: TestNoHost.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- TestNoHost.java 24 Apr 2004 19:39:24 -0000 1.35
+++ TestNoHost.java 25 Apr 2004 21:49:35 -0000 1.36
@@ -87,6 +87,7 @@
suite.addTest(TestHttpParser.suite());
suite.addTest(TestBadContentLength.suite());
suite.addTest(TestEquals.suite());
+ suite.addTestSuite(TestIdleConnectionTimeout.class);
return suite;
}
1.1 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestIdleConnectionTimeout.java
Index: TestIdleConnectionTimeout.java
===================================================================
/*
* $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestIdleConnectionTimeout.java,v 1.1 2004/04/25 21:49:35 mbecke Exp $
* $Revision: 1.1 $
* $Date: 2004/04/25 21:49:35 $
*
* ====================================================================
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.commons.httpclient;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.util.IdleConnectionHandler;
import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread;
/**
*/
public class TestIdleConnectionTimeout extends TestNoHostBase {
/**
*
*/
public TestIdleConnectionTimeout() {
super();
}
/**
* @param arg0
*/
public TestIdleConnectionTimeout(String arg0) {
super(arg0);
}
/**
* Tests that the IdleConnectionHandler correctly closes connections.
*/
public void testHandler() {
TimeoutHttpConnection connection = new TimeoutHttpConnection();
IdleConnectionHandler handler = new IdleConnectionHandler();
handler.add(connection);
synchronized(this) {
try {
this.wait(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.closeIdleConnections(100);
assertTrue("Connection not closed", connection.isClosed());
connection.setClosed(false);
handler.remove(connection);
synchronized(this) {
try {
this.wait(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.closeIdleConnections(100);
assertFalse("Connection closed", connection.isClosed());
}
/**
* Tests that the IdleConnectionTimeoutThread works correctly.
*/
public void testTimeoutThread() {
TimeoutHttpConnectionManager cm = new TimeoutHttpConnectionManager();
IdleConnectionTimeoutThread timeoutThread = new IdleConnectionTimeoutThread();
timeoutThread.addConnectionManager(cm);
timeoutThread.setTimeoutInterval(100);
timeoutThread.start();
synchronized(this) {
try {
this.wait(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
assertTrue("closeIdleConnections() not called", cm.closed);
timeoutThread.removeConnectionManager(cm);
cm.closed = false;
synchronized(this) {
try {
this.wait(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
assertFalse("closeIdleConnections() called", cm.closed);
timeoutThread.shutdown();
}
private static class TimeoutHttpConnectionManager implements HttpConnectionManager {
public boolean closed = false;
public void closeIdleConnections(long idleTimeout) {
this.closed = true;
}
public HttpConnection getConnection(HostConfiguration hostConfiguration, long timeout)
throws HttpException {
return null;
}
public HttpConnection getConnection(HostConfiguration hostConfiguration) {
return null;
}
public HttpConnection getConnectionWithTimeout(HostConfiguration hostConfiguration,
long timeout) throws ConnectTimeoutException {
return null;
}
public HttpConnectionManagerParams getParams() {
return null;
}
public void releaseConnection(HttpConnection conn) {
}
public void setParams(HttpConnectionManagerParams params) {
}
}
private static class TimeoutHttpConnection extends HttpConnection {
private boolean closed = false;;
public TimeoutHttpConnection() {
super("fake-host", 80);
}
/**
* @return Returns the closed.
*/
public boolean isClosed() {
return closed;
}
/**
* @param closed The closed to set.
*/
public void setClosed(boolean closed) {
this.closed = closed;
}
/* (non-Javadoc)
* @see org.apache.commons.httpclient.HttpConnection#close()
*/
public void close() {
closed = true;
}
}
}
1.1 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/IdleConnectionHandler.java
Index: IdleConnectionHandler.java
===================================================================
/*
* $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/IdleConnectionHandler.java,v 1.1 2004/04/25 21:49:35 mbecke Exp $
* $Revision: 1.1 $
* $Date: 2004/04/25 21:49:35 $
*
* ====================================================================
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.commons.httpclient.util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.httpclient.HttpConnection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A helper class for connection managers to track idle connections.
*
* <p>This class is not synchronized.</p>
*
* @see org.apache.commons.httpclient.HttpConnectionManager#closeIdleConnections(long)
*/
public class IdleConnectionHandler {
private static final Log LOG = LogFactory.getLog(IdleConnectionHandler.class);
/** Holds connections and the time they were added. */
private Map connectionToAdded = new HashMap();
/**
*
*/
public IdleConnectionHandler() {
super();
}
/**
* Registers the given connection with this handler. The connection will be held until
* {@link #remove(HttpConnection)} or {@link #closeIdleConnections(long)} is called.
*
* @param connection the connection to add
*
* @see #remove(HttpConnection)
*/
public void add(HttpConnection connection) {
Long timeAdded = new Long(System.currentTimeMillis());
if (LOG.isDebugEnabled()) {
LOG.debug("Adding connection at: " + timeAdded);
}
connectionToAdded.put(connection, timeAdded);
}
/**
* Removes the given connection from the list of connections to be closed when idle.
* @param connection
*/
public void remove(HttpConnection connection) {
connectionToAdded.remove(connection);
}
/**
* Removes all connections referenced by this handler.
*/
public void removeAll() {
this.connectionToAdded.clear();
}
/**
* Closes connections that have been idle for at least the given amount of time.
*
* @param idleTime the minimum idle time, in milliseconds, for connections to be closed
*/
public void closeIdleConnections(long idleTime) {
// the latest time for which connections will be closed
long idleTimeout = System.currentTimeMillis() - idleTime;
if (LOG.isDebugEnabled()) {
LOG.debug("Checking for connections, idleTimeout: " + idleTimeout);
}
Iterator connectionIter = connectionToAdded.keySet().iterator();
while (connectionIter.hasNext()) {
HttpConnection conn = (HttpConnection) connectionIter.next();
Long connectionTime = (Long) connectionToAdded.get(conn);
if (connectionTime.longValue() <= idleTimeout) {
if (LOG.isDebugEnabled()) {
LOG.debug("Closing connection, connection time: " + connectionTime);
}
connectionIter.remove();
conn.close();
}
}
}
}
1.1 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/IdleConnectionTimeoutThread.java
Index: IdleConnectionTimeoutThread.java
===================================================================
/*
* $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/IdleConnectionTimeoutThread.java,v 1.1 2004/04/25 21:49:35 mbecke Exp $
* $Revision: 1.1 $
* $Date: 2004/04/25 21:49:35 $
*
* ====================================================================
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.commons.httpclient.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.httpclient.HttpConnectionManager;
/**
* A utility class for periodically closing idle connections.
*
* @see org.apache.commons.httpclient.HttpConnectionManager#closeIdleConnections(long)
*/
public class IdleConnectionTimeoutThread extends Thread {
private List connectionManagers = new ArrayList();
private boolean shutdown = false;
private long timeoutInterval = 1000;
private long connectionTimeout = 3000;
public IdleConnectionTimeoutThread() {
setDaemon(true);
}
/**
* Adds a connection manager to be handled by this class.
* {@link HttpConnectionManager#closeIdleConnections(long)} will be called on the connection
* manager every {@link #setTimeoutInterval(long) timeoutInterval} milliseconds.
*
* @param connectionManager The connection manager to add
*/
public synchronized void addConnectionManager(HttpConnectionManager connectionManager) {
if (shutdown) {
throw new IllegalStateException("IdleConnectionTimeoutThread has been shutdown");
}
this.connectionManagers.add(connectionManager);
}
/**
* Removes the connection manager from this class. The idle connections from the connection
* manager will no longer be automatically closed by this class.
*
* @param connectionManager The connection manager to remove
*/
public synchronized void removeConnectionManager(HttpConnectionManager connectionManager) {
if (shutdown) {
throw new IllegalStateException("IdleConnectionTimeoutThread has been shutdown");
}
this.connectionManagers.remove(connectionManager);
}
/**
* Closes idle connections.
*/
public synchronized void run() {
while (!shutdown) {
Iterator iter = connectionManagers.iterator();
while (iter.hasNext()) {
HttpConnectionManager connectionManager = (HttpConnectionManager) iter.next();
connectionManager.closeIdleConnections(connectionTimeout);
}
try {
this.wait(timeoutInterval);
} catch (InterruptedException e) {
}
}
// clear out the connection managers now that we're shutdown
this.connectionManagers.clear();
}
/**
* Stops the thread used to close idle connections. This class cannot be used once shutdown.
*/
public synchronized void shutdown() {
this.shutdown = true;
}
/**
* Sets the timeout value to use when testing for idle connections.
*
* @param connectionTimeout The connection timeout in milliseconds
*
* @see HttpConnectionManager#closeIdleConnections(long)
*/
public void setConnectionTimeout(long connectionTimeout) {
if (shutdown) {
throw new IllegalStateException("IdleConnectionTimeoutThread has been shutdown");
}
this.connectionTimeout = connectionTimeout;
}
/**
* Sets the interval used by this class between closing idle connections. Idle
* connections will be closed every <code>timeoutInterval</code> milliseconds.
*
* @param timeoutInterval The timeout interval in milliseconds
*/
public void setTimeoutInterval(long timeoutInterval) {
if (shutdown) {
throw new IllegalStateException("IdleConnectionTimeoutThread has been shutdown");
}
this.timeoutInterval = timeoutInterval;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org