You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2014/05/21 20:53:54 UTC

svn commit: r1596649 - in /httpcomponents/httpclient/branches/4.3.x: ./ httpclient/src/main/java/org/apache/http/impl/conn/ httpclient/src/main/java/org/apache/http/impl/execchain/ httpclient/src/test/java/org/apache/http/impl/execchain/

Author: olegk
Date: Wed May 21 18:53:53 2014
New Revision: 1596649

URL: http://svn.apache.org/r1596649
Log:
Replaced dynamic proxies with custom proxy classes to reduce thread contention

Added:
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java   (with props)
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java   (contents, props changed)
      - copied, changed from r1596520, httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/Proxies.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java   (contents, props changed)
      - copied, changed from r1596520, httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityWrapper.java
Removed:
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/Proxies.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityExecHandler.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityWrapper.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseProxyHandler.java
Modified:
    httpcomponents/httpclient/branches/4.3.x/RELEASE_NOTES.txt
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java
    httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java

Modified: httpcomponents/httpclient/branches/4.3.x/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/RELEASE_NOTES.txt?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpclient/branches/4.3.x/RELEASE_NOTES.txt Wed May 21 18:53:53 2014
@@ -4,6 +4,9 @@ Changes for 4.3.TBA
 Changelog:
 -------------------
 
+* Replaced dynamic proxies with custom proxy classes to reduce thread contention.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
 * [HTTPCLIENT-1484] GzipCompressingEntity should not close the underlying output stream
   if the entity has not been fully written out due to an exception.
   Contributed by Oleg Kalnichevski <olegk at apache.org>

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java Wed May 21 18:53:53 2014
@@ -27,13 +27,17 @@
 package org.apache.http.impl.conn;
 
 import java.io.IOException;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import java.net.InetAddress;
+import java.net.Socket;
+
+import javax.net.ssl.SSLSession;
 
 import org.apache.http.HttpClientConnection;
-import org.apache.http.HttpConnection;
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
 import org.apache.http.annotation.NotThreadSafe;
 import org.apache.http.conn.ManagedHttpClientConnection;
 import org.apache.http.protocol.HttpContext;
@@ -42,23 +46,7 @@ import org.apache.http.protocol.HttpCont
  * @since 4.3
  */
 @NotThreadSafe
-class CPoolProxy implements InvocationHandler {
-
-    private static final Method CLOSE_METHOD;
-    private static final Method SHUTDOWN_METHOD;
-    private static final Method IS_OPEN_METHOD;
-    private static final Method IS_STALE_METHOD;
-
-    static {
-        try {
-            CLOSE_METHOD = HttpConnection.class.getMethod("close");
-            SHUTDOWN_METHOD = HttpConnection.class.getMethod("shutdown");
-            IS_OPEN_METHOD = HttpConnection.class.getMethod("isOpen");
-            IS_STALE_METHOD = HttpConnection.class.getMethod("isStale");
-        } catch (final NoSuchMethodException ex) {
-            throw new Error(ex);
-        }
-    }
+class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
 
     private volatile CPoolEntry poolEntry;
 
@@ -77,7 +65,7 @@ class CPoolProxy implements InvocationHa
         return local;
     }
 
-    HttpClientConnection getConnection() {
+    ManagedHttpClientConnection getConnection() {
         final CPoolEntry local = this.poolEntry;
         if (local == null) {
             return null;
@@ -85,6 +73,14 @@ class CPoolProxy implements InvocationHa
         return local.getConnection();
     }
 
+    ManagedHttpClientConnection getValidConnection() {
+        final ManagedHttpClientConnection conn = getConnection();
+        if (conn == null) {
+            throw new ConnectionShutdownException();
+        }
+        return conn;
+    }
+
     public void close() throws IOException {
         final CPoolEntry local = this.poolEntry;
         if (local != null) {
@@ -117,63 +113,120 @@ class CPoolProxy implements InvocationHa
         }
     }
 
-    public Object invoke(
-            final Object proxy, final Method method, final Object[] args) throws Throwable {
-        if (method.equals(CLOSE_METHOD)) {
-            close();
-            return null;
-        } else if (method.equals(SHUTDOWN_METHOD)) {
-            shutdown();
+    public void setSocketTimeout(final int timeout) {
+        getValidConnection().setSocketTimeout(timeout);
+    }
+
+    public int getSocketTimeout() {
+        return getValidConnection().getSocketTimeout();
+    }
+
+    public String getId() {
+        return getValidConnection().getId();
+    }
+
+    public void bind(final Socket socket) throws IOException {
+        getValidConnection().bind(socket);
+    }
+
+    public Socket getSocket() {
+        return getValidConnection().getSocket();
+    }
+
+    public SSLSession getSSLSession() {
+        return getValidConnection().getSSLSession();
+    }
+
+    public boolean isResponseAvailable(final int timeout) throws IOException {
+        return getValidConnection().isResponseAvailable(timeout);
+    }
+
+    public void sendRequestHeader(final HttpRequest request) throws HttpException, IOException {
+        getValidConnection().sendRequestHeader(request);
+    }
+
+    public void sendRequestEntity(final HttpEntityEnclosingRequest request) throws HttpException, IOException {
+        getValidConnection().sendRequestEntity(request);
+    }
+
+    public HttpResponse receiveResponseHeader() throws HttpException, IOException {
+        return getValidConnection().receiveResponseHeader();
+    }
+
+    public void receiveResponseEntity(final HttpResponse response) throws HttpException, IOException {
+        getValidConnection().receiveResponseEntity(response);
+    }
+
+    public void flush() throws IOException {
+        getValidConnection().flush();
+    }
+
+    public HttpConnectionMetrics getMetrics() {
+        return getValidConnection().getMetrics();
+    }
+
+    public InetAddress getLocalAddress() {
+        return getValidConnection().getLocalAddress();
+    }
+
+    public int getLocalPort() {
+        return getValidConnection().getLocalPort();
+    }
+
+    public InetAddress getRemoteAddress() {
+        return getValidConnection().getRemoteAddress();
+    }
+
+    public int getRemotePort() {
+        return getValidConnection().getRemotePort();
+    }
+
+    public Object getAttribute(final String id) {
+        final ManagedHttpClientConnection conn = getValidConnection();
+        if (conn instanceof HttpContext) {
+            return ((HttpContext) conn).getAttribute(id);
+        } else {
             return null;
-        } else if (method.equals(IS_OPEN_METHOD)) {
-            return Boolean.valueOf(isOpen());
-        } else if (method.equals(IS_STALE_METHOD)) {
-            return Boolean.valueOf(isStale());
+        }
+    }
+
+    public void setAttribute(final String id, final Object obj) {
+        final ManagedHttpClientConnection conn = getValidConnection();
+        if (conn instanceof HttpContext) {
+            ((HttpContext) conn).setAttribute(id, obj);
+        }
+    }
+
+    public Object removeAttribute(final String id) {
+        final ManagedHttpClientConnection conn = getValidConnection();
+        if (conn instanceof HttpContext) {
+            return ((HttpContext) conn).removeAttribute(id);
         } else {
-            final HttpClientConnection conn = getConnection();
-            if (conn == null) {
-                throw new ConnectionShutdownException();
-            }
-            try {
-                return method.invoke(conn, args);
-            } catch (final InvocationTargetException ex) {
-                final Throwable cause = ex.getCause();
-                if (cause != null) {
-                    throw cause;
-                } else {
-                    throw ex;
-                }
-            }
+            return null;
         }
     }
 
-    public static HttpClientConnection newProxy(
-            final CPoolEntry poolEntry) {
-        return (HttpClientConnection) Proxy.newProxyInstance(
-                CPoolProxy.class.getClassLoader(),
-                new Class<?>[] { ManagedHttpClientConnection.class, HttpContext.class },
-                new CPoolProxy(poolEntry));
-    }
-
-    private static CPoolProxy getHandler(
-            final HttpClientConnection proxy) {
-        final InvocationHandler handler = Proxy.getInvocationHandler(proxy);
-        if (!CPoolProxy.class.isInstance(handler)) {
-            throw new IllegalStateException("Unexpected proxy handler class: " + handler);
+    public static HttpClientConnection newProxy(final CPoolEntry poolEntry) {
+        return new CPoolProxy(poolEntry);
+    }
+
+    private static CPoolProxy getProxy(final HttpClientConnection conn) {
+        if (!CPoolProxy.class.isInstance(conn)) {
+            throw new IllegalStateException("Unexpected connection proxy class: " + conn.getClass());
         }
-        return CPoolProxy.class.cast(handler);
+        return CPoolProxy.class.cast(conn);
     }
 
     public static CPoolEntry getPoolEntry(final HttpClientConnection proxy) {
-        final CPoolEntry entry = getHandler(proxy).getPoolEntry();
+        final CPoolEntry entry = getProxy(proxy).getPoolEntry();
         if (entry == null) {
             throw new ConnectionShutdownException();
         }
         return entry;
     }
 
-    public static CPoolEntry detach(final HttpClientConnection proxy) {
-        return getHandler(proxy).detach();
+    public static CPoolEntry detach(final HttpClientConnection conn) {
+        return getProxy(conn).detach();
     }
 
 }

Added: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java?rev=1596649&view=auto
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java (added)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java Wed May 21 18:53:53 2014
@@ -0,0 +1,185 @@
+/*
+ * ====================================================================
+ * 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.impl.execchain;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.params.HttpParams;
+
+/**
+ * A proxy class for {@link org.apache.http.HttpResponse} that can be used to release client connection
+ * associated with the original response.
+ *
+ * @since 4.3
+ */
+@NotThreadSafe
+class HttpResponseProxy implements CloseableHttpResponse {
+
+    private final HttpResponse original;
+    private final ConnectionHolder connHolder;
+
+    public HttpResponseProxy(final HttpResponse original, final ConnectionHolder connHolder) {
+        this.original = original;
+        this.connHolder = connHolder;
+        ResponseEntityProxy.enchance(original, connHolder);
+    }
+
+    public void close() throws IOException {
+        if (this.connHolder != null) {
+            this.connHolder.abortConnection();
+        }
+    }
+
+    public StatusLine getStatusLine() {
+        return original.getStatusLine();
+    }
+
+    public void setStatusLine(final StatusLine statusline) {
+        original.setStatusLine(statusline);
+    }
+
+    public void setStatusLine(final ProtocolVersion ver, final int code) {
+        original.setStatusLine(ver, code);
+    }
+
+    public void setStatusLine(final ProtocolVersion ver, final int code, final String reason) {
+        original.setStatusLine(ver, code, reason);
+    }
+
+    public void setStatusCode(final int code) throws IllegalStateException {
+        original.setStatusCode(code);
+    }
+
+    public void setReasonPhrase(final String reason) throws IllegalStateException {
+        original.setReasonPhrase(reason);
+    }
+
+    public HttpEntity getEntity() {
+        return original.getEntity();
+    }
+
+    public void setEntity(final HttpEntity entity) {
+        original.setEntity(entity);
+    }
+
+    public Locale getLocale() {
+        return original.getLocale();
+    }
+
+    public void setLocale(final Locale loc) {
+        original.setLocale(loc);
+    }
+
+    public ProtocolVersion getProtocolVersion() {
+        return original.getProtocolVersion();
+    }
+
+    public boolean containsHeader(final String name) {
+        return original.containsHeader(name);
+    }
+
+    public Header[] getHeaders(final String name) {
+        return original.getHeaders(name);
+    }
+
+    public Header getFirstHeader(final String name) {
+        return original.getFirstHeader(name);
+    }
+
+    public Header getLastHeader(final String name) {
+        return original.getLastHeader(name);
+    }
+
+    public Header[] getAllHeaders() {
+        return original.getAllHeaders();
+    }
+
+    public void addHeader(final Header header) {
+        original.addHeader(header);
+    }
+
+    public void addHeader(final String name, final String value) {
+        original.addHeader(name, value);
+    }
+
+    public void setHeader(final Header header) {
+        original.setHeader(header);
+    }
+
+    public void setHeader(final String name, final String value) {
+        original.setHeader(name, value);
+    }
+
+    public void setHeaders(final Header[] headers) {
+        original.setHeaders(headers);
+    }
+
+    public void removeHeader(final Header header) {
+        original.removeHeader(header);
+    }
+
+    public void removeHeaders(final String name) {
+        original.removeHeaders(name);
+    }
+
+    public HeaderIterator headerIterator() {
+        return original.headerIterator();
+    }
+
+    public HeaderIterator headerIterator(final String name) {
+        return original.headerIterator(name);
+    }
+
+    @Deprecated
+    public HttpParams getParams() {
+        return original.getParams();
+    }
+
+    @Deprecated
+    public void setParams(final HttpParams params) {
+        original.setParams(params);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("HttpResponseProxy{");
+        sb.append(original);
+        sb.append('}');
+        return sb.toString();
+    }
+
+}

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java Wed May 21 18:53:53 2014
@@ -150,7 +150,7 @@ public class MainClientExec implements C
         }
 
         if (request instanceof HttpEntityEnclosingRequest) {
-            Proxies.enhanceEntity((HttpEntityEnclosingRequest) request);
+            RequestEntityProxy.enhance((HttpEntityEnclosingRequest) request);
         }
 
         Object userToken = context.getUserToken();
@@ -204,7 +204,7 @@ public class MainClientExec implements C
             HttpResponse response;
             for (int execCount = 1;; execCount++) {
 
-                if (execCount > 1 && !Proxies.isRepeatable(request)) {
+                if (execCount > 1 && !RequestEntityProxy.isRepeatable(request)) {
                     throw new NonRepeatableRequestException("Cannot retry request " +
                             "with a non-repeatable request entity.");
                 }
@@ -319,9 +319,9 @@ public class MainClientExec implements C
             if (entity == null || !entity.isStreaming()) {
                 // connection not needed and (assumed to be) in re-usable state
                 connHolder.releaseConnection();
-                return Proxies.enhanceResponse(response, null);
+                return new HttpResponseProxy(response, null);
             } else {
-                return Proxies.enhanceResponse(response, connHolder);
+                return new HttpResponseProxy(response, connHolder);
             }
         } catch (final ConnectionShutdownException ex) {
             final InterruptedIOException ioex = new InterruptedIOException(

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java Wed May 21 18:53:53 2014
@@ -227,9 +227,9 @@ public class MinimalClientExec implement
             if (entity == null || !entity.isStreaming()) {
                 // connection not needed and (assumed to be) in re-usable state
                 releaseTrigger.releaseConnection();
-                return Proxies.enhanceResponse(response, null);
+                return new HttpResponseProxy(response, null);
             } else {
-                return Proxies.enhanceResponse(response, releaseTrigger);
+                return new HttpResponseProxy(response, releaseTrigger);
             }
         } catch (final ConnectionShutdownException ex) {
             final InterruptedIOException ioex = new InterruptedIOException(

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java Wed May 21 18:53:53 2014
@@ -125,7 +125,7 @@ public class RedirectExec implements Cli
                     currentRequest = HttpRequestWrapper.wrap(redirect);
 
                     if (currentRequest instanceof HttpEntityEnclosingRequest) {
-                        Proxies.enhanceEntity((HttpEntityEnclosingRequest) currentRequest);
+                        RequestEntityProxy.enhance((HttpEntityEnclosingRequest) currentRequest);
                     }
 
                     final URI uri = currentRequest.getURI();

Copied: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java (from r1596520, httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/Proxies.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java?p2=httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java&p1=httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/Proxies.java&r1=1596520&r2=1596649&rev=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/Proxies.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java Wed May 21 18:53:53 2014
@@ -26,42 +26,33 @@
  */
 package org.apache.http.impl.execchain;
 
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
+import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
 import org.apache.http.annotation.NotThreadSafe;
-import org.apache.http.client.methods.CloseableHttpResponse;
 
 /**
- * Execution proxies for HTTP message objects.
+ * A Proxy class for {@link org.apache.http.HttpEntity} enclosed in a request message.
  *
  * @since 4.3
  */
 @NotThreadSafe
-class Proxies {
+class RequestEntityProxy implements HttpEntity  {
 
-    static void enhanceEntity(final HttpEntityEnclosingRequest request) {
+    static void enhance(final HttpEntityEnclosingRequest request) {
         final HttpEntity entity = request.getEntity();
         if (entity != null && !entity.isRepeatable() && !isEnhanced(entity)) {
-            final HttpEntity proxy = (HttpEntity) Proxy.newProxyInstance(
-                    HttpEntity.class.getClassLoader(),
-                    new Class<?>[] { HttpEntity.class },
-                    new RequestEntityExecHandler(entity));
-            request.setEntity(proxy);
+            request.setEntity(new RequestEntityProxy(entity));
         }
     }
 
     static boolean isEnhanced(final HttpEntity entity) {
-        if (entity != null && Proxy.isProxyClass(entity.getClass())) {
-            final InvocationHandler handler = Proxy.getInvocationHandler(entity);
-            return handler instanceof RequestEntityExecHandler;
-        } else {
-            return false;
-        }
+        return entity instanceof RequestEntityProxy;
     }
 
     static boolean isRepeatable(final HttpRequest request) {
@@ -69,9 +60,8 @@ class Proxies {
             final HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
             if (entity != null) {
                 if (isEnhanced(entity)) {
-                    final RequestEntityExecHandler handler = (RequestEntityExecHandler)
-                            Proxy.getInvocationHandler(entity);
-                    if (!handler.isConsumed()) {
+                    final RequestEntityProxy proxy = (RequestEntityProxy) entity;
+                    if (!proxy.isConsumed()) {
                         return true;
                     }
                 }
@@ -81,13 +71,67 @@ class Proxies {
         return true;
     }
 
-    public static CloseableHttpResponse enhanceResponse(
-            final HttpResponse original,
-            final ConnectionHolder connHolder) {
-        return (CloseableHttpResponse) Proxy.newProxyInstance(
-                ResponseProxyHandler.class.getClassLoader(),
-                new Class<?>[] { CloseableHttpResponse.class },
-                new ResponseProxyHandler(original, connHolder));
+    private final HttpEntity original;
+    private boolean consumed = false;
+
+    RequestEntityProxy(final HttpEntity original) {
+        super();
+        this.original = original;
+    }
+
+    public HttpEntity getOriginal() {
+        return original;
+    }
+
+    public boolean isConsumed() {
+        return consumed;
+    }
+
+    public boolean isRepeatable() {
+        return original.isRepeatable();
+    }
+
+    public boolean isChunked() {
+        return original.isChunked();
+    }
+
+    public long getContentLength() {
+        return original.getContentLength();
+    }
+
+    public Header getContentType() {
+        return original.getContentType();
+    }
+
+    public Header getContentEncoding() {
+        return original.getContentEncoding();
+    }
+
+    public InputStream getContent() throws IOException, IllegalStateException {
+        return original.getContent();
+    }
+
+    public void writeTo(final OutputStream outstream) throws IOException {
+        consumed = true;
+        original.writeTo(outstream);
+    }
+
+    public boolean isStreaming() {
+        return original.isStreaming();
+    }
+
+    @Deprecated
+    public void consumeContent() throws IOException {
+        consumed = true;
+        original.consumeContent();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("RequestEntityProxy{");
+        sb.append(original);
+        sb.append('}');
+        return sb.toString();
     }
 
 }

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java (from r1596520, httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityWrapper.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java?p2=httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java&p1=httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityWrapper.java&r1=1596520&r2=1596649&rev=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityWrapper.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java Wed May 21 18:53:53 2014
@@ -33,6 +33,7 @@ import java.io.OutputStream;
 import java.net.SocketException;
 
 import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
 import org.apache.http.annotation.NotThreadSafe;
 import org.apache.http.conn.EofSensorInputStream;
 import org.apache.http.conn.EofSensorWatcher;
@@ -44,28 +45,33 @@ import org.apache.http.entity.HttpEntity
  * @since 4.3
  */
 @NotThreadSafe
-class ResponseEntityWrapper extends HttpEntityWrapper implements EofSensorWatcher {
+class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher {
 
-    private final ConnectionHolder connReleaseTrigger;
+    private final ConnectionHolder connHolder;
 
-    public ResponseEntityWrapper(
-            final HttpEntity entity,
-            final ConnectionHolder connReleaseTrigger) {
+    public static void enchance(final HttpResponse response, final ConnectionHolder connHolder) {
+        final HttpEntity entity = response.getEntity();
+        if (entity != null && entity.isStreaming() && connHolder != null) {
+            response.setEntity(new ResponseEntityProxy(entity, connHolder));
+        }
+    }
+
+    ResponseEntityProxy(final HttpEntity entity, final ConnectionHolder connHolder) {
         super(entity);
-        this.connReleaseTrigger = connReleaseTrigger;
+        this.connHolder = connHolder;
     }
 
     private void cleanup() {
-        if (this.connReleaseTrigger != null) {
-            this.connReleaseTrigger.abortConnection();
+        if (this.connHolder != null) {
+            this.connHolder.abortConnection();
         }
     }
 
     public void releaseConnection() throws IOException {
-        if (this.connReleaseTrigger != null) {
+        if (this.connHolder != null) {
             try {
-                if (this.connReleaseTrigger.isReusable()) {
-                    this.connReleaseTrigger.releaseConnection();
+                if (this.connHolder.isReusable()) {
+                    this.connHolder.releaseConnection();
                 }
             } finally {
                 cleanup();
@@ -113,7 +119,7 @@ class ResponseEntityWrapper extends Http
 
     public boolean streamClosed(final InputStream wrapped) throws IOException {
         try {
-            final boolean open = connReleaseTrigger != null && !connReleaseTrigger.isReleased();
+            final boolean open = connHolder != null && !connHolder.isReleased();
             // this assumes that closing the stream will
             // consume the remainder of the response body:
             try {
@@ -135,4 +141,12 @@ class ResponseEntityWrapper extends Http
         return false;
     }
 
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("ResponseEntityProxy{");
+        sb.append(wrappedEntity);
+        sb.append('}');
+        return sb.toString();
+    }
+
 }

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java Wed May 21 18:53:53 2014
@@ -100,7 +100,7 @@ public class RetryExec implements Client
                     if (this.log.isDebugEnabled()) {
                         this.log.debug(ex.getMessage(), ex);
                     }
-                    if (!Proxies.isRepeatable(request)) {
+                    if (!RequestEntityProxy.isRepeatable(request)) {
                         this.log.debug("Cannot retry non-repeatable request");
                         throw new NonRepeatableRequestException("Cannot retry request " +
                                 "with a non-repeatable request entity", ex);

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java Wed May 21 18:53:53 2014
@@ -31,7 +31,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InterruptedIOException;
-import java.lang.reflect.Proxy;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -39,7 +38,6 @@ import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.Assert;
 import org.apache.http.ConnectionReuseStrategy;
 import org.apache.http.Header;
 import org.apache.http.HttpClientConnection;
@@ -90,6 +88,8 @@ import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import junit.framework.Assert;
+
 @SuppressWarnings({"boxing","static-access"}) // test code
 public class TestMainClientExec {
 
@@ -200,7 +200,7 @@ public class TestMainClientExec {
         Assert.assertSame(managedConn, context.getConnection());
         Assert.assertNull(context.getUserToken());
         Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(Proxy.isProxyClass(finalResponse.getClass()));
+        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
     }
 
     @Test
@@ -232,7 +232,7 @@ public class TestMainClientExec {
         Mockito.verify(managedConn, Mockito.never()).close();
 
         Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(Proxy.isProxyClass(finalResponse.getClass()));
+        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
     }
 
     @Test
@@ -298,7 +298,7 @@ public class TestMainClientExec {
         Mockito.verify(managedConn, Mockito.never()).close();
 
         Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(Proxy.isProxyClass(finalResponse.getClass()));
+        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
         finalResponse.close();
 
         Mockito.verify(connManager, Mockito.times(1)).releaseConnection(
@@ -332,7 +332,7 @@ public class TestMainClientExec {
         Mockito.verify(managedConn, Mockito.times(1)).close();
 
         Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(Proxy.isProxyClass(finalResponse.getClass()));
+        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
     }
 
     @Test

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java Wed May 21 18:53:53 2014
@@ -26,7 +26,13 @@
  */
 package org.apache.http.impl.execchain;
 
-import junit.framework.Assert;
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.http.ConnectionReuseStrategy;
 import org.apache.http.HttpClientConnection;
@@ -57,14 +63,7 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import static org.junit.Assert.assertEquals;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.lang.reflect.Proxy;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
+import junit.framework.Assert;
 
 @SuppressWarnings({"boxing","static-access"}) // test code
 public class TestMinimalClientExec {
@@ -132,7 +131,7 @@ public class TestMinimalClientExec {
 
         Assert.assertSame(managedConn, context.getConnection());
         Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(Proxy.isProxyClass(finalResponse.getClass()));
+        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
     }
 
     @Test
@@ -164,7 +163,7 @@ public class TestMinimalClientExec {
         Mockito.verify(managedConn, Mockito.never()).close();
 
         Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(Proxy.isProxyClass(finalResponse.getClass()));
+        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
     }
 
     @Test
@@ -201,7 +200,7 @@ public class TestMinimalClientExec {
         Mockito.verify(managedConn, Mockito.never()).close();
 
         Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(Proxy.isProxyClass(finalResponse.getClass()));
+        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
         finalResponse.close();
 
         Mockito.verify(connManager, Mockito.times(1)).releaseConnection(

Modified: httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java?rev=1596649&r1=1596648&r2=1596649&view=diff
==============================================================================
--- httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java (original)
+++ httpcomponents/httpclient/branches/4.3.x/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java Wed May 21 18:53:53 2014
@@ -44,7 +44,7 @@ public class TestResponseEntityWrapper {
     private InputStream instream;
     private HttpEntity entity;
     private ConnectionHolder connHolder;
-    private ResponseEntityWrapper wrapper;
+    private ResponseEntityProxy wrapper;
 
     @Before
     public void setup() throws Exception {
@@ -52,7 +52,7 @@ public class TestResponseEntityWrapper {
         entity = Mockito.mock(HttpEntity.class);
         Mockito.when(entity.getContent()).thenReturn(instream);
         connHolder = Mockito.mock(ConnectionHolder.class);
-        wrapper = new ResponseEntityWrapper(entity, connHolder);
+        wrapper = new ResponseEntityProxy(entity, connHolder);
     }
 
     @Test