On the off chance someone wrote a custom serializer for use with the
4.1-beta version of HttpCacheEntry, we want to make sure things still work properly. The current implementation of HttpCacheEntry already throws an UnsupportedOperationException if you try to get at the variant map but the old set-based data structure is there; now we handle this exception, log a warning, and then use the old structure. This is a bit less efficient but still demonstrably works (I added a unit test to the Ehcache suite, where you can submit a custom serializer, that shows that the implementation still conforms to all the MUST/MUST NOTs). git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1057745 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e95a80b7a2
commit
3c0bc58a30
|
@ -29,7 +29,10 @@ package org.apache.http.impl.client.cache;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.http.Header;
|
import org.apache.http.Header;
|
||||||
|
@ -50,6 +53,14 @@ import org.apache.http.message.BasicHttpResponse;
|
||||||
|
|
||||||
class BasicHttpCache implements HttpCache {
|
class BasicHttpCache implements HttpCache {
|
||||||
|
|
||||||
|
static final String DEPRECATED_VARIANT_SET_MSG =
|
||||||
|
"It looks like you have a custom HttpCacheEntrySerializer " +
|
||||||
|
"that was written against the 4.1-beta API and is using the " +
|
||||||
|
"old (and deprecated) variant tracking mechanism of a Set " +
|
||||||
|
"instead of a Map. Everything is still working, just not as " +
|
||||||
|
"efficiently as possible. Please update your serializer" +
|
||||||
|
"appropriately to use the non-deprecated API for HttpCacheEntry.";
|
||||||
|
|
||||||
private final CacheKeyGenerator uriExtractor;
|
private final CacheKeyGenerator uriExtractor;
|
||||||
private final ResourceFactory resourceFactory;
|
private final ResourceFactory resourceFactory;
|
||||||
private final int maxObjectSizeBytes;
|
private final int maxObjectSizeBytes;
|
||||||
|
@ -183,6 +194,7 @@ class BasicHttpCache implements HttpCache {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
HttpCacheEntry doGetUpdatedParentEntry(
|
HttpCacheEntry doGetUpdatedParentEntry(
|
||||||
final String requestId,
|
final String requestId,
|
||||||
final HttpCacheEntry existing,
|
final HttpCacheEntry existing,
|
||||||
|
@ -194,16 +206,30 @@ class BasicHttpCache implements HttpCache {
|
||||||
src = entry;
|
src = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String,String> variantMap = new HashMap<String,String>(src.getVariantMap());
|
|
||||||
variantMap.put(variantKey, variantCacheKey);
|
|
||||||
Resource resource = resourceFactory.copy(requestId, src.getResource());
|
Resource resource = resourceFactory.copy(requestId, src.getResource());
|
||||||
return new HttpCacheEntry(
|
try {
|
||||||
src.getRequestDate(),
|
Map<String,String> variantMap = new HashMap<String,String>(src.getVariantMap());
|
||||||
src.getResponseDate(),
|
variantMap.put(variantKey, variantCacheKey);
|
||||||
src.getStatusLine(),
|
return new HttpCacheEntry(
|
||||||
src.getAllHeaders(),
|
src.getRequestDate(),
|
||||||
resource,
|
src.getResponseDate(),
|
||||||
variantMap);
|
src.getStatusLine(),
|
||||||
|
src.getAllHeaders(),
|
||||||
|
resource,
|
||||||
|
variantMap);
|
||||||
|
} catch (UnsupportedOperationException uoe) {
|
||||||
|
// TODO: to be removed once HttpCacheEntry#getVariantURIs is removed
|
||||||
|
log.warn(DEPRECATED_VARIANT_SET_MSG);
|
||||||
|
Set<String> variantURIs = new HashSet<String>(src.getVariantURIs());
|
||||||
|
variantURIs.add(variantCacheKey);
|
||||||
|
return new HttpCacheEntry(
|
||||||
|
src.getRequestDate(),
|
||||||
|
src.getResponseDate(),
|
||||||
|
src.getStatusLine(),
|
||||||
|
src.getAllHeaders(),
|
||||||
|
resource,
|
||||||
|
variantURIs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpCacheEntry updateCacheEntry(HttpHost target, HttpRequest request,
|
public HttpCacheEntry updateCacheEntry(HttpHost target, HttpRequest request,
|
||||||
|
@ -267,7 +293,14 @@ class BasicHttpCache implements HttpCache {
|
||||||
HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request));
|
HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request));
|
||||||
if (root == null) return null;
|
if (root == null) return null;
|
||||||
if (!root.hasVariants()) return root;
|
if (!root.hasVariants()) return root;
|
||||||
String variantCacheKey = root.getVariantMap().get(uriExtractor.getVariantKey(request, root));
|
String variantCacheKey = null;
|
||||||
|
try {
|
||||||
|
variantCacheKey = root.getVariantMap().get(uriExtractor.getVariantKey(request, root));
|
||||||
|
} catch (UnsupportedOperationException uoe) {
|
||||||
|
// TODO: to be removed once HttpCacheEntry#getVariantURIs is removed
|
||||||
|
log.warn(DEPRECATED_VARIANT_SET_MSG);
|
||||||
|
variantCacheKey = uriExtractor.getVariantURI(host, request, root);
|
||||||
|
}
|
||||||
if (variantCacheKey == null) return null;
|
if (variantCacheKey == null) return null;
|
||||||
return storage.getEntry(variantCacheKey);
|
return storage.getEntry(variantCacheKey);
|
||||||
}
|
}
|
||||||
|
@ -277,21 +310,37 @@ class BasicHttpCache implements HttpCache {
|
||||||
cacheInvalidator.flushInvalidatedCacheEntries(host, request);
|
cacheInvalidator.flushInvalidatedCacheEntries(host, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public Map<String, Variant> getVariantCacheEntriesWithEtags(HttpHost host, HttpRequest request)
|
public Map<String, Variant> getVariantCacheEntriesWithEtags(HttpHost host, HttpRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Map<String,Variant> variants = new HashMap<String,Variant>();
|
Map<String,Variant> variants = new HashMap<String,Variant>();
|
||||||
HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request));
|
HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request));
|
||||||
if (root == null || !root.hasVariants()) return variants;
|
if (root == null || !root.hasVariants()) return variants;
|
||||||
for(Map.Entry<String, String> variant : root.getVariantMap().entrySet()) {
|
try {
|
||||||
String variantKey = variant.getKey();
|
for(Map.Entry<String, String> variant : root.getVariantMap().entrySet()) {
|
||||||
String variantCacheKey = variant.getValue();
|
String variantKey = variant.getKey();
|
||||||
HttpCacheEntry entry = storage.getEntry(variantCacheKey);
|
String variantCacheKey = variant.getValue();
|
||||||
if (entry == null) continue;
|
addVariantWithEtag(variantKey, variantCacheKey, variants);
|
||||||
Header etagHeader = entry.getFirstHeader(HeaderConstants.ETAG);
|
}
|
||||||
if (etagHeader == null) continue;
|
} catch (UnsupportedOperationException uoe) {
|
||||||
variants.put(etagHeader.getValue(), new Variant(variantKey, variantCacheKey, entry));
|
// TODO: to be removed once HttpCacheEntry#getVariantURIs is removed
|
||||||
|
log.warn(DEPRECATED_VARIANT_SET_MSG);
|
||||||
|
for(String variantCacheKey : root.getVariantURIs()) {
|
||||||
|
String variantKey = uriExtractor.getVariantKey(request, root);
|
||||||
|
addVariantWithEtag(variantKey, variantCacheKey, variants);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return variants;
|
return variants;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addVariantWithEtag(String variantKey,
|
||||||
|
String variantCacheKey, Map<String, Variant> variants)
|
||||||
|
throws IOException {
|
||||||
|
HttpCacheEntry entry = storage.getEntry(variantCacheKey);
|
||||||
|
if (entry == null) return;
|
||||||
|
Header etagHeader = entry.getFirstHeader(HeaderConstants.ETAG);
|
||||||
|
if (etagHeader == null) return;
|
||||||
|
variants.put(etagHeader.getValue(), new Variant(variantKey, variantCacheKey, entry));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -29,6 +29,7 @@ package org.apache.http.impl.client.cache;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -79,6 +80,7 @@ class CacheInvalidator {
|
||||||
* @param host The backend host we are talking to
|
* @param host The backend host we are talking to
|
||||||
* @param req The HttpRequest to that host
|
* @param req The HttpRequest to that host
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void flushInvalidatedCacheEntries(HttpHost host, HttpRequest req) {
|
public void flushInvalidatedCacheEntries(HttpHost host, HttpRequest req) {
|
||||||
if (requestShouldNotBeCached(req)) {
|
if (requestShouldNotBeCached(req)) {
|
||||||
log.debug("Request should not be cached");
|
log.debug("Request should not be cached");
|
||||||
|
@ -90,7 +92,15 @@ class CacheInvalidator {
|
||||||
log.debug("parent entry: " + parent);
|
log.debug("parent entry: " + parent);
|
||||||
|
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
for (String variantURI : parent.getVariantMap().values()) {
|
Collection<String> variantURIs = null;
|
||||||
|
try {
|
||||||
|
variantURIs = parent.getVariantMap().values();
|
||||||
|
} catch (UnsupportedOperationException uoe) {
|
||||||
|
// TODO: to be removed once HttpCacheEntry#getVariantURIs is removed
|
||||||
|
log.warn(BasicHttpCache.DEPRECATED_VARIANT_SET_MSG);
|
||||||
|
variantURIs = parent.getVariantURIs();
|
||||||
|
}
|
||||||
|
for (String variantURI : variantURIs) {
|
||||||
flushEntry(variantURI);
|
flushEntry(variantURI);
|
||||||
}
|
}
|
||||||
flushEntry(theUri);
|
flushEntry(theUri);
|
||||||
|
|
|
@ -45,9 +45,9 @@ import org.junit.BeforeClass;
|
||||||
|
|
||||||
public class TestEhcacheProtocolRequirements extends TestProtocolRequirements{
|
public class TestEhcacheProtocolRequirements extends TestProtocolRequirements{
|
||||||
|
|
||||||
private final String TEST_EHCACHE_NAME = "TestEhcacheProtocolRequirements-cache";
|
protected final String TEST_EHCACHE_NAME = "TestEhcacheProtocolRequirements-cache";
|
||||||
|
|
||||||
private static CacheManager CACHE_MANAGER;
|
protected static CacheManager CACHE_MANAGER;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUpGlobal() {
|
public static void setUpGlobal() {
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package org.apache.http.impl.client.cache.ehcache;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.http.Header;
|
||||||
|
import org.apache.http.StatusLine;
|
||||||
|
import org.apache.http.client.cache.HttpCacheEntry;
|
||||||
|
import org.apache.http.client.cache.HttpCacheStorage;
|
||||||
|
import org.apache.http.client.cache.HttpCacheEntrySerializer;
|
||||||
|
import org.apache.http.client.cache.Resource;
|
||||||
|
import org.apache.http.impl.client.cache.CachingHttpClient;
|
||||||
|
import org.apache.http.impl.client.cache.HeapResourceFactory;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
public class TestProtocolRequirementsWithDeprecatedSerializer
|
||||||
|
extends TestEhcacheProtocolRequirements {
|
||||||
|
|
||||||
|
private static class OldSerializer implements HttpCacheEntrySerializer {
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void writeTo(HttpCacheEntry entry, OutputStream os)
|
||||||
|
throws IOException {
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(os);
|
||||||
|
oos.writeObject(entry.getRequestDate());
|
||||||
|
oos.writeObject(entry.getResponseDate());
|
||||||
|
oos.writeObject(entry.getStatusLine());
|
||||||
|
oos.writeObject(entry.getAllHeaders());
|
||||||
|
oos.writeObject(entry.getResource());
|
||||||
|
oos.writeObject(entry.getVariantURIs());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||||
|
public HttpCacheEntry readFrom(InputStream is) throws IOException {
|
||||||
|
ObjectInputStream ois = new ObjectInputStream(is);
|
||||||
|
try {
|
||||||
|
Date requestDate = (Date)ois.readObject();
|
||||||
|
Date responseDate = (Date)ois.readObject();
|
||||||
|
StatusLine statusLine = (StatusLine)ois.readObject();
|
||||||
|
Header[] responseHeaders = (Header[])ois.readObject();
|
||||||
|
Resource resource = (Resource)ois.readObject();
|
||||||
|
Set<String> variants = (Set<String>)ois.readObject();
|
||||||
|
return new HttpCacheEntry(requestDate, responseDate, statusLine,
|
||||||
|
responseHeaders, resource, variants);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} finally {
|
||||||
|
ois.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
super.setUp();
|
||||||
|
HttpCacheStorage storage = new EhcacheHttpCacheStorage(CACHE_MANAGER.getCache(TEST_EHCACHE_NAME), params,
|
||||||
|
new OldSerializer());
|
||||||
|
impl = new CachingHttpClient(mockBackend, new HeapResourceFactory(), storage, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue