You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ro...@apache.org on 2007/02/18 19:36:22 UTC

svn commit: r508937 - in /jakarta/httpcomponents/httpclient/trunk/src: examples/org/apache/http/examples/client/ java/org/apache/http/conn/ java/org/apache/http/impl/client/ java/org/apache/http/impl/conn/

Author: rolandw
Date: Sun Feb 18 10:36:21 2007
New Revision: 508937

URL: http://svn.apache.org/viewvc?view=rev&rev=508937
Log:
entity with connection release

Added:
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java   (with props)
Modified:
    jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java
    jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteProxy.java
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ClientConnectionManager.java
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ConnectionReleaseTrigger.java
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java

Modified: jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java?view=diff&rev=508937&r1=508936&r2=508937
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java Sun Feb 18 10:36:21 2007
@@ -32,8 +32,9 @@
 package org.apache.http.examples.client;
 
 
-import org.apache.http.HttpHost;
 import org.apache.http.Header;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpEntity;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpVersion;
@@ -47,7 +48,7 @@
 import org.apache.http.protocol.RequestExpectContinue;
 import org.apache.http.protocol.RequestTargetHost;
 import org.apache.http.protocol.RequestUserAgent;
-//import org.apache.http.util.EntityUtils;
+import org.apache.http.util.EntityUtils;
 
 import org.apache.http.conn.Scheme;
 import org.apache.http.conn.SchemeRegistry;
@@ -94,7 +95,7 @@
     public final static void main(String[] args)
         throws Exception {
 
-        final HttpHost target = new HttpHost("jakarta.apache.org", 80, "http");
+        final HttpHost target = new HttpHost("issues.apache.org", 80, "http");
 
         setup(); // some general setup
 
@@ -103,8 +104,10 @@
         HttpRequest req = createRequest(target);
 
         System.out.println("executing request to " + target);
+        HttpEntity entity = null;
         try {
             HttpResponse rsp = client.execute(target, req);
+            entity = rsp.getEntity();
 
             System.out.println("----------------------------------------");
             System.out.println(rsp.getStatusLine());
@@ -114,24 +117,18 @@
             }
             System.out.println("----------------------------------------");
 
-            if (rsp.getEntity() != null) {
-                // the entity is probably tied to the connection
-                rsp.getEntity().getContent().close();
-                // If you want to see the content, use the line below
-                // _instead_ of the close() call above. The utility class
-                // will read to the end of the stream and close it,
-                // thereby releasing the underlying connection.
-                //System.out.println(EntityUtils.toString(rsp.getEntity()));
-                //@@@ in case of an exception from EntityUtils.toString,
-                //@@@ there currently is no way of releasing the connection.
-                //@@@ The stream can be obtained from the entity only once.
+            if (entity != null) {
+                System.out.println(EntityUtils.toString(rsp.getEntity()));
             }
-            // if there is no entity, the connection is already released
 
         } finally {
-            //@@@ any kind of cleanup that should be performed?
-            //@@@ if content is read instead of being ignored, this is
-            //@@@ the place for connection release in case of an error
+            // If we could be sure that the stream of the entity has been
+            // closed, we wouldn't need this code to release the connection.
+            // However, EntityUtils.toString(...) can throw an exception.
+
+            // if there is no entity, the connection is already released
+            if (entity != null)
+                entity.consumeContent(); // release connection gracefully
         }
     } // main
 

Modified: jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteProxy.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteProxy.java?view=diff&rev=508937&r1=508936&r2=508937
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteProxy.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/examples/org/apache/http/examples/client/ClientExecuteProxy.java Sun Feb 18 10:36:21 2007
@@ -32,8 +32,9 @@
 package org.apache.http.examples.client;
 
 
-import org.apache.http.HttpHost;
 import org.apache.http.Header;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpEntity;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpVersion;
@@ -47,7 +48,7 @@
 import org.apache.http.protocol.RequestExpectContinue;
 import org.apache.http.protocol.RequestTargetHost;
 import org.apache.http.protocol.RequestUserAgent;
-//import org.apache.http.util.EntityUtils;
+import org.apache.http.util.EntityUtils;
 
 import org.apache.http.conn.Scheme;
 import org.apache.http.conn.SchemeRegistry;
@@ -115,8 +116,10 @@
         final RoutedRequest roureq = new RoutedRequest.Impl(req, route);
         
         System.out.println("executing request to " + target + " via " + proxy);
+        HttpEntity entity = null;
         try {
             HttpResponse rsp = client.execute(roureq, null);
+            entity = rsp.getEntity();
 
             System.out.println("----------------------------------------");
             System.out.println(rsp.getStatusLine());
@@ -127,23 +130,17 @@
             System.out.println("----------------------------------------");
 
             if (rsp.getEntity() != null) {
-                // the entity is probably tied to the connection
-                rsp.getEntity().getContent().close();
-                // If you want to see the content, use the line below
-                // _instead_ of the close() call above. The utility class
-                // will read to the end of the stream and close it,
-                // thereby releasing the underlying connection.
-                //System.out.println(EntityUtils.toString(rsp.getEntity()));
-                //@@@ in case of an exception from EntityUtils.toString,
-                //@@@ there currently is no way of releasing the connection.
-                //@@@ The stream can be obtained from the entity only once.
+                System.out.println(EntityUtils.toString(rsp.getEntity()));
             }
-            // if there is no entity, the connection is already released
 
         } finally {
-            //@@@ any kind of cleanup that should be performed?
-            //@@@ if content is read instead of being ignored, this is
-            //@@@ the place for connection release in case of an error
+            // If we could be sure that the stream of the entity has been
+            // closed, we wouldn't need this code to release the connection.
+            // However, EntityUtils.toString(...) can throw an exception.
+
+            // if there is no entity, the connection is already released
+            if (entity != null)
+                entity.consumeContent(); // release connection gracefully
         }
     } // main
 

Added: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java?view=auto&rev=508937
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java (added)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java Sun Feb 18 10:36:21 2007
@@ -0,0 +1,205 @@
+/*
+ * $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.InputStream;
+import java.io.IOException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.HttpEntityWrapper;
+
+
+/**
+ * An entity that releases a {@link ManagedClientConnection connection}.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ *
+ *
+ * <!-- empty lines to avoid svn diff problems -->
+ * @version $Revision$
+ *
+ * @since 4.0
+ */
+public class BasicManagedEntity extends HttpEntityWrapper
+    implements HttpEntity, ConnectionReleaseTrigger, EofSensorWatcher {
+
+    /** The connection to release. */
+    protected ManagedClientConnection managedConn;
+
+    /** Whether to keep the connection alive. */
+    protected boolean attemptReuse;
+
+
+    /**
+     * Creates a new managed entity that can release a connection.
+     *
+     * @param entity    the entity of which to wrap the content.
+     *                  Note that the argument entity can no longer be used
+     *                  afterwards, since the content will be taken by this
+     *                  managed entity.
+     * @param conn      the connection to release
+     * @param reuse     whether the connection should be re-used
+     */
+    public BasicManagedEntity(HttpEntity entity,
+                              ManagedClientConnection conn,
+                              boolean reuse) {
+        super(entity);
+
+        if (conn == null)
+            throw new IllegalArgumentException
+                ("Connection may not be null.");
+
+        managedConn = conn;
+        attemptReuse = reuse;
+    }
+
+
+    // non-javadoc, see interface HttpEntity
+    public boolean isRepeatable() {
+        return false;
+    }
+
+
+    // non-javadoc, see interface HttpEntity
+    public InputStream getContent() throws IOException {
+
+        return new EofSensorInputStream(wrappedEntity.getContent(), this);
+    }
+
+
+    // non-javadoc, see interface HttpEntity
+    public void consumeContent() throws IOException {
+
+        if (managedConn == null)
+            return;
+
+        try {
+            if (attemptReuse) {
+                // this will not trigger a callback from EofSensorInputStream
+                wrappedEntity.consumeContent();
+                managedConn.markReusable();
+            }
+        } finally {
+            releaseManagedConnection();
+        }
+    }
+
+
+    // non-javadoc, see interface ConnectionReleaseTrigger
+    public void releaseConnection()
+        throws IOException {
+
+        this.consumeContent();
+    }
+
+
+    // non-javadoc, see interface ConnectionReleaseTrigger
+    public void abortConnection()
+        throws IOException {
+
+        if (managedConn != null) {
+            try {
+                managedConn.abortConnection();
+            } finally {
+                managedConn = null;
+            }
+        }
+    }
+
+
+    // non-javadoc, see interface EofSensorWatcher
+    public boolean eofDetected(InputStream wrapped)
+        throws IOException {
+
+        try {
+            if (attemptReuse && (managedConn != null)) {
+                // there may be some cleanup required, such as
+                // reading trailers after the response body:
+                wrapped.close();
+                managedConn.markReusable();
+            }
+        } finally {
+            releaseManagedConnection();
+        }
+        return false;
+    }
+
+
+    // non-javadoc, see interface EofSensorWatcher
+    public boolean streamClosed(InputStream wrapped)
+        throws IOException {
+
+        try {
+            if (attemptReuse && (managedConn != null)) {
+                // this assumes that closing the stream will
+                // consume the remainder of the response body:
+                wrapped.close();
+                managedConn.markReusable();
+            }
+        } finally {
+            releaseManagedConnection();
+        }
+        return false;
+    }
+
+
+    // non-javadoc, see interface EofSensorWatcher
+    public boolean streamAbort(InputStream wrapped)
+        throws IOException {
+
+        if (managedConn != null) {
+            managedConn.abortConnection();
+        }
+        return false;
+    }
+
+
+    /**
+     * Releases the connection gracefully.
+     * The connection attribute will be nullified.
+     * Subsequent invocations are no-ops.
+     *
+     * @throws IOException      in case of an IO problem.
+     *         The connection attribute will be nullified anyway.
+     */
+    protected void releaseManagedConnection()
+        throws IOException {
+
+        if (managedConn != null) {
+            try {
+                managedConn.releaseConnection();
+            } finally {
+                managedConn = null;
+            }
+        }
+    }
+
+} // class BasicManagedEntity

Propchange: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/BasicManagedEntity.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ClientConnectionManager.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ClientConnectionManager.java?view=diff&rev=508937&r1=508936&r2=508937
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ClientConnectionManager.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ClientConnectionManager.java Sun Feb 18 10:36:21 2007
@@ -86,6 +86,8 @@
 
     /**
      * Releases a connection for use by others.
+     * If the argument connection has been released before,
+     * the call will be ignored.
      *
      * @param conn      the connection to release
      */

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ConnectionReleaseTrigger.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ConnectionReleaseTrigger.java?view=diff&rev=508937&r1=508936&r2=508937
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ConnectionReleaseTrigger.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ConnectionReleaseTrigger.java Sun Feb 18 10:36:21 2007
@@ -36,7 +36,9 @@
 /**
  * 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
+ * associated with a connection, for example
+ * a {@link EofSensorInputStream stream}
+ * or an entity
  * or the {@link ManagedClientConnection connection} itself.
  * <br/>
  * The methods in this interface can safely be called multiple times.

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java?view=diff&rev=508937&r1=508936&r2=508937
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/client/DefaultClientRequestDirector.java Sun Feb 18 10:36:21 2007
@@ -47,9 +47,7 @@
 import org.apache.http.conn.RouteDirector;
 import org.apache.http.conn.ClientConnectionManager;
 import org.apache.http.conn.ManagedClientConnection;
-import org.apache.http.conn.EofSensorInputStream;
-import org.apache.http.conn.EofSensorWatcher;
-import org.apache.http.conn.BasicEofSensorWatcher;
+import org.apache.http.conn.BasicManagedEntity;
 import org.apache.http.client.RoutedRequest;
 import org.apache.http.client.ClientRequestDirector;
 
@@ -413,24 +411,11 @@
                 mcc.markReusable();
                 connManager.releaseConnection(mcc);
             } else {
+                // install an auto-release entity
                 HttpEntity entity = response.getEntity();
-                if (!(entity instanceof BasicHttpEntity)) {
-                    //@@@ fall back to an entity wrapper in this case?
-                    managedConn = null;
-                    connManager.releaseConnection(mcc);
-                    throw new IllegalStateException
-                        ("Unsupported entity type: " +
-                         entity.getClass().getName());
-                }
-                // install an auto-release handler
-                BasicHttpEntity bhe = (BasicHttpEntity) entity;
                 //@@@ evaluate connection re-use strategy
                 boolean reuse = false;
-                BasicEofSensorWatcher esw =
-                    new BasicEofSensorWatcher(mcc, reuse);
-                EofSensorInputStream esis =
-                    new EofSensorInputStream(bhe.getContent(), esw);
-                bhe.setContent(esis);
+                response.setEntity(new BasicManagedEntity(entity, mcc, reuse));
             }
         } else {
             // we got here as the result of an exception
@@ -438,16 +423,12 @@
             managedConn = null;
             //@@@ is the connection in a re-usable state? consume response?
             //@@@ for now, just shut it down
-            // Do not delegate this to the connection manager, can't
-            // tell whether it would shut down or close gracefully.
             try {
-                if (mcc.isOpen())
-                    mcc.shutdown();
+                mcc.abortConnection();
             } catch (IOException ignore) {
                 // can't allow exception while handling exception
                 //@@@ log as debug or warning?
             }
-            connManager.releaseConnection(mcc);
         }
     } // cleanupConnection
 

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java?view=diff&rev=508937&r1=508936&r2=508937
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java Sun Feb 18 10:36:21 2007
@@ -369,7 +369,7 @@
                 }
                 // In MTHCM, method releasePoolEntry below would call
                 // SimpleHttpConnectionManager.finishLastResponse(conn);
-                //@@@ consume response here or outside? (rolandw: outside)
+                // Consuming the response is handled outside in 4.0.
 
                 // make sure this connection will not be re-used
                 //@@@ Can we set some kind of flag before shutting down?