[prev in list] [next in list] [prev in thread] [next in thread]
List: httpcomponents-commits
Subject: [1/4] httpcomponents-client git commit: Redesign of CacheKeyGenerator and HttpCacheInvalidator APIs
From: olegk () apache ! org
Date: 2017-12-27 10:55:45
Message-ID: 73f4723f610c4946ae9959d1c277f396 () git ! apache ! org
[Download RAW message or body]
Repository: httpcomponents-client
Updated Branches:
refs/heads/master 6459d6882 -> 749b02ac0
Redesign of CacheKeyGenerator and HttpCacheInvalidator APIs
Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/6200a17c
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/6200a17c
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/6200a17c
Branch: refs/heads/master
Commit: 6200a17c0caa38d2af9b3f9ca43c5aba5e1a9226
Parents: 6459d68
Author: Oleg Kalnichevski <olegk@apache.org>
Authored: Mon Dec 11 15:41:01 2017 +0100
Committer: Oleg Kalnichevski <olegk@apache.org>
Committed: Tue Dec 26 18:09:08 2017 +0100
----------------------------------------------------------------------
.../http/cache/HttpCacheInvalidator.java | 40 +++-
.../http/impl/cache/AsynchronousValidator.java | 2 +-
.../client5/http/impl/cache/BasicHttpCache.java | 6 +-
.../http/impl/cache/CacheKeyGenerator.java | 10 +-
.../cache/CachingHttp2AsyncClientBuilder.java | 5 +-
.../cache/CachingHttpAsyncClientBuilder.java | 5 +-
.../impl/cache/CachingHttpClientBuilder.java | 5 +-
.../impl/cache/DefaultCacheInvalidator.java | 187 ++++++++++---------
.../http/impl/cache/HttpCacheSupport.java | 14 ++
.../http/impl/cache/TestCacheKeyGenerator.java | 4 +-
.../impl/cache/TestDefaultCacheInvalidator.java | 116 ++++++------
11 files changed, 221 insertions(+), 173 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheInvalidator.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheInvalidator.java
index 5412d7d..36fd2a1 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheInvalidator.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheInvalidator.java
@@ -26,33 +26,57 @@
*/
package org.apache.hc.client5.http.cache;
+import java.net.URI;
+
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.function.Resolver;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
/**
- * Given a particular HttpRequest, flush any cache entries that this request
- * would invalidate.
+ * Given a particular HTTP request / response pair, flush any cache entries
+ * that this exchange would invalidate.
*
* @since 4.3
*/
+@Internal
public interface HttpCacheInvalidator {
/**
* Remove cache entries from the cache that are no longer fresh or have been
* invalidated in some way.
*
- * @param host
- * The backend host we are talking to
- * @param req
- * The HttpRequest to that host
+ * @param host backend host
+ * @param request request message
+ * @param cacheKeyResolver cache key resolver used by cache storage
+ * @param cacheStorage internal cache storage
+ *
+ * @since 5.0
*/
- void flushInvalidatedCacheEntries(HttpHost host, HttpRequest req);
+ void flushInvalidatedCacheEntries(
+ HttpHost host,
+ HttpRequest request,
+ Resolver<URI, String> cacheKeyResolver,
+ HttpCacheStorage cacheStorage);
/**
* Flushes entries that were invalidated by the given response received for
* the given host/request pair.
+ *
+ * @param host backend host
+ * @param request request message
+ * @param response response message
+ * @param cacheKeyResolver cache key resolver used by cache storage
+ * @param cacheStorage internal cache storage
+ *
+ * @since 5.0
*/
- void flushInvalidatedCacheEntries(HttpHost host, HttpRequest request, \
HttpResponse response); + void flushInvalidatedCacheEntries(
+ HttpHost host,
+ HttpRequest request,
+ HttpResponse response,
+ Resolver<URI, String> cacheKeyResolver,
+ HttpCacheStorage cacheStorage);
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsynchronousValidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsynchronousValidator.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsynchronousValidator.java
index 6eea5d5..c17928a 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsynchronousValidator.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsynchronousValidator.java
@@ -76,7 +76,7 @@ class AsynchronousValidator implements Closeable {
AsynchronousValidator(final SchedulingStrategy schedulingStrategy) {
this.schedulingStrategy = schedulingStrategy;
this.queued = new HashSet<>();
- this.cacheKeyGenerator = new CacheKeyGenerator();
+ this.cacheKeyGenerator = CacheKeyGenerator.INSTANCE;
this.failureCache = new DefaultFailureCache();
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
index eb4f3d7..5078cce 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
@@ -71,7 +71,7 @@ class BasicHttpCache implements HttpCache {
final ResourceFactory resourceFactory,
final HttpCacheStorage storage,
final CacheKeyGenerator cacheKeyGenerator) {
- this(resourceFactory, storage, cacheKeyGenerator, new \
DefaultCacheInvalidator(cacheKeyGenerator, storage)); + this(resourceFactory, \
storage, cacheKeyGenerator, new DefaultCacheInvalidator()); }
public BasicHttpCache(final ResourceFactory resourceFactory, final \
HttpCacheStorage storage) { @@ -97,7 +97,7 @@ class BasicHttpCache implements \
HttpCache { @Override
public void flushInvalidatedCacheEntriesFor(final HttpHost host, final \
HttpRequest request, final HttpResponse response) { if \
(!StandardMethods.isSafe(request.getMethod())) {
- cacheInvalidator.flushInvalidatedCacheEntries(host, request, response);
+ cacheInvalidator.flushInvalidatedCacheEntries(host, request, response, \
cacheKeyGenerator, storage); }
}
@@ -224,7 +224,7 @@ class BasicHttpCache implements HttpCache {
@Override
public void flushInvalidatedCacheEntriesFor(final HttpHost host,
final HttpRequest request) throws ResourceIOException {
- cacheInvalidator.flushInvalidatedCacheEntries(host, request);
+ cacheInvalidator.flushInvalidatedCacheEntries(host, request, \
cacheKeyGenerator, storage); }
@Override
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheKeyGenerator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheKeyGenerator.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheKeyGenerator.java
index 3975e8d..a3eb5fe 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheKeyGenerator.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheKeyGenerator.java
@@ -40,6 +40,7 @@ import org.apache.hc.client5.http.cache.HeaderConstants;
import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.function.Resolver;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HeaderElement;
import org.apache.hc.core5.http.HttpHost;
@@ -50,7 +51,14 @@ import org.apache.hc.core5.http.message.MessageSupport;
* @since 4.1
*/
@Contract(threading = ThreadingBehavior.IMMUTABLE)
-class CacheKeyGenerator {
+public class CacheKeyGenerator implements Resolver<URI, String> {
+
+ public static final CacheKeyGenerator INSTANCE = new CacheKeyGenerator();
+
+ @Override
+ public String resolve(final URI uri) {
+ return generateKey(uri);
+ }
/**
* Computes a key for the given request {@link URI} that can be used as
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttp2AsyncClientBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttp2AsyncClientBuilder.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttp2AsyncClientBuilder.java
index b2e6d0d..faa1d16 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttp2AsyncClientBuilder.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttp2AsyncClientBuilder.java
@@ -130,12 +130,11 @@ public class CachingHttp2AsyncClientBuilder extends \
Http2AsyncClientBuilder { storageCopy = managedStorage;
}
}
- final CacheKeyGenerator uriExtractor = new CacheKeyGenerator();
final HttpCache httpCache = new BasicHttpCache(
resourceFactoryCopy,
storageCopy,
- uriExtractor,
- this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new \
DefaultCacheInvalidator(uriExtractor, storageCopy)); + \
CacheKeyGenerator.INSTANCE, + this.httpCacheInvalidator != null ? \
this.httpCacheInvalidator : new DefaultCacheInvalidator());
final AsyncCachingExec cachingExec = new AsyncCachingExec(httpCache, \
config);
execChainDefinition.addBefore(ChainElements.PROTOCOL.name(), cachingExec, \
ChainElements.CACHING.name());
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
index 4a92692..3e6deda 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
@@ -130,12 +130,11 @@ public class CachingHttpAsyncClientBuilder extends \
HttpAsyncClientBuilder { storageCopy = managedStorage;
}
}
- final CacheKeyGenerator uriExtractor = new CacheKeyGenerator();
final HttpCache httpCache = new BasicHttpCache(
resourceFactoryCopy,
storageCopy,
- uriExtractor,
- this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new \
DefaultCacheInvalidator(uriExtractor, storageCopy)); + \
CacheKeyGenerator.INSTANCE, + this.httpCacheInvalidator != null ? \
this.httpCacheInvalidator : new DefaultCacheInvalidator());
final AsyncCachingExec cachingExec = new AsyncCachingExec(httpCache, \
config);
execChainDefinition.addBefore(ChainElements.PROTOCOL.name(), cachingExec, \
ChainElements.CACHING.name());
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
index 4ae9025..9836479 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
@@ -130,12 +130,11 @@ public class CachingHttpClientBuilder extends \
HttpClientBuilder { storageCopy = managedStorage;
}
}
- final CacheKeyGenerator uriExtractor = new CacheKeyGenerator();
final HttpCache httpCache = new BasicHttpCache(
resourceFactoryCopy,
storageCopy,
- uriExtractor,
- this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new \
DefaultCacheInvalidator(uriExtractor, storageCopy)); + \
CacheKeyGenerator.INSTANCE, + this.httpCacheInvalidator != null ? \
this.httpCacheInvalidator : new DefaultCacheInvalidator());
final CachingExec cachingExec = new CachingExec(httpCache, config);
execChainDefinition.addBefore(ChainElements.PROTOCOL.name(), cachingExec, \
ChainElements.CACHING.name());
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
index 725540f..029928b 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
@@ -26,18 +26,19 @@
*/
package org.apache.hc.client5.http.impl.cache;
-import java.io.IOException;
import java.net.URI;
-import java.net.URISyntaxException;
import org.apache.hc.client5.http.cache.HeaderConstants;
import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.cache.HttpCacheInvalidator;
import org.apache.hc.client5.http.cache.HttpCacheStorage;
+import org.apache.hc.client5.http.cache.ResourceIOException;
import org.apache.hc.client5.http.utils.DateUtils;
import org.apache.hc.client5.http.utils.URIUtils;
import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.Internal;
import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.function.Resolver;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpHost;
@@ -47,41 +48,37 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
- * Given a particular HttpRequest, flush any cache entries that this request
- * would invalidate.
+ * Given a particular HTTP request / response pair, flush any cache entries
+ * that this exchange would invalidate.
*
* @since 4.1
*/
@Contract(threading = ThreadingBehavior.IMMUTABLE)
-class DefaultCacheInvalidator implements HttpCacheInvalidator {
+@Internal
+public class DefaultCacheInvalidator implements HttpCacheInvalidator {
- private final HttpCacheStorage storage;
- private final CacheKeyGenerator cacheKeyGenerator;
+ public static final DefaultCacheInvalidator INSTANCE = new \
DefaultCacheInvalidator();
private final Logger log = LogManager.getLogger(getClass());
- /**
- * Create a new {@link DefaultCacheInvalidator} for a given {@link HttpCache} \
and
- * {@link CacheKeyGenerator}.
- *
- * @param cacheKeyGenerator Provides identifiers for the keys to store cache \
entries
- * @param storage the cache to store items away in
- */
- public DefaultCacheInvalidator(
- final CacheKeyGenerator cacheKeyGenerator,
- final HttpCacheStorage storage) {
- this.cacheKeyGenerator = cacheKeyGenerator;
- this.storage = storage;
- }
-
- private static URI parse(final String uri) {
- if (uri == null) {
+ private HttpCacheEntry getEntry(final HttpCacheStorage storage, final String \
cacheKey) { + try {
+ return storage.getEntry(cacheKey);
+ } catch (final ResourceIOException ex) {
+ if (log.isWarnEnabled()) {
+ log.warn("Unable to get cache entry with key " + cacheKey, ex);
+ }
return null;
}
+ }
+
+ private void removeEntry(final HttpCacheStorage storage, final String cacheKey) \
{ try {
- return new URI(uri);
- } catch (final URISyntaxException ex) {
- return null;
+ storage.removeEntry(cacheKey);
+ } catch (final ResourceIOException ex) {
+ if (log.isWarnEnabled()) {
+ log.warn("Unable to flush cache entry with key " + cacheKey, ex);
+ }
}
}
@@ -90,40 +87,49 @@ class DefaultCacheInvalidator implements HttpCacheInvalidator {
* have been invalidated in some way.
*
* @param host The backend host we are talking to
- * @param req The HttpRequest to that host
+ * @param request The HttpRequest to that host
*/
@Override
- public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest \
req) {
- final String key = cacheKeyGenerator.generateKey(host, req);
- final HttpCacheEntry parent = getEntry(key);
+ public void flushInvalidatedCacheEntries(
+ final HttpHost host,
+ final HttpRequest request,
+ final Resolver<URI, String> cacheKeyResolver,
+ final HttpCacheStorage storage) {
+ final String s = HttpCacheSupport.getRequestUri(request, host);
+ final URI uri = HttpCacheSupport.normalizeQuetly(s);
+ final String cacheKey = uri != null ? cacheKeyResolver.resolve(uri) : s;
+ final HttpCacheEntry parent = getEntry(storage, cacheKey);
- if (requestShouldNotBeCached(req) || shouldInvalidateHeadCacheEntry(req, \
parent)) {
- if (log.isDebugEnabled()) {
- log.debug("Invalidating parent cache entry: " + parent);
- }
+ if (requestShouldNotBeCached(request) || \
shouldInvalidateHeadCacheEntry(request, parent)) { if (parent != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Invalidating parent cache entry with key " + \
cacheKey); + }
for (final String variantURI : parent.getVariantMap().values()) {
- flushEntry(variantURI);
+ removeEntry(storage, variantURI);
}
- flushEntry(key);
+ removeEntry(storage, cacheKey);
}
- final URI uri = parse(key);
- if (uri == null) {
- log.error("Couldn't transform request into valid URI");
- return;
- }
- final Header clHdr = req.getFirstHeader("Content-Location");
- if (clHdr != null) {
- final URI contentLocation = parse(clHdr.getValue());
- if (contentLocation != null) {
- if (!flushAbsoluteUriFromSameHost(uri, contentLocation)) {
- flushRelativeUriFromSameHost(uri, contentLocation);
+ if (uri != null) {
+ if (log.isWarnEnabled()) {
+ log.warn(s + " is not a valid URI");
+ }
+ final Header clHdr = request.getFirstHeader("Content-Location");
+ if (clHdr != null) {
+ final URI contentLocation = \
HttpCacheSupport.normalizeQuetly(clHdr.getValue()); + if \
(contentLocation != null) { + if \
(!flushAbsoluteUriFromSameHost(uri, contentLocation, cacheKeyResolver, storage)) { + \
flushRelativeUriFromSameHost(uri, contentLocation, cacheKeyResolver, storage); + \
} + }
+ }
+ final Header lHdr = request.getFirstHeader("Location");
+ if (lHdr != null) {
+ final URI location = \
HttpCacheSupport.normalizeQuetly(lHdr.getValue()); + if (location \
!= null) { + flushAbsoluteUriFromSameHost(uri, location, \
cacheKeyResolver, storage); }
}
- }
- final Header lHdr = req.getFirstHeader("Location");
- if (lHdr != null) {
- flushAbsoluteUriFromSameHost(uri, parse(lHdr.getValue()));
}
}
}
@@ -140,52 +146,42 @@ class DefaultCacheInvalidator implements HttpCacheInvalidator {
return parentCacheEntry != null && \
parentCacheEntry.getRequestMethod().equals(HeaderConstants.HEAD_METHOD); }
- private void flushEntry(final String uri) {
- try {
- storage.removeEntry(uri);
- } catch (final IOException ioe) {
- log.warn("unable to flush cache entry", ioe);
- }
- }
-
- private HttpCacheEntry getEntry(final String theUri) {
- try {
- return storage.getEntry(theUri);
- } catch (final IOException ioe) {
- log.warn("could not retrieve entry from storage", ioe);
- }
- return null;
- }
-
- protected void flushUriIfSameHost(final URI requestURI, final URI targetURI) {
- try {
- final URI canonicalTarget = HttpCacheSupport.normalize(targetURI);
- if (canonicalTarget.isAbsolute()
- && \
canonicalTarget.getAuthority().equalsIgnoreCase(requestURI.getAuthority())) \
{
- flushEntry(canonicalTarget.toString());
- }
- } catch (final URISyntaxException ignore) {
+ private void flushUriIfSameHost(
+ final URI requestURI,
+ final URI targetURI,
+ final Resolver<URI, String> cacheKeyResolver,
+ final HttpCacheStorage storage) {
+ if (targetURI.isAbsolute() && \
targetURI.getAuthority().equalsIgnoreCase(requestURI.getAuthority())) { + \
removeEntry(storage, cacheKeyResolver.resolve(targetURI)); }
}
- protected void flushRelativeUriFromSameHost(final URI requestUri, final URI uri) \
{ + private void flushRelativeUriFromSameHost(
+ final URI requestUri,
+ final URI uri,
+ final Resolver<URI, String> cacheKeyResolver,
+ final HttpCacheStorage storage) {
final URI resolvedUri = uri != null ? URIUtils.resolve(requestUri, uri) : \
null; if (resolvedUri != null) {
- flushUriIfSameHost(requestUri, resolvedUri);
+ flushUriIfSameHost(requestUri, resolvedUri, cacheKeyResolver, storage);
}
}
- protected boolean flushAbsoluteUriFromSameHost(final URI requestUri, final URI \
uri) { + private boolean flushAbsoluteUriFromSameHost(
+ final URI requestUri,
+ final URI uri,
+ final Resolver<URI, String> cacheKeyResolver,
+ final HttpCacheStorage storage) {
if (uri != null && uri.isAbsolute()) {
- flushUriIfSameHost(requestUri, uri);
+ flushUriIfSameHost(requestUri, uri, cacheKeyResolver, storage);
return true;
} else {
return false;
}
}
- protected boolean requestShouldNotBeCached(final HttpRequest req) {
+ private boolean requestShouldNotBeCached(final HttpRequest req) {
final String method = req.getMethod();
return notGetOrHeadRequest(method);
}
@@ -199,28 +195,39 @@ class DefaultCacheInvalidator implements HttpCacheInvalidator {
* received for the given host/request pair.
*/
@Override
- public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest \
request, final HttpResponse response) { + public void \
flushInvalidatedCacheEntries( + final HttpHost host,
+ final HttpRequest request,
+ final HttpResponse response,
+ final Resolver<URI, String> cacheKeyResolver,
+ final HttpCacheStorage storage) {
final int status = response.getCode();
if (status < 200 || status > 299) {
return;
}
- final URI uri = parse(cacheKeyGenerator.generateKey(host, request));
+ final String s = HttpCacheSupport.getRequestUri(request, host);
+ final URI uri = HttpCacheSupport.normalizeQuetly(s);
if (uri == null) {
return;
}
final URI contentLocation = getContentLocationURI(uri, response);
if (contentLocation != null) {
- flushLocationCacheEntry(uri, response, contentLocation);
+ flushLocationCacheEntry(uri, response, contentLocation, \
cacheKeyResolver, storage); }
final URI location = getLocationURI(uri, response);
if (location != null) {
- flushLocationCacheEntry(uri, response, location);
+ flushLocationCacheEntry(uri, response, location, cacheKeyResolver, \
storage); }
}
- private void flushLocationCacheEntry(final URI requestUri, final HttpResponse \
response, final URI location) {
- final String cacheKey = cacheKeyGenerator.generateKey(location);
- final HttpCacheEntry entry = getEntry(cacheKey);
+ private void flushLocationCacheEntry(
+ final URI requestUri,
+ final HttpResponse response,
+ final URI location,
+ final Resolver<URI, String> cacheKeyResolver,
+ final HttpCacheStorage storage) {
+ final String cacheKey = cacheKeyResolver.resolve(location);
+ final HttpCacheEntry entry = getEntry(storage, cacheKey);
if (entry == null) {
return;
}
@@ -235,7 +242,7 @@ class DefaultCacheInvalidator implements HttpCacheInvalidator {
return;
}
- flushUriIfSameHost(requestUri, location);
+ flushUriIfSameHost(requestUri, location, cacheKeyResolver, storage);
}
private static URI getLocationURI(final URI requestUri, final HttpResponse \
response, final String headerName) { @@ -243,7 +250,7 @@ class \
DefaultCacheInvalidator implements HttpCacheInvalidator { if (h == null) {
return null;
}
- final URI locationUri = parse(h.getValue());
+ final URI locationUri = HttpCacheSupport.normalizeQuetly(h.getValue());
if (locationUri == null) {
return requestUri;
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpCacheSupport.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpCacheSupport.java \
b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpCacheSupport.java
index 34f4ec4..5369a0b 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpCacheSupport.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpCacheSupport.java
@@ -120,4 +120,18 @@ public final class HttpCacheSupport {
return builder.build();
}
+ /**
+ * Lenient URI parser that normalizes valid {@link URI}s and returns {@code \
null} for malformed URIs. + */
+ public static URI normalizeQuetly(final String requestUri) {
+ if (requestUri == null) {
+ return null;
+ }
+ try {
+ return normalize(new URI(requestUri));
+ } catch (final URISyntaxException ex) {
+ return null;
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheKeyGenerator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheKeyGenerator.java \
b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheKeyGenerator.java
index f9f928a..0713e10 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheKeyGenerator.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheKeyGenerator.java
@@ -49,7 +49,7 @@ public class TestCacheKeyGenerator {
"/full_episodes");
private static final BasicHttpRequest REQUEST_ROOT = new BasicHttpRequest("GET", \
"/");
- CacheKeyGenerator extractor;
+ private CacheKeyGenerator extractor;
private HttpHost defaultHost;
private HttpCacheEntry mockEntry;
private HttpRequest mockRequest;
@@ -59,7 +59,7 @@ public class TestCacheKeyGenerator {
defaultHost = new HttpHost("foo.example.com");
mockEntry = mock(HttpCacheEntry.class);
mockRequest = mock(HttpRequest.class);
- extractor = new CacheKeyGenerator();
+ extractor = CacheKeyGenerator.INSTANCE;
}
@Test
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6200a17c/httpclient5 \
-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java \
b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java
index 4b1f6d8..5c18134 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java
@@ -26,7 +26,6 @@
*/
package org.apache.hc.client5.http.impl.cache;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -41,6 +40,7 @@ import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.cache.HttpCacheStorage;
import org.apache.hc.client5.http.cache.ResourceIOException;
import org.apache.hc.client5.http.utils.DateUtils;
+import org.apache.hc.core5.function.Resolver;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
@@ -51,14 +51,24 @@ import org.apache.hc.core5.http.message.BasicHttpRequest;
import org.apache.hc.core5.http.message.BasicHttpResponse;
import org.junit.Before;
import org.junit.Test;
-
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+@RunWith(MockitoJUnitRunner.class)
public class TestDefaultCacheInvalidator {
private DefaultCacheInvalidator impl;
- private HttpCacheStorage mockStorage;
private HttpHost host;
- private CacheKeyGenerator cacheKeyGenerator;
+ @Mock
private HttpCacheEntry mockEntry;
+ @Mock
+ private Resolver<URI, String> cacheKeyResolver;
+ @Mock
+ private HttpCacheStorage mockStorage;
private Date now;
private Date tenSecondsAgo;
@@ -68,12 +78,18 @@ public class TestDefaultCacheInvalidator {
now = new Date();
tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
- host = new HttpHost("foo.example.com");
- mockStorage = mock(HttpCacheStorage.class);
- cacheKeyGenerator = new CacheKeyGenerator();
- mockEntry = mock(HttpCacheEntry.class);
+ when(cacheKeyResolver.resolve(Mockito.<URI>any())).thenAnswer(new \
Answer<String>() { +
+ @Override
+ public String answer(final InvocationOnMock invocation) throws Throwable \
{ + final URI uri = invocation.getArgument(0);
+ return HttpCacheSupport.normalize(uri).toASCIIString();
+ }
- impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
+ });
+
+ host = new HttpHost("foo.example.com");
+ impl = new DefaultCacheInvalidator();
}
// Tests
@@ -86,7 +102,7 @@ public class TestDefaultCacheInvalidator {
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getVariantMap();
verify(mockStorage).getEntry(key);
@@ -107,7 +123,7 @@ public class TestDefaultCacheInvalidator {
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getVariantMap();
verify(mockStorage).getEntry(key);
@@ -129,12 +145,12 @@ public class TestDefaultCacheInvalidator {
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getVariantMap();
verify(mockStorage).getEntry(key);
verify(mockStorage).removeEntry(key);
- verify(mockStorage).removeEntry(cacheKeyGenerator.generateKey(new \
URI(contentLocation))); + \
verify(mockStorage).removeEntry(cacheKeyResolver.resolve(new URI(contentLocation))); \
}
@Test
@@ -151,7 +167,7 @@ public class TestDefaultCacheInvalidator {
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getVariantMap();
verify(mockStorage).getEntry(key);
@@ -173,7 +189,7 @@ public class TestDefaultCacheInvalidator {
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getVariantMap();
verify(mockStorage).getEntry(key);
@@ -183,7 +199,7 @@ public class TestDefaultCacheInvalidator {
@Test
public void testDoesNotInvalidateGETRequest() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET","/");
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry("http://foo.example.com:80/");
verifyNoMoreInteractions(mockStorage);
@@ -192,7 +208,7 @@ public class TestDefaultCacheInvalidator {
@Test
public void testDoesNotInvalidateHEADRequest() throws Exception {
final HttpRequest request = new BasicHttpRequest("HEAD","/");
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry("http://foo.example.com:80/");
verifyNoMoreInteractions(mockStorage);
@@ -200,7 +216,6 @@ public class TestDefaultCacheInvalidator {
@Test
public void testInvalidatesHEADCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() \
throws Exception {
- impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
final URI uri = new URI("http://foo.example.com:80/");
final String key = uri.toASCIIString();
final HttpRequest request = new BasicHttpRequest("GET", uri);
@@ -209,7 +224,7 @@ public class TestDefaultCacheInvalidator {
cacheEntryHasVariantMap(new HashMap<String, String>());
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getRequestMethod();
verify(mockEntry).getVariantMap();
@@ -219,7 +234,6 @@ public class TestDefaultCacheInvalidator {
@Test
public void testInvalidatesVariantHEADCacheEntriesIfSubsequentGETRequestsAreMadeToTheSameURI() \
throws Exception {
- impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
final URI uri = new URI("http://foo.example.com:80/");
final String key = uri.toASCIIString();
final HttpRequest request = new BasicHttpRequest("GET", uri);
@@ -231,7 +245,7 @@ public class TestDefaultCacheInvalidator {
cacheEntryHasVariantMap(variants);
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getRequestMethod();
verify(mockEntry).getVariantMap();
@@ -248,7 +262,7 @@ public class TestDefaultCacheInvalidator {
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verifyNoMoreInteractions(mockStorage);
@@ -256,14 +270,13 @@ public class TestDefaultCacheInvalidator {
@Test
public void testDoesNotInvalidateHEADCacheEntryIfSubsequentHEADRequestsAreMadeToTheSameURI() \
throws Exception {
- impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
final URI uri = new URI("http://foo.example.com:80/");
final String key = uri.toASCIIString();
final HttpRequest request = new BasicHttpRequest("HEAD", uri);
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verifyNoMoreInteractions(mockStorage);
@@ -271,7 +284,6 @@ public class TestDefaultCacheInvalidator {
@Test
public void testDoesNotInvalidateGETCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() \
throws Exception {
- impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
final URI uri = new URI("http://foo.example.com:80/");
final String key = uri.toASCIIString();
final HttpRequest request = new BasicHttpRequest("GET", uri);
@@ -279,7 +291,7 @@ public class TestDefaultCacheInvalidator {
cacheEntryisForMethod("GET");
cacheReturnsEntryForUri(key);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockEntry).getRequestMethod();
verify(mockStorage).getEntry(key);
@@ -291,7 +303,7 @@ public class TestDefaultCacheInvalidator {
final HttpRequest request = new BasicHttpRequest("GET","/");
request.setHeader("Cache-Control","no-cache");
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry("http://foo.example.com:80/");
verifyNoMoreInteractions(mockStorage);
@@ -302,7 +314,7 @@ public class TestDefaultCacheInvalidator {
final HttpRequest request = new BasicHttpRequest("GET","/");
request.setHeader("Pragma","no-cache");
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry("http://foo.example.com:80/");
verifyNoMoreInteractions(mockStorage);
@@ -319,7 +331,7 @@ public class TestDefaultCacheInvalidator {
cacheReturnsEntryForUri(key);
cacheEntryHasVariantMap(mapOfURIs);
- impl.flushInvalidatedCacheEntries(host, request);
+ impl.flushInvalidatedCacheEntries(host, request, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verify(mockEntry).getVariantMap();
@@ -328,24 +340,10 @@ public class TestDefaultCacheInvalidator {
}
@Test
- public void testCacheFlushException() throws Exception {
- final HttpRequest request = new BasicHttpRequest("POST","/");
- final URI uri = new URI("http://foo.example.com:80/");
- final String key = uri.toASCIIString();
-
- cacheReturnsExceptionForUri(key);
-
- impl.flushInvalidatedCacheEntries(host, request);
-
- verify(mockStorage).getEntry(key);
- verifyNoMoreInteractions(mockStorage);
- }
-
- @Test
public void doesNotFlushForResponsesWithoutContentLocation() throws Exception {
final HttpRequest request = new BasicHttpRequest("POST","/");
final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verifyNoMoreInteractions(mockStorage);
}
@@ -366,7 +364,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verify(mockStorage).removeEntry(key);
@@ -388,7 +386,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verify(mockStorage).removeEntry(key);
@@ -403,7 +401,7 @@ public class TestDefaultCacheInvalidator {
final String key = "http://foo.example.com:80/bar";
response.setHeader("Content-Location", key);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verifyNoMoreInteractions(mockStorage);
}
@@ -424,7 +422,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(cacheKey);
verify(mockStorage).removeEntry(cacheKey);
@@ -446,7 +444,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(cacheKey);
verify(mockStorage).removeEntry(cacheKey);
@@ -468,7 +466,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(cacheKey);
verifyNoMoreInteractions(mockStorage);
@@ -491,7 +489,7 @@ public class TestDefaultCacheInvalidator {
});
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verifyNoMoreInteractions(mockStorage);
@@ -513,7 +511,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verifyNoMoreInteractions(mockStorage);
@@ -530,7 +528,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(null);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verifyNoMoreInteractions(mockStorage);
@@ -552,7 +550,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verifyNoMoreInteractions(mockStorage);
@@ -573,7 +571,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verifyNoMoreInteractions(mockStorage);
@@ -595,7 +593,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verify(mockStorage).removeEntry(key);
@@ -617,7 +615,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verify(mockStorage).removeEntry(key);
@@ -640,7 +638,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verify(mockStorage).removeEntry(key);
@@ -663,7 +661,7 @@ public class TestDefaultCacheInvalidator {
when(mockStorage.getEntry(key)).thenReturn(entry);
- impl.flushInvalidatedCacheEntries(host, request, response);
+ impl.flushInvalidatedCacheEntries(host, request, response, cacheKeyResolver, \
mockStorage);
verify(mockStorage).getEntry(key);
verify(mockStorage).removeEntry(key);
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic