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