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.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.Header;
|
||||
|
@ -50,6 +53,14 @@ import org.apache.http.message.BasicHttpResponse;
|
|||
|
||||
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 ResourceFactory resourceFactory;
|
||||
private final int maxObjectSizeBytes;
|
||||
|
@ -183,6 +194,7 @@ class BasicHttpCache implements HttpCache {
|
|||
return error;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
HttpCacheEntry doGetUpdatedParentEntry(
|
||||
final String requestId,
|
||||
final HttpCacheEntry existing,
|
||||
|
@ -194,16 +206,30 @@ class BasicHttpCache implements HttpCache {
|
|||
src = entry;
|
||||
}
|
||||
|
||||
Map<String,String> variantMap = new HashMap<String,String>(src.getVariantMap());
|
||||
variantMap.put(variantKey, variantCacheKey);
|
||||
Resource resource = resourceFactory.copy(requestId, src.getResource());
|
||||
return new HttpCacheEntry(
|
||||
src.getRequestDate(),
|
||||
src.getResponseDate(),
|
||||
src.getStatusLine(),
|
||||
src.getAllHeaders(),
|
||||
resource,
|
||||
variantMap);
|
||||
try {
|
||||
Map<String,String> variantMap = new HashMap<String,String>(src.getVariantMap());
|
||||
variantMap.put(variantKey, variantCacheKey);
|
||||
return new HttpCacheEntry(
|
||||
src.getRequestDate(),
|
||||
src.getResponseDate(),
|
||||
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,
|
||||
|
@ -267,7 +293,14 @@ class BasicHttpCache implements HttpCache {
|
|||
HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request));
|
||||
if (root == null) return null;
|
||||
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;
|
||||
return storage.getEntry(variantCacheKey);
|
||||
}
|
||||
|
@ -277,21 +310,37 @@ class BasicHttpCache implements HttpCache {
|
|||
cacheInvalidator.flushInvalidatedCacheEntries(host, request);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public Map<String, Variant> getVariantCacheEntriesWithEtags(HttpHost host, HttpRequest request)
|
||||
throws IOException {
|
||||
Map<String,Variant> variants = new HashMap<String,Variant>();
|
||||
HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request));
|
||||
if (root == null || !root.hasVariants()) return variants;
|
||||
for(Map.Entry<String, String> variant : root.getVariantMap().entrySet()) {
|
||||
String variantKey = variant.getKey();
|
||||
String variantCacheKey = variant.getValue();
|
||||
HttpCacheEntry entry = storage.getEntry(variantCacheKey);
|
||||
if (entry == null) continue;
|
||||
Header etagHeader = entry.getFirstHeader(HeaderConstants.ETAG);
|
||||
if (etagHeader == null) continue;
|
||||
variants.put(etagHeader.getValue(), new Variant(variantKey, variantCacheKey, entry));
|
||||
try {
|
||||
for(Map.Entry<String, String> variant : root.getVariantMap().entrySet()) {
|
||||
String variantKey = variant.getKey();
|
||||
String variantCacheKey = variant.getValue();
|
||||
addVariantWithEtag(variantKey, variantCacheKey, variants);
|
||||
}
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
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.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -79,6 +80,7 @@ class CacheInvalidator {
|
|||
* @param host The backend host we are talking to
|
||||
* @param req The HttpRequest to that host
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void flushInvalidatedCacheEntries(HttpHost host, HttpRequest req) {
|
||||
if (requestShouldNotBeCached(req)) {
|
||||
log.debug("Request should not be cached");
|
||||
|
@ -90,7 +92,15 @@ class CacheInvalidator {
|
|||
log.debug("parent entry: " + parent);
|
||||
|
||||
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(theUri);
|
||||
|
|
|
@ -45,9 +45,9 @@ import org.junit.BeforeClass;
|
|||
|
||||
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
|
||||
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