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:
parent
fe62d7292a
commit
6175558fb5
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue