connection can release itself, stream can be aborted

git-svn-id: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpclient/trunk@508919 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Roland Weber 2007-02-18 17:04:31 +00:00
parent fe62d7292a
commit 6175558fb5
8 changed files with 209 additions and 35 deletions

View File

@ -52,9 +52,6 @@ public class BasicEofSensorWatcher implements EofSensorWatcher {
/** The connection to auto-release. */
protected ManagedClientConnection managedConn;
/** The connection manager to release to. */
protected ClientConnectionManager connManager;
/** Whether to keep the connection alive. */
protected boolean attemptReuse;
@ -64,22 +61,15 @@ public class BasicEofSensorWatcher implements EofSensorWatcher {
* Creates a new watcher for auto-releasing a connection.
*
* @param conn the connection to auto-release
* @param mgr the connection manager to release to
* @param reuse whether the connection should be re-used
*/
public BasicEofSensorWatcher(ManagedClientConnection conn,
ClientConnectionManager mgr,
boolean reuse) {
if (conn == null)
throw new IllegalArgumentException
("Connection may not be null.");
if (mgr == null)
throw new IllegalArgumentException
("Connection manager may not be null.");
managedConn = conn;
//@@@ put a release method in the connection interface?
connManager = mgr;
attemptReuse = reuse;
}
@ -96,7 +86,7 @@ public class BasicEofSensorWatcher implements EofSensorWatcher {
managedConn.markReusable();
}
} finally {
connManager.releaseConnection(managedConn);
managedConn.releaseConnection();
}
return false;
}
@ -114,9 +104,18 @@ public class BasicEofSensorWatcher implements EofSensorWatcher {
managedConn.markReusable();
}
} finally {
connManager.releaseConnection(managedConn);
managedConn.releaseConnection();
}
return false;
}
// non-javadoc, see interface EofSensorWatcher
public boolean streamAbort(InputStream wrapped)
throws IOException {
managedConn.abortConnection();
return false;
}
} // class BasicEofSensorWatcher

View File

@ -0,0 +1,82 @@
/*
* $HeadURL$
* $Revision$
* $Date$
*
* ====================================================================
*
* 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.
* ====================================================================
*
* 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.http.conn;
import java.io.IOException;
/**
* Interface for releasing a connection.
* This can be implemented by various "trigger" objects which are
* associated with a connection, for example a stream or an entity
* or the {@link ManagedClientConnection connection} itself.
* <br/>
* The methods in this interface can safely be called multiple times.
* The first invocation releases the connection, subsequent calls
* are ignored.
*
* @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
*
*
* <!-- empty lines to avoid svn diff problems -->
* @version $Revision$
*
* @since 4.0
*/
public interface ConnectionReleaseTrigger {
/**
* Releases the connection with the option of keep-alive.
* This is a "graceful" release and may cause IO operations
* for consuming the remainder of a response entity.
* Use {@link #abortConnection abortConnection} for a hard release.
*
* @throws IOException in case of an IO problem.
* The connection will be released anyway.
*/
void releaseConnection()
throws IOException
;
/**
* Releases the connection without the option of keep-alive.
* This is a "hard" release that implies a shutdown of the connection.
* Use {@link #releaseConnection releaseConnection} for a graceful release.
*
* @throws IOException in case of an IO problem.
* The connection will be released anyway.
*/
void abortConnection()
throws IOException
;
} // interface ConnectionReleaseTrigger

View File

@ -60,9 +60,10 @@ import java.io.IOException;
*
* @since 4.0
*/
public class EofSensorInputStream extends InputStream {
// don't use FilterInputStream as the base class, we'd have to
// override markSupported(), mark(), and reset() to disable them
// don't use FilterInputStream as the base class, we'd have to
// override markSupported(), mark(), and reset() to disable them
public class EofSensorInputStream extends InputStream
implements ConnectionReleaseTrigger {
/**
* The wrapped input stream, while accessible.
@ -246,5 +247,55 @@ public class EofSensorInputStream extends InputStream {
}
}
/**
* Detects stream abort and notifies the watcher.
* There's not much to detect since this is called by
* {@link #abortConnection abortConnection}.
* The watcher will only be notified if this stream is aborted
* for the first time and before EOF has been detected or the
* stream has been {@link #close closed} gracefully.
* This stream will be detached from the underlying stream to prevent
* multiple notifications to the watcher.
*
* @throws IOException
* in case of an IO problem on closing the underlying stream
*/
protected void checkAbort() throws IOException {
if (wrappedStream != null) {
try {
boolean scws = true; // should close wrapped stream?
if (eofWatcher != null)
scws = eofWatcher.streamAbort(wrappedStream);
if (scws)
wrappedStream.close();
} finally {
wrappedStream = null;
}
}
}
/**
* Same as {@link #close close()}.
*/
public void releaseConnection() throws IOException {
this.close();
}
/**
* Aborts this stream.
* This is a special version of {@link #close close()} which prevents
* re-use of the underlying connection, if any. Calling this method
* indicates that there should be no attempt to read until the end of
* the stream.
*/
public void abortConnection() throws IOException {
// tolerate multiple calls
selfClosed = true;
checkAbort();
}
} // class EOFSensorInputStream

View File

@ -85,4 +85,25 @@ public interface EofSensorWatcher {
throws IOException
;
/**
* Indicates that the {@link EofSensorInputStream stream} is aborted.
* This method will be called only if EOF was <i>not</i> detected
* before aborting. Otherwise, {@link #eofDetected eofDetected} is called.
*
* @param wrapped the underlying stream which has not reached EOF
*
* @return <code>true</code> if <code>wrapped</code> should be closed,
* <code>false</code> if it should be left alone
*
* @throws IOException
* in case of an IO problem, for example if the watcher itself
* closes the underlying stream. The caller will leave the
* wrapped stream alone, as if <code>false</code> was returned.
*/
boolean streamAbort(InputStream wrapped)
throws IOException
;
} // interface EofSensorWatcher

View File

@ -51,8 +51,8 @@ import org.apache.http.protocol.HttpContext;
*
* @since 4.0
*/
public interface ManagedClientConnection
extends HttpClientConnection, HttpInetConnection {
public interface ManagedClientConnection extends
HttpClientConnection, HttpInetConnection, ConnectionReleaseTrigger {
/**
@ -132,18 +132,6 @@ public interface ManagedClientConnection
;
/* *
* Releases this connection back to it's connection manager.
*
* @throws IllegalStateException
* if this connection is already released
* /
boolean release()
throws IllegalStateException
;
*/
/**
* Marks this connection as being in a reusable communication state.
* The checkpoints for reuseable communication states (in the absence

View File

@ -426,10 +426,10 @@ public class DefaultClientRequestDirector
BasicHttpEntity bhe = (BasicHttpEntity) entity;
//@@@ evaluate connection re-use strategy
boolean reuse = false;
BasicEofSensorWatcher esw = new BasicEofSensorWatcher
(mcc, connManager, reuse);
EofSensorInputStream esis = new EofSensorInputStream
(bhe.getContent(), esw);
BasicEofSensorWatcher esw =
new BasicEofSensorWatcher(mcc, reuse);
EofSensorInputStream esis =
new EofSensorInputStream(bhe.getContent(), esw);
bhe.setContent(esis);
}
} else {

View File

@ -41,6 +41,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.params.HttpParams;
import org.apache.http.conn.OperatedClientConnection;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.ClientConnectionManager;
@ -57,6 +58,11 @@ import org.apache.http.conn.ManagedClientConnection;
* as indicated by {@link #markReusable markReusable} and queried by
* {@link #isMarkedReusable isMarkedReusable}.
* All send and receive operations will automatically clear the mark.
* <br/>
* Connection release calls are delegated to the connection manager,
* if there is one. {@link #abortConnection abortConnection} will
* clear the reusability mark first. The connection manager is
* expected to tolerate multiple calls to the release method.
*
* @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
*
@ -69,6 +75,9 @@ import org.apache.http.conn.ManagedClientConnection;
public abstract class AbstractClientConnectionAdapter
implements ManagedClientConnection {
/** The connection manager, if any. */
protected final ClientConnectionManager connManager;
/** The wrapped connection. */
protected OperatedClientConnection wrappedConnection;
@ -81,10 +90,13 @@ public abstract class AbstractClientConnectionAdapter
* The adapter is initially <i>not</i>
* {@link #isMarkedReusable marked} as reusable.
*
* @param mgr the connection manager, or <code>null</code>
* @param conn the connection to wrap, or <code>null</code>
*/
protected AbstractClientConnectionAdapter(OperatedClientConnection conn) {
protected AbstractClientConnectionAdapter(ClientConnectionManager mgr,
OperatedClientConnection conn) {
connManager = mgr;
wrappedConnection = conn;
markedReusable = false;
@ -225,4 +237,25 @@ public abstract class AbstractClientConnectionAdapter
return markedReusable;
}
// non-javadoc, see interface ConnectionReleaseTrigger
public void releaseConnection() {
if (connManager == null)
throw new IllegalStateException
("No connection manager to release to.");
connManager.releaseConnection(this);
}
// non-javadoc, see interface ConnectionReleaseTrigger
public void abortConnection() {
unmarkReusable();
if (connManager == null)
throw new IllegalStateException
("No connection manager to release to.");
connManager.releaseConnection(this);
}
} // class AbstractClientConnectionAdapter

View File

@ -1316,7 +1316,7 @@ public class ThreadSafeClientConnManager
* @param entry the pool entry for the connection being wrapped
*/
protected HttpConnectionAdapter(TrackingPoolEntry entry) {
super(entry.connection);
super(ThreadSafeClientConnManager.this, entry.connection);
poolEntry = entry;
super.markedReusable = true;
}