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 2012/12/08 20:59:26 UTC
svn commit: r1418743 [1/6] - in /httpcomponents/httpclient/trunk:
httpclient-cache/src/main/java/org/apache/http/impl/client/cache/
httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/
httpclient-cache/src/test/java/org/apache/ht...
Author: olegk
Date: Sat Dec 8 19:59:24 2012
New Revision: 1418743
URL: http://svn.apache.org/viewvc?rev=1418743&view=rev
Log:
Ported CachingHttpClient to ClientExecChain API
Added:
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java
- copied, changed from r1418654, httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java (with props)
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java (with props)
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java (with props)
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExec.java (contents, props changed)
- copied, changed from r1418654, httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/execchain/Proxies.java (contents, props changed)
- copied, changed from r1418654, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/execchain/ExecProxies.java
Removed:
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DoNotTestProtocolRequirements.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyHttpClient.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/execchain/ExecProxies.java
Modified:
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidationRequest.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidator.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheJiraNumber1147.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolAllowedBehavior.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtocolRequirements.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedHttpCacheStorage.java
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/execchain/MainClientExec.java
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/execchain/RedirectExec.java
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/execchain/RetryExec.java
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java?rev=1418743&r1=1418742&r2=1418743&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java Sat Dec 8 19:59:24 2012
@@ -29,11 +29,12 @@ package org.apache.http.impl.client.cach
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.http.HttpHost;
-import org.apache.http.ProtocolException;
+import org.apache.http.HttpException;
import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.methods.HttpRequestWrapper;
-import org.apache.http.protocol.HttpContext;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
/**
* Class used to represent an asynchronous revalidation event, such as with
@@ -41,10 +42,11 @@ import org.apache.http.protocol.HttpCont
*/
class AsynchronousValidationRequest implements Runnable {
private final AsynchronousValidator parent;
- private final CachingHttpClient cachingClient;
- private final HttpHost target;
+ private final CachingExec cachingExec;
+ private final HttpRoute route;
private final HttpRequestWrapper request;
- private final HttpContext context;
+ private final HttpClientContext context;
+ private final HttpExecutionAware execAware;
private final HttpCacheEntry cacheEntry;
private final String identifier;
@@ -61,27 +63,32 @@ class AsynchronousValidationRequest impl
* @param bookKeeping
* @param identifier
*/
- AsynchronousValidationRequest(AsynchronousValidator parent,
- CachingHttpClient cachingClient, HttpHost target,
- HttpRequestWrapper request, HttpContext context,
- HttpCacheEntry cacheEntry,
- String identifier) {
+ AsynchronousValidationRequest(
+ final AsynchronousValidator parent,
+ final CachingExec cachingExec,
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final HttpCacheEntry cacheEntry,
+ final String identifier) {
this.parent = parent;
- this.cachingClient = cachingClient;
- this.target = target;
+ this.cachingExec = cachingExec;
+ this.route = route;
this.request = request;
this.context = context;
+ this.execAware = execAware;
this.cacheEntry = cacheEntry;
this.identifier = identifier;
}
public void run() {
try {
- cachingClient.revalidateCacheEntry(target, request, context, cacheEntry);
+ cachingExec.revalidateCacheEntry(route, request, context, execAware, cacheEntry);
} catch (IOException ioe) {
- log.debug("Asynchronous revalidation failed due to exception: " + ioe);
- } catch (ProtocolException pe) {
- log.error("ProtocolException thrown during asynchronous revalidation: " + pe);
+ log.debug("Asynchronous revalidation failed due to I/O error", ioe);
+ } catch (HttpException pe) {
+ log.error("HTTP protocol exception during asynchronous revalidation", pe);
} finally {
parent.markComplete(identifier);
}
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java?rev=1418743&r1=1418742&r2=1418743&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java Sat Dec 8 19:59:24 2012
@@ -37,17 +37,18 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.http.HttpHost;
import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.methods.HttpRequestWrapper;
-import org.apache.http.protocol.HttpContext;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
/**
* Class used for asynchronous revalidations to be used when the "stale-
* while-revalidate" directive is present
*/
class AsynchronousValidator {
- private final CachingHttpClient cachingClient;
+ private final CachingExec cachingExec;
private final ExecutorService executor;
private final Set<String> queued;
private final CacheKeyGenerator cacheKeyGenerator;
@@ -59,16 +60,16 @@ class AsynchronousValidator {
* using the supplied {@link CachingHttpClient}, and
* a {@link ThreadPoolExecutor} generated according to the thread
* pool settings provided in the given {@link CacheConfig}.
- * @param cachingClient used to execute asynchronous requests
+ * @param cachingExect used to execute asynchronous requests
* @param config specifies thread pool settings. See
* {@link CacheConfig#getAsynchronousWorkersMax()},
* {@link CacheConfig#getAsynchronousWorkersCore()},
* {@link CacheConfig#getAsynchronousWorkerIdleLifetimeSecs()},
* and {@link CacheConfig#getRevalidationQueueSize()}.
*/
- public AsynchronousValidator(CachingHttpClient cachingClient,
+ public AsynchronousValidator(CachingExec cachingExect,
CacheConfig config) {
- this(cachingClient,
+ this(cachingExect,
new ThreadPoolExecutor(config.getAsynchronousWorkersCore(),
config.getAsynchronousWorkersMax(),
config.getAsynchronousWorkerIdleLifetimeSecs(),
@@ -81,12 +82,11 @@ class AsynchronousValidator {
* Create AsynchronousValidator which will make revalidation requests
* using the supplied {@link CachingHttpClient} and
* {@link ExecutorService}.
- * @param cachingClient used to execute asynchronous requests
+ * @param cachingExect used to execute asynchronous requests
* @param executor used to manage a thread pool of revalidation workers
*/
- AsynchronousValidator(CachingHttpClient cachingClient,
- ExecutorService executor) {
- this.cachingClient = cachingClient;
+ AsynchronousValidator(CachingExec cachingExec, ExecutorService executor) {
+ this.cachingExec = cachingExec;
this.executor = executor;
this.queued = new HashSet<String>();
this.cacheKeyGenerator = new CacheKeyGenerator();
@@ -94,21 +94,20 @@ class AsynchronousValidator {
/**
* Schedules an asynchronous revalidation
- *
- * @param target
- * @param request
- * @param context
- * @param entry
*/
- public synchronized void revalidateCacheEntry(HttpHost target,
- HttpRequestWrapper request, HttpContext context, HttpCacheEntry entry) {
+ public synchronized void revalidateCacheEntry(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final HttpCacheEntry entry) {
// getVariantURI will fall back on getURI if no variants exist
- String uri = cacheKeyGenerator.getVariantURI(target, request, entry);
+ String uri = cacheKeyGenerator.getVariantURI(route.getTargetHost(), request, entry);
if (!queued.contains(uri)) {
AsynchronousValidationRequest revalidationRequest =
- new AsynchronousValidationRequest(this, cachingClient, target,
- request, context, entry, uri);
+ new AsynchronousValidationRequest(
+ this, cachingExec, route, request, context, execAware, entry, uri);
try {
executor.execute(revalidationRequest);
Copied: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java (from r1418654, httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java?p2=httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java&p1=httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java&r1=1418654&r2=1418743&rev=1418743&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java Sat Dec 8 19:59:24 2012
@@ -27,8 +27,6 @@
package org.apache.http.impl.client.cache;
import java.io.IOException;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.net.URI;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -39,33 +37,31 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
-import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpMessage;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
-import org.apache.http.ProtocolException;
import org.apache.http.ProtocolVersion;
import org.apache.http.RequestLine;
import org.apache.http.annotation.ThreadSafe;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.ResponseHandler;
import org.apache.http.client.cache.CacheResponseStatus;
import org.apache.http.client.cache.HeaderConstants;
import org.apache.http.client.cache.HttpCacheEntry;
import org.apache.http.client.cache.HttpCacheStorage;
import org.apache.http.client.cache.ResourceFactory;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.methods.HttpRequestWrapper;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.client.execchain.ClientExecChain;
import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHttpResponse;
-import org.apache.http.params.HttpParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
@@ -73,32 +69,11 @@ import org.apache.http.util.EntityUtils;
import org.apache.http.util.VersionInfo;
/**
- * <p>The {@link CachingHttpClient} is meant to be a drop-in replacement for
- * a {@link DefaultHttpClient} that transparently adds client-side caching.
+ * <p>CachingExec is intended to transparently add client-side caching
+ * to the HttpClient {@link ClientExecChain execution chain}.
* The current implementation is conditionally compliant with HTTP/1.1
* (meaning all the MUST and MUST NOTs are obeyed), although quite a lot,
- * though not all, of the SHOULDs and SHOULD NOTs are obeyed too. Generally
- * speaking, you construct a {@code CachingHttpClient} by providing a
- * "backend" {@link HttpClient} used for making actual network requests and
- * provide an {@link HttpCacheStorage} instance to use for holding onto
- * cached responses. Additional configuration options can be provided by
- * passing in a {@link CacheConfig}. Note that all of the usual client
- * related configuration you want to do vis-a-vis timeouts and connection
- * pools should be done on this backend client before constructing a {@code
- * CachingHttpClient} from it.</p>
- *
- * <p>Generally speaking, the {@code CachingHttpClient} is implemented as a
- * <a href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</a>
- * of the backend client; for any incoming request it attempts to satisfy
- * it from the cache, but if it can't, or if it needs to revalidate a stale
- * cache entry, it will use the backend client to make an actual request.
- * However, a proper HTTP/1.1 cache won't change the semantics of a request
- * and response; in particular, if you issue an unconditional request you
- * will get a full response (although it may be served to you from the cache,
- * or the cache may make a conditional request on your behalf to the origin).
- * This notion of "semantic transparency" means you should be able to drop
- * a {@link CachingHttpClient} into an existing application without breaking
- * anything.</p>
+ * though not all, of the SHOULDs and SHOULD NOTs are obeyed too.</p>
*
* <p>Folks that would like to experiment with alternative storage backends
* should look at the {@link HttpCacheStorage} interface and the related
@@ -108,10 +83,11 @@ import org.apache.http.util.VersionInfo;
* org.apache.http.impl.client.cache.memcached.MemcachedHttpCacheStorage
* memcached} storage backends.</p>
* </p>
- * @since 4.1
+ *
+ * @since 4.3
*/
@ThreadSafe // So long as the responseCache implementation is threadsafe
-public class CachingHttpClient implements HttpClient {
+public class CachingExec implements ClientExecChain {
/**
* This is the name under which the {@link
@@ -129,160 +105,77 @@ public class CachingHttpClient implement
private final Map<ProtocolVersion, String> viaHeaders = new HashMap<ProtocolVersion, String>(4);
- private final HttpClient backend;
+ private final CacheConfig cacheConfig;
+ private final ClientExecChain backend;
private final HttpCache responseCache;
private final CacheValidityPolicy validityPolicy;
- private final ResponseCachingPolicy responseCachingPolicy;
private final CachedHttpResponseGenerator responseGenerator;
private final CacheableRequestPolicy cacheableRequestPolicy;
private final CachedResponseSuitabilityChecker suitabilityChecker;
-
private final ConditionalRequestBuilder conditionalRequestBuilder;
-
- private final long maxObjectSizeBytes;
- private final boolean sharedCache;
-
private final ResponseProtocolCompliance responseCompliance;
private final RequestProtocolCompliance requestCompliance;
+ private final ResponseCachingPolicy responseCachingPolicy;
private final AsynchronousValidator asynchRevalidator;
private final Log log = LogFactory.getLog(getClass());
- CachingHttpClient(
- HttpClient client,
+ public CachingExec(
+ ClientExecChain backend,
HttpCache cache,
CacheConfig config) {
super();
- if (client == null) {
- throw new IllegalArgumentException("HttpClient may not be null");
+ if (backend == null) {
+ throw new IllegalArgumentException("HTTP backend may not be null");
}
if (cache == null) {
throw new IllegalArgumentException("HttpCache may not be null");
}
- if (config == null) {
- throw new IllegalArgumentException("CacheConfig may not be null");
- }
- this.maxObjectSizeBytes = config.getMaxObjectSize();
- this.sharedCache = config.isSharedCache();
- this.backend = client;
+ this.cacheConfig = config != null ? config : CacheConfig.DEFAULT;
+ this.backend = backend;
this.responseCache = cache;
this.validityPolicy = new CacheValidityPolicy();
- this.responseCachingPolicy = new ResponseCachingPolicy(maxObjectSizeBytes, sharedCache);
this.responseGenerator = new CachedHttpResponseGenerator(this.validityPolicy);
this.cacheableRequestPolicy = new CacheableRequestPolicy();
this.suitabilityChecker = new CachedResponseSuitabilityChecker(this.validityPolicy, config);
this.conditionalRequestBuilder = new ConditionalRequestBuilder();
-
this.responseCompliance = new ResponseProtocolCompliance();
this.requestCompliance = new RequestProtocolCompliance();
-
+ this.responseCachingPolicy = new ResponseCachingPolicy(
+ this.cacheConfig.getMaxObjectSize(), this.cacheConfig.isSharedCache());
this.asynchRevalidator = makeAsynchronousValidator(config);
}
- /**
- * Constructs a {@code CachingHttpClient} with default caching settings that
- * stores cache entries in memory and uses a vanilla {@link DefaultHttpClient}
- * for backend requests.
- */
- public CachingHttpClient() {
- this(new DefaultHttpClient(),
- new BasicHttpCache(),
- new CacheConfig());
- }
-
- /**
- * Constructs a {@code CachingHttpClient} with the given caching options that
- * stores cache entries in memory and uses a vanilla {@link DefaultHttpClient}
- * for backend requests.
- * @param config cache module options
- */
- public CachingHttpClient(CacheConfig config) {
- this(new DefaultHttpClient(),
- new BasicHttpCache(config),
- config);
- }
-
- /**
- * Constructs a {@code CachingHttpClient} with default caching settings that
- * stores cache entries in memory and uses the given {@link HttpClient}
- * for backend requests.
- * @param client used to make origin requests
- */
- public CachingHttpClient(HttpClient client) {
- this(client,
- new BasicHttpCache(),
- new CacheConfig());
- }
-
- /**
- * Constructs a {@code CachingHttpClient} with the given caching options that
- * stores cache entries in memory and uses the given {@link HttpClient}
- * for backend requests.
- * @param config cache module options
- * @param client used to make origin requests
- */
- public CachingHttpClient(HttpClient client, CacheConfig config) {
- this(client,
- new BasicHttpCache(config),
- config);
- }
-
- /**
- * Constructs a {@code CachingHttpClient} with the given caching options
- * that stores cache entries in the provided storage backend and uses
- * the given {@link HttpClient} for backend requests. However, cached
- * response bodies are managed using the given {@link ResourceFactory}.
- * @param client used to make origin requests
- * @param resourceFactory how to manage cached response bodies
- * @param storage where to store cache entries
- * @param config cache module options
- */
- public CachingHttpClient(
- HttpClient client,
+ public CachingExec(
+ ClientExecChain backend,
ResourceFactory resourceFactory,
HttpCacheStorage storage,
CacheConfig config) {
- this(client,
- new BasicHttpCache(resourceFactory, storage, config),
- config);
+ this(backend, new BasicHttpCache(resourceFactory, storage, config), config);
}
- /**
- * Constructs a {@code CachingHttpClient} with the given caching options
- * that stores cache entries in the provided storage backend and uses
- * the given {@link HttpClient} for backend requests.
- * @param client used to make origin requests
- * @param storage where to store cache entries
- * @param config cache module options
- */
- public CachingHttpClient(
- HttpClient client,
- HttpCacheStorage storage,
- CacheConfig config) {
- this(client,
- new BasicHttpCache(new HeapResourceFactory(), storage, config),
- config);
+ public CachingExec(ClientExecChain backend) {
+ this(backend, new BasicHttpCache(), CacheConfig.DEFAULT);
}
- CachingHttpClient(
- HttpClient backend,
+ CachingExec(
+ ClientExecChain backend,
+ HttpCache responseCache,
CacheValidityPolicy validityPolicy,
ResponseCachingPolicy responseCachingPolicy,
- HttpCache responseCache,
CachedHttpResponseGenerator responseGenerator,
CacheableRequestPolicy cacheableRequestPolicy,
CachedResponseSuitabilityChecker suitabilityChecker,
ConditionalRequestBuilder conditionalRequestBuilder,
ResponseProtocolCompliance responseCompliance,
- RequestProtocolCompliance requestCompliance) {
- CacheConfig config = new CacheConfig();
- this.maxObjectSizeBytes = config.getMaxObjectSize();
- this.sharedCache = config.isSharedCache();
+ RequestProtocolCompliance requestCompliance,
+ CacheConfig config) {
+ this.cacheConfig = config != null ? config : CacheConfig.DEFAULT;
this.backend = backend;
+ this.responseCache = responseCache;
this.validityPolicy = validityPolicy;
this.responseCachingPolicy = responseCachingPolicy;
- this.responseCache = responseCache;
this.responseGenerator = responseGenerator;
this.cacheableRequestPolicy = cacheableRequestPolicy;
this.suitabilityChecker = suitabilityChecker;
@@ -327,195 +220,142 @@ public class CachingHttpClient implement
return cacheUpdates.get();
}
- public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException {
- HttpContext defaultContext = null;
- return execute(target, request, defaultContext);
- }
-
- public <T> T execute(HttpHost target, HttpRequest request,
- ResponseHandler<? extends T> responseHandler) throws IOException {
- return execute(target, request, responseHandler, null);
- }
-
- public <T> T execute(HttpHost target, HttpRequest request,
- ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException {
- HttpResponse resp = execute(target, request, context);
- return handleAndConsume(responseHandler,resp);
- }
-
- public HttpResponse execute(HttpUriRequest request) throws IOException {
- HttpContext context = null;
- return execute(request, context);
- }
-
- public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException {
- URI uri = request.getURI();
- HttpHost httpHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
- return execute(httpHost, request, context);
- }
-
- public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler)
- throws IOException {
- return execute(request, responseHandler, null);
- }
-
- public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler,
- HttpContext context) throws IOException {
- HttpResponse resp = execute(request, context);
- return handleAndConsume(responseHandler, resp);
- }
-
- private <T> T handleAndConsume(
- final ResponseHandler<? extends T> responseHandler,
- HttpResponse response) throws Error, IOException {
- T result;
- try {
- result = responseHandler.handleResponse(response);
- } catch (Exception t) {
- HttpEntity entity = response.getEntity();
- try {
- EntityUtils.consume(entity);
- } catch (Exception t2) {
- // Log this exception. The original exception is more
- // important and will be thrown to the caller.
- this.log.warn("Error consuming content after an exception.", t2);
- }
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- }
- if (t instanceof IOException) {
- throw (IOException) t;
- }
- throw new UndeclaredThrowableException(t);
- }
-
- // Handling the response was successful. Ensure that the content has
- // been fully consumed.
- HttpEntity entity = response.getEntity();
- EntityUtils.consume(entity);
- return result;
- }
+ public CloseableHttpResponse execute(
+ final HttpRoute route,
+ final HttpRequestWrapper request) throws IOException, HttpException {
+ return execute(route, request, HttpClientContext.create(), null);
+ }
+
+ public CloseableHttpResponse execute(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context) throws IOException, HttpException {
+ return execute(route, request, context, null);
+ }
+
+ public CloseableHttpResponse execute(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware) throws IOException, HttpException {
- public ClientConnectionManager getConnectionManager() {
- return backend.getConnectionManager();
- }
-
- public HttpParams getParams() {
- return backend.getParams();
- }
-
- public HttpResponse execute(HttpHost target, HttpRequest originalRequest, HttpContext context)
- throws IOException {
-
- HttpRequestWrapper request;
- if (originalRequest instanceof HttpRequestWrapper) {
- request = ((HttpRequestWrapper) originalRequest);
- } else {
- request = HttpRequestWrapper.wrap(originalRequest);
- }
- String via = generateViaHeader(originalRequest);
+ HttpHost target = route.getTargetHost();
+ String via = generateViaHeader(request.getOriginal());
// default response context
setResponseStatus(context, CacheResponseStatus.CACHE_MISS);
if (clientRequestsOurOptions(request)) {
setResponseStatus(context, CacheResponseStatus.CACHE_MODULE_RESPONSE);
- return new OptionsHttp11Response();
+ return Proxies.enhanceResponse(new OptionsHttp11Response());
}
- HttpResponse fatalErrorResponse = getFatallyNoncompliantResponse(
- request, context);
- if (fatalErrorResponse != null) return fatalErrorResponse;
+ HttpResponse fatalErrorResponse = getFatallyNoncompliantResponse(request, context);
+ if (fatalErrorResponse != null) {
+ return Proxies.enhanceResponse(fatalErrorResponse);
+ }
requestCompliance.makeRequestCompliant(request);
request.addHeader("Via",via);
- flushEntriesInvalidatedByRequest(target, request);
+ flushEntriesInvalidatedByRequest(route.getTargetHost(), request);
if (!cacheableRequestPolicy.isServableFromCache(request)) {
log.debug("Request is not servable from cache");
- return callBackend(target, request, context);
+ return callBackend(route, request, context, execAware);
}
HttpCacheEntry entry = satisfyFromCache(target, request);
if (entry == null) {
log.debug("Cache miss");
- return handleCacheMiss(target, request, context);
+ return handleCacheMiss(route, request, context, execAware);
}
- return handleCacheHit(target, request, context, entry);
+ return handleCacheHit(route, request, context, execAware, entry);
}
- private HttpResponse handleCacheHit(HttpHost target, HttpRequestWrapper request,
- HttpContext context, HttpCacheEntry entry)
- throws ClientProtocolException, IOException {
+ private CloseableHttpResponse handleCacheHit(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final HttpCacheEntry entry) throws IOException, HttpException {
+ HttpHost target = route.getTargetHost();
recordCacheHit(target, request);
- HttpResponse out = null;
+ CloseableHttpResponse out = null;
Date now = getCurrentDate();
if (suitabilityChecker.canCachedResponseBeUsed(target, request, entry, now)) {
log.debug("Cache hit");
- out = generateCachedResponse(request, context, entry, now);
+ out = Proxies.enhanceResponse(generateCachedResponse(request, context, entry, now));
} else if (!mayCallBackend(request)) {
log.debug("Cache entry not suitable but only-if-cached requested");
- out = generateGatewayTimeout(context);
+ out = Proxies.enhanceResponse(generateGatewayTimeout(context));
} else if (validityPolicy.isRevalidatable(entry)) {
log.debug("Revalidating cache entry");
- return revalidateCacheEntry(target, request, context, entry, now);
+ return revalidateCacheEntry(route, request, context, execAware, entry, now);
} else {
log.debug("Cache entry not usable; calling backend");
- return callBackend(target, request, context);
+ return callBackend(route, request, context, execAware);
}
if (context != null) {
- context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
- context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
- context.setAttribute(ExecutionContext.HTTP_RESPONSE, out);
- context.setAttribute(ExecutionContext.HTTP_REQ_SENT, Boolean.TRUE);
+ context.setAttribute(ClientContext.ROUTE, route);
+ context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
+ context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
+ context.setAttribute(ExecutionContext.HTTP_RESPONSE, out);
+ context.setAttribute(ExecutionContext.HTTP_REQ_SENT, Boolean.TRUE);
}
return out;
}
- private HttpResponse revalidateCacheEntry(HttpHost target,
- HttpRequestWrapper request, HttpContext context, HttpCacheEntry entry,
- Date now) throws ClientProtocolException {
+ private CloseableHttpResponse revalidateCacheEntry(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final HttpCacheEntry entry,
+ final Date now) throws IOException, HttpException {
try {
if (asynchRevalidator != null
&& !staleResponseNotAllowed(request, entry, now)
&& validityPolicy.mayReturnStaleWhileRevalidating(entry, now)) {
log.trace("Serving stale with asynchronous revalidation");
- final HttpResponse resp = generateCachedResponse(request, context, entry, now);
-
- asynchRevalidator.revalidateCacheEntry(target, request, context, entry);
-
- return resp;
+ HttpResponse resp = generateCachedResponse(request, context, entry, now);
+ asynchRevalidator.revalidateCacheEntry(route, request, context, execAware, entry);
+ return Proxies.enhanceResponse(resp);
}
- return revalidateCacheEntry(target, request, context, entry);
+ return revalidateCacheEntry(route, request, context, execAware, entry);
} catch (IOException ioex) {
- return handleRevalidationFailure(request, context, entry, now);
- } catch (ProtocolException e) {
- throw new ClientProtocolException(e);
+ return Proxies.enhanceResponse(
+ handleRevalidationFailure(request, context, entry, now));
}
}
- private HttpResponse handleCacheMiss(HttpHost target, HttpRequestWrapper request,
- HttpContext context) throws IOException {
+ private CloseableHttpResponse handleCacheMiss(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware) throws IOException, HttpException {
+ HttpHost target = route.getTargetHost();
recordCacheMiss(target, request);
if (!mayCallBackend(request)) {
- return new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT,
- "Gateway Timeout");
+ return Proxies.enhanceResponse(
+ new BasicHttpResponse(
+ HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout"));
}
- Map<String, Variant> variants =
- getExistingCacheVariants(target, request);
+ Map<String, Variant> variants = getExistingCacheVariants(target, request);
if (variants != null && variants.size() > 0) {
- return negotiateResponseFromVariants(target, request, context, variants);
+ return Proxies.enhanceResponse(
+ negotiateResponseFromVariants(route, request, context, execAware, variants));
}
- return callBackend(target, request, context);
+ return callBackend(route, request, context, execAware);
}
- private HttpCacheEntry satisfyFromCache(HttpHost target, HttpRequestWrapper request) {
+ private HttpCacheEntry satisfyFromCache(
+ final HttpHost target, final HttpRequestWrapper request) {
HttpCacheEntry entry = null;
try {
entry = responseCache.getCacheEntry(target, request);
@@ -525,8 +365,9 @@ public class CachingHttpClient implement
return entry;
}
- private HttpResponse getFatallyNoncompliantResponse(HttpRequestWrapper request,
- HttpContext context) {
+ private HttpResponse getFatallyNoncompliantResponse(
+ final HttpRequestWrapper request,
+ final HttpContext context) {
HttpResponse fatalErrorResponse = null;
List<RequestProtocolError> fatalError = requestCompliance.requestIsFatallyNonCompliant(request);
@@ -537,8 +378,9 @@ public class CachingHttpClient implement
return fatalErrorResponse;
}
- private Map<String, Variant> getExistingCacheVariants(HttpHost target,
- HttpRequestWrapper request) {
+ private Map<String, Variant> getExistingCacheVariants(
+ final HttpHost target,
+ final HttpRequestWrapper request) {
Map<String,Variant> variants = null;
try {
variants = responseCache.getVariantCacheEntriesWithEtags(target, request);
@@ -548,7 +390,7 @@ public class CachingHttpClient implement
return variants;
}
- private void recordCacheMiss(HttpHost target, HttpRequestWrapper request) {
+ private void recordCacheMiss(final HttpHost target, final HttpRequestWrapper request) {
cacheMisses.getAndIncrement();
if (log.isTraceEnabled()) {
RequestLine rl = request.getRequestLine();
@@ -556,7 +398,7 @@ public class CachingHttpClient implement
}
}
- private void recordCacheHit(HttpHost target, HttpRequestWrapper request) {
+ private void recordCacheHit(final HttpHost target, final HttpRequestWrapper request) {
cacheHits.getAndIncrement();
if (log.isTraceEnabled()) {
RequestLine rl = request.getRequestLine();
@@ -569,8 +411,9 @@ public class CachingHttpClient implement
setResponseStatus(context, CacheResponseStatus.VALIDATED);
}
- private void flushEntriesInvalidatedByRequest(HttpHost target,
- HttpRequestWrapper request) {
+ private void flushEntriesInvalidatedByRequest(
+ final HttpHost target,
+ final HttpRequestWrapper request) {
try {
responseCache.flushInvalidatedCacheEntriesFor(target, request);
} catch (IOException ioe) {
@@ -594,8 +437,11 @@ public class CachingHttpClient implement
return cachedResponse;
}
- private HttpResponse handleRevalidationFailure(HttpRequestWrapper request,
- HttpContext context, HttpCacheEntry entry, Date now) {
+ private HttpResponse handleRevalidationFailure(
+ final HttpRequestWrapper request,
+ final HttpContext context,
+ final HttpCacheEntry entry,
+ final Date now) {
if (staleResponseNotAllowed(request, entry, now)) {
return generateGatewayTimeout(context);
} else {
@@ -603,28 +449,30 @@ public class CachingHttpClient implement
}
}
- private HttpResponse generateGatewayTimeout(HttpContext context) {
+ private HttpResponse generateGatewayTimeout(final HttpContext context) {
setResponseStatus(context, CacheResponseStatus.CACHE_MODULE_RESPONSE);
return new BasicHttpResponse(HttpVersion.HTTP_1_1,
HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
}
- private HttpResponse unvalidatedCacheHit(HttpContext context,
- HttpCacheEntry entry) {
+ private HttpResponse unvalidatedCacheHit(
+ final HttpContext context, final HttpCacheEntry entry) {
final HttpResponse cachedResponse = responseGenerator.generateResponse(entry);
setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
cachedResponse.addHeader(HeaderConstants.WARNING, "111 localhost \"Revalidation failed\"");
return cachedResponse;
}
- private boolean staleResponseNotAllowed(HttpRequestWrapper request,
- HttpCacheEntry entry, Date now) {
+ private boolean staleResponseNotAllowed(
+ final HttpRequestWrapper request,
+ final HttpCacheEntry entry,
+ final Date now) {
return validityPolicy.mustRevalidate(entry)
- || (isSharedCache() && validityPolicy.proxyRevalidate(entry))
+ || (cacheConfig.isSharedCache() && validityPolicy.proxyRevalidate(entry))
|| explicitFreshnessRequest(request, entry, now);
}
- private boolean mayCallBackend(HttpRequestWrapper request) {
+ private boolean mayCallBackend(final HttpRequestWrapper request) {
for (Header h: request.getHeaders(HeaderConstants.CACHE_CONTROL)) {
for (HeaderElement elt : h.getElements()) {
if ("only-if-cached".equals(elt.getName())) {
@@ -636,7 +484,10 @@ public class CachingHttpClient implement
return true;
}
- private boolean explicitFreshnessRequest(HttpRequestWrapper request, HttpCacheEntry entry, Date now) {
+ private boolean explicitFreshnessRequest(
+ final HttpRequestWrapper request,
+ final HttpCacheEntry entry,
+ final Date now) {
for(Header h : request.getHeaders(HeaderConstants.CACHE_CONTROL)) {
for(HeaderElement elt : h.getElements()) {
if (HeaderConstants.CACHE_CONTROL_MAX_STALE.equals(elt.getName())) {
@@ -657,7 +508,7 @@ public class CachingHttpClient implement
return false;
}
- private String generateViaHeader(HttpMessage msg) {
+ private String generateViaHeader(final HttpMessage msg) {
final ProtocolVersion pv = msg.getProtocolVersion();
String existingEntry = viaHeaders.get(pv);
@@ -695,22 +546,11 @@ public class CachingHttpClient implement
return SUPPORTS_RANGE_AND_CONTENT_RANGE_HEADERS;
}
- /**
- * Reports whether this {@code CachingHttpClient} is configured as
- * a shared (public) or non-shared (private) cache. See {@link
- * CacheConfig#setSharedCache(boolean)}.
- * @return {@code true} if we are behaving as a shared (public)
- * cache
- */
- public boolean isSharedCache() {
- return sharedCache;
- }
-
Date getCurrentDate() {
return new Date();
}
- boolean clientRequestsOurOptions(HttpRequest request) {
+ boolean clientRequestsOurOptions(final HttpRequest request) {
RequestLine line = request.getRequestLine();
if (!HeaderConstants.OPTIONS_METHOD.equals(line.getMethod()))
@@ -725,17 +565,19 @@ public class CachingHttpClient implement
return true;
}
- HttpResponse callBackend(HttpHost target, HttpRequestWrapper request, HttpContext context)
- throws IOException {
+ CloseableHttpResponse callBackend(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware) throws IOException, HttpException {
Date requestDate = getCurrentDate();
log.trace("Calling the backend");
- HttpResponse backendResponse = backend.execute(target, request, context);
+ CloseableHttpResponse backendResponse = backend.execute(route, request, context, execAware);
backendResponse.addHeader("Via", generateViaHeader(backendResponse));
- return handleBackendResponse(target, request, requestDate, getCurrentDate(),
- backendResponse);
-
+ return handleBackendResponse(route, request, context, execAware,
+ requestDate, getCurrentDate(), backendResponse);
}
private boolean revalidationResponseIsTooOld(HttpResponse backendResponse,
@@ -757,51 +599,56 @@ public class CachingHttpClient implement
return false;
}
- HttpResponse negotiateResponseFromVariants(HttpHost target,
- HttpRequestWrapper request, HttpContext context,
- Map<String, Variant> variants) throws IOException {
+ HttpResponse negotiateResponseFromVariants(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final Map<String, Variant> variants) throws IOException, HttpException {
HttpRequestWrapper conditionalRequest = conditionalRequestBuilder
.buildConditionalRequestFromVariants(request, variants);
Date requestDate = getCurrentDate();
- HttpResponse backendResponse = backend.execute(target, conditionalRequest, context);
+ CloseableHttpResponse backendResponse = backend.execute(
+ route, conditionalRequest, context, execAware);
Date responseDate = getCurrentDate();
backendResponse.addHeader("Via", generateViaHeader(backendResponse));
if (backendResponse.getStatusLine().getStatusCode() != HttpStatus.SC_NOT_MODIFIED) {
- return handleBackendResponse(target, request, requestDate, responseDate, backendResponse);
+ return handleBackendResponse(
+ route, request, context, execAware,
+ requestDate, responseDate, backendResponse);
}
Header resultEtagHeader = backendResponse.getFirstHeader(HeaderConstants.ETAG);
if (resultEtagHeader == null) {
log.warn("304 response did not contain ETag");
- return callBackend(target, request, context);
+ return callBackend(route, request, context, execAware);
}
String resultEtag = resultEtagHeader.getValue();
Variant matchingVariant = variants.get(resultEtag);
if (matchingVariant == null) {
log.debug("304 response did not contain ETag matching one sent in If-None-Match");
- return callBackend(target, request, context);
+ return callBackend(route, request, context, execAware);
}
HttpCacheEntry matchedEntry = matchingVariant.getEntry();
if (revalidationResponseIsTooOld(backendResponse, matchedEntry)) {
EntityUtils.consume(backendResponse.getEntity());
- return retryRequestUnconditionally(target, request, context,
- matchedEntry);
+ return retryRequestUnconditionally(route, request, context, execAware, matchedEntry);
}
recordCacheUpdate(context);
- HttpCacheEntry responseEntry = getUpdatedVariantEntry(target,
- conditionalRequest, requestDate, responseDate, backendResponse,
- matchingVariant, matchedEntry);
+ HttpCacheEntry responseEntry = getUpdatedVariantEntry(
+ route.getTargetHost(), conditionalRequest, requestDate, responseDate,
+ backendResponse, matchingVariant, matchedEntry);
HttpResponse resp = responseGenerator.generateResponse(responseEntry);
- tryToUpdateVariantMap(target, request, matchingVariant);
+ tryToUpdateVariantMap(route.getTargetHost(), request, matchingVariant);
if (shouldSendNotModifiedResponse(request, responseEntry)) {
return responseGenerator.generateNotModifiedResponse(responseEntry);
@@ -810,18 +657,25 @@ public class CachingHttpClient implement
return resp;
}
- private HttpResponse retryRequestUnconditionally(HttpHost target,
- HttpRequestWrapper request, HttpContext context,
- HttpCacheEntry matchedEntry) throws IOException {
+ private HttpResponse retryRequestUnconditionally(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final HttpCacheEntry matchedEntry) throws IOException, HttpException {
HttpRequestWrapper unconditional = conditionalRequestBuilder
.buildUnconditionalRequest(request, matchedEntry);
- return callBackend(target, unconditional, context);
+ return callBackend(route, unconditional, context, execAware);
}
- private HttpCacheEntry getUpdatedVariantEntry(HttpHost target,
- HttpRequestWrapper conditionalRequest, Date requestDate,
- Date responseDate, HttpResponse backendResponse,
- Variant matchingVariant, HttpCacheEntry matchedEntry) {
+ private HttpCacheEntry getUpdatedVariantEntry(
+ final HttpHost target,
+ final HttpRequestWrapper conditionalRequest,
+ final Date requestDate,
+ final Date responseDate,
+ final HttpResponse backendResponse,
+ final Variant matchingVariant,
+ final HttpCacheEntry matchedEntry) {
HttpCacheEntry responseEntry = matchedEntry;
try {
responseEntry = responseCache.updateVariantCacheEntry(target, conditionalRequest,
@@ -832,8 +686,10 @@ public class CachingHttpClient implement
return responseEntry;
}
- private void tryToUpdateVariantMap(HttpHost target, HttpRequestWrapper request,
- Variant matchingVariant) {
+ private void tryToUpdateVariantMap(
+ final HttpHost target,
+ final HttpRequestWrapper request,
+ final Variant matchingVariant) {
try {
responseCache.reuseVariantEntryFor(target, request, matchingVariant);
} catch (IOException ioe) {
@@ -841,30 +697,33 @@ public class CachingHttpClient implement
}
}
- private boolean shouldSendNotModifiedResponse(HttpRequestWrapper request,
- HttpCacheEntry responseEntry) {
+ private boolean shouldSendNotModifiedResponse(
+ final HttpRequestWrapper request,
+ final HttpCacheEntry responseEntry) {
return (suitabilityChecker.isConditional(request)
&& suitabilityChecker.allConditionalsMatch(request, responseEntry, new Date()));
}
- HttpResponse revalidateCacheEntry(
- HttpHost target,
- HttpRequestWrapper request,
- HttpContext context,
- HttpCacheEntry cacheEntry) throws IOException, ProtocolException {
+ CloseableHttpResponse revalidateCacheEntry(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final HttpCacheEntry cacheEntry) throws IOException, HttpException {
HttpRequestWrapper conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(request, cacheEntry);
Date requestDate = getCurrentDate();
- HttpResponse backendResponse = backend.execute(target, conditionalRequest, context);
+ CloseableHttpResponse backendResponse = backend.execute(
+ route, conditionalRequest, context, execAware);
Date responseDate = getCurrentDate();
if (revalidationResponseIsTooOld(backendResponse, cacheEntry)) {
- EntityUtils.consume(backendResponse.getEntity());
- HttpRequest unconditional = conditionalRequestBuilder
+ backendResponse.close();
+ HttpRequestWrapper unconditional = conditionalRequestBuilder
.buildUnconditionalRequest(request, cacheEntry);
requestDate = getCurrentDate();
- backendResponse = backend.execute(target, unconditional, context);
+ backendResponse = backend.execute(route, unconditional, context, execAware);
responseDate = getCurrentDate();
}
@@ -876,27 +735,31 @@ public class CachingHttpClient implement
}
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
- HttpCacheEntry updatedEntry = responseCache.updateCacheEntry(target, request, cacheEntry,
+ HttpCacheEntry updatedEntry = responseCache.updateCacheEntry(
+ route.getTargetHost(), request, cacheEntry,
backendResponse, requestDate, responseDate);
if (suitabilityChecker.isConditional(request)
&& suitabilityChecker.allConditionalsMatch(request, updatedEntry, new Date())) {
- return responseGenerator.generateNotModifiedResponse(updatedEntry);
+ return Proxies.enhanceResponse(
+ responseGenerator.generateNotModifiedResponse(updatedEntry));
}
- return responseGenerator.generateResponse(updatedEntry);
+ return Proxies.enhanceResponse(responseGenerator.generateResponse(updatedEntry));
}
if (staleIfErrorAppliesTo(statusCode)
&& !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
&& validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
- final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry);
- cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
- HttpEntity errorBody = backendResponse.getEntity();
- if (errorBody != null) EntityUtils.consume(errorBody);
- return cachedResponse;
+ try {
+ HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry);
+ cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
+ return Proxies.enhanceResponse(cachedResponse);
+ } finally {
+ backendResponse.close();
+ }
}
-
- return handleBackendResponse(target, conditionalRequest, requestDate, responseDate,
- backendResponse);
+ return handleBackendResponse(
+ route, conditionalRequest, context, execAware,
+ requestDate, responseDate, backendResponse);
}
private boolean staleIfErrorAppliesTo(int statusCode) {
@@ -906,25 +769,29 @@ public class CachingHttpClient implement
|| statusCode == HttpStatus.SC_GATEWAY_TIMEOUT;
}
- HttpResponse handleBackendResponse(
- HttpHost target,
- HttpRequestWrapper request,
- Date requestDate,
- Date responseDate,
- HttpResponse backendResponse) throws IOException {
+ CloseableHttpResponse handleBackendResponse(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext context,
+ final HttpExecutionAware execAware,
+ final Date requestDate,
+ final Date responseDate,
+ final CloseableHttpResponse backendResponse) throws IOException {
log.trace("Handling Backend response");
responseCompliance.ensureProtocolCompliance(request, backendResponse);
+ HttpHost target = route.getTargetHost();
boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse);
responseCache.flushInvalidatedCacheEntriesFor(target, request, backendResponse);
- if (cacheable &&
- !alreadyHaveNewerCacheEntry(target, request, backendResponse)) {
+ if (cacheable && !alreadyHaveNewerCacheEntry(target, request, backendResponse)) {
try {
- return responseCache.cacheAndReturnResponse(target, request, backendResponse, requestDate,
- responseDate);
+ return Proxies.enhanceResponse(responseCache.cacheAndReturnResponse(
+ target, request, backendResponse, requestDate, responseDate));
} catch (IOException ioe) {
log.warn("Unable to store entries in cache", ioe);
+ } finally {
+ backendResponse.close();
}
}
if (!cacheable) {
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java?rev=1418743&r1=1418742&r2=1418743&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java Sat Dec 8 19:59:24 2012
@@ -29,10 +29,18 @@ package org.apache.http.impl.client.cach
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URI;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
@@ -109,7 +117,10 @@ import org.apache.http.util.VersionInfo;
* memcached} storage backends.</p>
* </p>
* @since 4.1
+ *
+ * @deprecated (4.3)
*/
+@Deprecated
@ThreadSafe // So long as the responseCache implementation is threadsafe
public class CachingHttpClient implements HttpClient {
@@ -960,4 +971,151 @@ public class CachingHttpClient implement
return false;
}
+ static class AsynchronousValidator {
+ private final CachingHttpClient cachingClient;
+ private final ExecutorService executor;
+ private final Set<String> queued;
+ private final CacheKeyGenerator cacheKeyGenerator;
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /**
+ * Create AsynchronousValidator which will make revalidation requests
+ * using the supplied {@link CachingHttpClient}, and
+ * a {@link ThreadPoolExecutor} generated according to the thread
+ * pool settings provided in the given {@link CacheConfig}.
+ * @param cachingClient used to execute asynchronous requests
+ * @param config specifies thread pool settings. See
+ * {@link CacheConfig#getAsynchronousWorkersMax()},
+ * {@link CacheConfig#getAsynchronousWorkersCore()},
+ * {@link CacheConfig#getAsynchronousWorkerIdleLifetimeSecs()},
+ * and {@link CacheConfig#getRevalidationQueueSize()}.
+ */
+ public AsynchronousValidator(CachingHttpClient cachingClient,
+ CacheConfig config) {
+ this(cachingClient,
+ new ThreadPoolExecutor(config.getAsynchronousWorkersCore(),
+ config.getAsynchronousWorkersMax(),
+ config.getAsynchronousWorkerIdleLifetimeSecs(),
+ TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(config.getRevalidationQueueSize()))
+ );
+ }
+
+ /**
+ * Create AsynchronousValidator which will make revalidation requests
+ * using the supplied {@link CachingHttpClient} and
+ * {@link ExecutorService}.
+ * @param cachingClient used to execute asynchronous requests
+ * @param executor used to manage a thread pool of revalidation workers
+ */
+ AsynchronousValidator(CachingHttpClient cachingClient,
+ ExecutorService executor) {
+ this.cachingClient = cachingClient;
+ this.executor = executor;
+ this.queued = new HashSet<String>();
+ this.cacheKeyGenerator = new CacheKeyGenerator();
+ }
+
+ /**
+ * Schedules an asynchronous revalidation
+ *
+ * @param target
+ * @param request
+ * @param context
+ * @param entry
+ */
+ public synchronized void revalidateCacheEntry(HttpHost target,
+ HttpRequestWrapper request, HttpContext context, HttpCacheEntry entry) {
+ // getVariantURI will fall back on getURI if no variants exist
+ String uri = cacheKeyGenerator.getVariantURI(target, request, entry);
+
+ if (!queued.contains(uri)) {
+ AsynchronousValidationRequest revalidationRequest =
+ new AsynchronousValidationRequest(this, cachingClient, target,
+ request, context, entry, uri);
+
+ try {
+ executor.execute(revalidationRequest);
+ queued.add(uri);
+ } catch (RejectedExecutionException ree) {
+ log.debug("Revalidation for [" + uri + "] not scheduled: " + ree);
+ }
+ }
+ }
+
+ /**
+ * Removes an identifier from the internal list of revalidation jobs in
+ * progress. This is meant to be called by
+ * {@link AsynchronousValidationRequest#run()} once the revalidation is
+ * complete, using the identifier passed in during constructions.
+ * @param identifier
+ */
+ synchronized void markComplete(String identifier) {
+ queued.remove(identifier);
+ }
+
+ Set<String> getScheduledIdentifiers() {
+ return Collections.unmodifiableSet(queued);
+ }
+
+ ExecutorService getExecutor() {
+ return executor;
+ }
+ }
+
+ static class AsynchronousValidationRequest implements Runnable {
+ private final AsynchronousValidator parent;
+ private final CachingHttpClient cachingClient;
+ private final HttpHost target;
+ private final HttpRequestWrapper request;
+ private final HttpContext context;
+ private final HttpCacheEntry cacheEntry;
+ private final String identifier;
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ /**
+ * Used internally by {@link AsynchronousValidator} to schedule a
+ * revalidation.
+ * @param cachingClient
+ * @param target
+ * @param request
+ * @param context
+ * @param cacheEntry
+ * @param bookKeeping
+ * @param identifier
+ */
+ AsynchronousValidationRequest(AsynchronousValidator parent,
+ CachingHttpClient cachingClient, HttpHost target,
+ HttpRequestWrapper request, HttpContext context,
+ HttpCacheEntry cacheEntry,
+ String identifier) {
+ this.parent = parent;
+ this.cachingClient = cachingClient;
+ this.target = target;
+ this.request = request;
+ this.context = context;
+ this.cacheEntry = cacheEntry;
+ this.identifier = identifier;
+ }
+
+ public void run() {
+ try {
+ cachingClient.revalidateCacheEntry(target, request, context, cacheEntry);
+ } catch (IOException ioe) {
+ log.debug("Asynchronous revalidation failed due to exception: " + ioe);
+ } catch (ProtocolException pe) {
+ log.error("ProtocolException thrown during asynchronous revalidation: " + pe);
+ } finally {
+ parent.markComplete(identifier);
+ }
+ }
+
+ String getIdentifier() {
+ return identifier;
+ }
+
+ }
+
}
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java?rev=1418743&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java Sat Dec 8 19:59:24 2012
@@ -0,0 +1,30 @@
+package org.apache.http.impl.client.cache;
+
+import java.lang.reflect.Proxy;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.util.Args;
+
+/**
+ * Proxies for HTTP message objects.
+ *
+ * @since 4.3
+ */
+@NotThreadSafe
+class Proxies {
+
+ public static CloseableHttpResponse enhanceResponse(final HttpResponse original) {
+ Args.notNull(original, "HTTP response");
+ if (original instanceof CloseableHttpResponse) {
+ return (CloseableHttpResponse) original;
+ } else {
+ return (CloseableHttpResponse) Proxy.newProxyInstance(
+ ResponseProxyHandler.class.getClassLoader(),
+ new Class<?>[] { CloseableHttpResponse.class },
+ new ResponseProxyHandler(original));
+ }
+ }
+
+}
\ No newline at end of file
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/Proxies.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java?rev=1418743&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java Sat Dec 8 19:59:24 2012
@@ -0,0 +1,89 @@
+/*
+ * ====================================================================
+ * 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.client.cache;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.util.EntityUtils;
+
+/**
+ * A proxy class that can enhance an arbitrary {@link HttpResponse} with
+ * {@link Closeable#close()} method.
+ *
+ * @since 4.3
+ */
+@NotThreadSafe
+class ResponseProxyHandler implements InvocationHandler {
+
+ private static final Method CLOSE_METHOD;
+
+ static {
+ try {
+ CLOSE_METHOD = Closeable.class.getMethod("close");
+ } catch (NoSuchMethodException ex) {
+ throw new Error(ex);
+ }
+ }
+
+ private final HttpResponse original;
+
+ ResponseProxyHandler(final HttpResponse original) {
+ super();
+ this.original = original;
+ }
+
+ public void close() throws IOException {
+ EntityUtils.consume(original.getEntity());
+ }
+
+ public Object invoke(
+ final Object proxy, final Method method, final Object[] args) throws Throwable {
+ if (method.equals(CLOSE_METHOD)) {
+ close();
+ return null;
+ } else {
+ try {
+ return method.invoke(this.original, args);
+ } catch (InvocationTargetException ex) {
+ Throwable cause = ex.getCause();
+ if (cause != null) {
+ throw cause;
+ } else {
+ throw ex;
+ }
+ }
+ }
+ }
+
+}
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java?rev=1418743&r1=1418742&r2=1418743&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java Sat Dec 8 19:59:24 2012
@@ -43,7 +43,6 @@ import org.apache.http.client.cache.Http
import org.apache.http.client.cache.HttpCacheStorage;
import org.apache.http.client.cache.HttpCacheUpdateCallback;
import org.apache.http.impl.client.cache.CacheConfig;
-import org.apache.http.impl.client.cache.CachingHttpClient;
/**
* <p>This class is a storage backend that uses an external <i>memcached</i>
@@ -62,13 +61,13 @@ import org.apache.http.impl.client.cache
* fails (see the <a href="http://dustin.github.com/java-memcached-client/apidocs/net/spy/memcached/KetamaConnectionFactory.html">
* KetamaConnectionFactory</a>).
* </p>
- *
+ *
* <p>Because memcached places limits on the size of its keys, we need to
* introduce a key hashing scheme to map the annotated URLs the higher-level
- * {@link CachingHttpClient} wants to use as keys onto ones that are suitable
+ * caching HTTP client wants to use as keys onto ones that are suitable
* for use with memcached. Please see {@link KeyHashingScheme} if you would
* like to use something other than the provided {@link SHA256KeyHashingScheme}.</p>
- *
+ *
* <p>Because this hashing scheme can potentially result in key collisions (though
* highly unlikely), we need to store the higher-level logical storage key along
* with the {@link HttpCacheEntry} so that we can re-check it on retrieval. There
@@ -87,7 +86,7 @@ import org.apache.http.impl.client.cache
public class MemcachedHttpCacheStorage implements HttpCacheStorage {
private static final Log log = LogFactory.getLog(MemcachedHttpCacheStorage.class);
-
+
private final MemcachedClientIF client;
private final KeyHashingScheme keyHashingScheme;
private final MemcachedCacheEntryFactory memcachedCacheEntryFactory;
@@ -158,7 +157,7 @@ public class MemcachedHttpCacheStorage i
this.memcachedCacheEntryFactory = memcachedCacheEntryFactory;
this.keyHashingScheme = keyHashingScheme;
}
-
+
public void putEntry(String url, HttpCacheEntry entry) throws IOException {
byte[] bytes = serializeEntry(url, entry);
String key = getCacheKey(url);
@@ -209,7 +208,7 @@ public class MemcachedHttpCacheStorage i
}
return mce;
}
-
+
public HttpCacheEntry getEntry(String url) throws IOException {
String key = getCacheKey(url);
if (key == null) return null;
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java?rev=1418743&r1=1418742&r2=1418743&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java Sat Dec 8 19:59:24 2012
@@ -27,15 +27,19 @@
package org.apache.http.impl.client.cache;
import java.util.HashMap;
+
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
-import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.client.execchain.ClientExecChain;
import org.apache.http.message.BasicHttpRequest;
-import org.apache.http.protocol.HttpContext;
import org.easymock.IExpectationSetters;
import org.easymock.classextension.EasyMock;
import org.junit.Before;
@@ -46,16 +50,17 @@ public abstract class AbstractProtocolTe
protected static final int MAX_ENTRIES = 100;
protected int entityLength = 128;
protected HttpHost host;
+ protected HttpRoute route;
protected HttpEntity body;
- protected HttpClient mockBackend;
+ protected ClientExecChain mockBackend;
protected HttpCache mockCache;
protected HttpRequestWrapper request;
- protected HttpResponse originResponse;
+ protected CloseableHttpResponse originResponse;
protected CacheConfig config;
- protected CachingHttpClient impl;
+ protected CachingExec impl;
protected HttpCache cache;
- public static HttpRequest eqRequest(HttpRequest in) {
+ public static HttpRequestWrapper eqRequest(HttpRequestWrapper in) {
EasyMock.reportMatcher(new RequestEquivalent(in));
return null;
}
@@ -64,20 +69,23 @@ public abstract class AbstractProtocolTe
public void setUp() {
host = new HttpHost("foo.example.com");
+ route = new HttpRoute(host);
+
body = HttpTestUtils.makeBody(entityLength);
request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1));
- originResponse = HttpTestUtils.make200Response();
+ originResponse = Proxies.enhanceResponse(HttpTestUtils.make200Response());
config = CacheConfig.custom()
.setMaxCacheEntries(MAX_ENTRIES)
.setMaxObjectSize(MAX_BYTES)
.build();
+
cache = new BasicHttpCache(config);
- mockBackend = EasyMock.createNiceMock(HttpClient.class);
+ mockBackend = EasyMock.createNiceMock(ClientExecChain.class);
mockCache = EasyMock.createNiceMock(HttpCache.class);
- impl = new CachingHttpClient(mockBackend, cache, config);
+ impl = new CachingExec(mockBackend, cache, config);
}
protected void replayMocks() {
@@ -90,17 +98,30 @@ public abstract class AbstractProtocolTe
EasyMock.verify(mockCache);
}
- protected IExpectationSetters<HttpResponse> backendExpectsAnyRequest() throws Exception {
- HttpResponse resp = mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock
- .isA(HttpRequest.class), (HttpContext) EasyMock.isNull());
+ protected IExpectationSetters<CloseableHttpResponse> backendExpectsAnyRequest() throws Exception {
+ CloseableHttpResponse resp = mockBackend.execute(
+ EasyMock.isA(HttpRoute.class),
+ EasyMock.isA(HttpRequestWrapper.class),
+ EasyMock.isA(HttpClientContext.class),
+ EasyMock.<HttpExecutionAware>isNull());
return EasyMock.expect(resp);
}
+ protected IExpectationSetters<CloseableHttpResponse> backendExpectsAnyRequestAndReturn(
+ HttpResponse reponse) throws Exception {
+ CloseableHttpResponse resp = mockBackend.execute(
+ EasyMock.isA(HttpRoute.class),
+ EasyMock.isA(HttpRequestWrapper.class),
+ EasyMock.isA(HttpClientContext.class),
+ EasyMock.<HttpExecutionAware>isNull());
+ return EasyMock.expect(resp).andReturn(Proxies.enhanceResponse(reponse));
+ }
+
protected void emptyMockCacheExpectsNoPuts() throws Exception {
- mockBackend = EasyMock.createNiceMock(HttpClient.class);
+ mockBackend = EasyMock.createNiceMock(ClientExecChain.class);
mockCache = EasyMock.createNiceMock(HttpCache.class);
- impl = new CachingHttpClient(mockBackend, mockCache, config);
+ impl = new CachingExec(mockBackend, mockCache, config);
EasyMock.expect(mockCache.getCacheEntry(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class)))
.andReturn(null).anyTimes();
@@ -126,7 +147,7 @@ public abstract class AbstractProtocolTe
.setMaxObjectSize(MAX_BYTES)
.setSharedCache(false)
.build();
- impl = new CachingHttpClient(mockBackend, cache, config);
+ impl = new CachingExec(mockBackend, cache, config);
}
public AbstractProtocolTest() {
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java?rev=1418743&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java Sat Dec 8 19:59:24 2012
@@ -0,0 +1,70 @@
+/*
+ * ====================================================================
+ *
+ * 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.client.cache;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpExecutionAware;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.client.execchain.ClientExecChain;
+import org.apache.http.message.BasicHttpResponse;
+
+public class DummyBackend implements ClientExecChain {
+
+ private HttpRequest request;
+ private HttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP",1,1), HttpStatus.SC_OK, "OK");
+ private int executions = 0;
+
+ public void setResponse(HttpResponse resp) {
+ response = resp;
+ }
+
+ public HttpRequest getCapturedRequest() {
+ return request;
+ }
+
+ public CloseableHttpResponse execute(
+ final HttpRoute route,
+ final HttpRequestWrapper request,
+ final HttpClientContext clientContext,
+ final HttpExecutionAware execAware) throws IOException, HttpException {
+ this.request = request;
+ executions++;
+ return Proxies.enhanceResponse(response);
+ }
+
+ public int getExecutions() {
+ return executions;
+ }
+}
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java
------------------------------------------------------------------------------
svn:mime-type = text/plain