Refactor ETag cache API

This commit is contained in:
Reinhard Pointner 2016-04-25 14:31:33 +08:00
parent 724e55485d
commit 5a2e9d3730
4 changed files with 42 additions and 15 deletions

View File

@ -45,9 +45,19 @@ public class Cache {
}
private final net.sf.ehcache.Cache cache;
private final CacheType cacheType;
public Cache(net.sf.ehcache.Cache cache) {
public Cache(net.sf.ehcache.Cache cache, CacheType cacheType) {
this.cache = cache;
this.cacheType = cacheType;
}
public String getName() {
return cache.getName();
}
public CacheType getCacheType() {
return cacheType;
}
public Object get(Object key) {
@ -123,15 +133,15 @@ public class Cache {
}
public <V> TypedCache<V> typed(Function<Object, V> read, Function<V, Object> write) {
return new TypedCache<V>(cache, read, write);
return new TypedCache<V>(cache, cacheType, read, write);
}
public <V> TypedCache<V> cast(Class<V> cls) {
return new TypedCache<V>(cache, it -> cls.cast(it), it -> it);
return new TypedCache<V>(cache, cacheType, it -> cls.cast(it), it -> it);
}
public <V> TypedCache<List<V>> castList(Class<V> cls) {
return new TypedCache<List<V>>(cache, it -> it == null ? null : stream((Object[]) it).map(cls::cast).collect(toList()), it -> it == null ? null : it.toArray());
return new TypedCache<List<V>>(cache, cacheType, it -> it == null ? null : stream((Object[]) it).map(cls::cast).collect(toList()), it -> it == null ? null : it.toArray());
}
@SuppressWarnings("unchecked")
@ -140,8 +150,8 @@ public class Cache {
private final Function<Object, V> read;
private final Function<V, Object> write;
public TypedCache(net.sf.ehcache.Cache cache, Function<Object, V> read, Function<V, Object> write) {
super(cache);
public TypedCache(net.sf.ehcache.Cache cache, CacheType cacheType, Function<Object, V> read, Function<V, Object> write) {
super(cache, cacheType);
this.read = read;
this.write = write;
}

View File

@ -42,7 +42,7 @@ public class CacheManager {
if (!manager.cacheExists(name)) {
manager.addCache(new net.sf.ehcache.Cache(type.getConfiguration(name)));
}
return new Cache(manager.getCache(name));
return new Cache(manager.getCache(name), type);
}
public synchronized void clearAll() {

View File

@ -15,6 +15,7 @@ import java.util.concurrent.Callable;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.w3c.dom.Document;
@ -189,21 +190,41 @@ public class CachedResource<K, R> implements Resource<R> {
};
}
public static Fetch fetchIfNoneMatch(Transform<URL, ?> key, Cache cache) {
// create cache with the same config
Cache etagStorage = Cache.getCache(cache.getName() + "_etag", cache.getCacheType());
// make sure value cache contains key, otherwise ignore previously stored etag
return fetchIfNoneMatch(url -> {
try {
return cache.get(key.transform(url)) == null ? null : etagStorage.get(key.transform(url));
} catch (Exception e) {
throw new RuntimeException(e);
}
}, (url, etag) -> {
try {
etagStorage.put(key.transform(url), etag);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
public static Fetch fetchIfNoneMatch(Function<URL, Object> etagRetrieve, BiConsumer<URL, String> etagStore) {
return (url, lastModified) -> {
Object etagValue = etagRetrieve.apply(url);
debug.fine(WebRequest.log(url, lastModified, etagValue));
try {
return WebRequest.fetch(url, etagValue == null ? lastModified : 0, etagValue, null, storeETag(url, etagStore));
return WebRequest.fetch(url, etagValue == null ? lastModified : 0, etagValue, null, storeETag(url, etagStore, etag -> !etag.equals(etagValue)));
} catch (FileNotFoundException e) {
return fileNotFound(url, e);
}
};
}
private static Consumer<Map<String, List<String>>> storeETag(URL url, BiConsumer<URL, String> etagStore) {
private static Consumer<Map<String, List<String>>> storeETag(URL url, BiConsumer<URL, String> etagStore, Predicate<String> etagFilter) {
return (responseHeaders) -> {
WebRequest.getETag(responseHeaders).ifPresent(etag -> {
WebRequest.getETag(responseHeaders).filter(etagFilter).ifPresent(etag -> {
debug.finest(format("Store ETag: %s", etag));
etagStore.accept(url, etag);
});

View File

@ -33,7 +33,6 @@ import javax.swing.Icon;
import net.filebot.Cache;
import net.filebot.CacheType;
import net.filebot.CachedResource.Fetch;
import net.filebot.Language;
import net.filebot.ResourceManager;
import net.filebot.web.TMDbClient.MovieInfo.MovieProperty;
@ -297,11 +296,8 @@ public class TMDbClient implements MovieIdentificationService, ArtworkProvider {
String key = parameters.isEmpty() ? resource : resource + '?' + encodeParameters(parameters, true);
String cacheName = locale.getLanguage().isEmpty() ? getName() : getName() + "_" + locale;
Cache etagStorage = Cache.getCache(cacheName + "_etag", CacheType.Monthly);
Cache cache = Cache.getCache(cacheName, CacheType.Monthly);
Fetch fetchIfNoneMatch = fetchIfNoneMatch(url -> cache.get(key) == null ? null : etagStorage.get(key), (url, etag) -> etagStorage.put(key, etag));
Object json = cache.json(key, s -> getResource(s, locale)).fetch(withPermit(fetchIfNoneMatch, r -> limit.acquirePermit())).expire(Cache.ONE_WEEK).get();
Object json = cache.json(key, k -> getResource(k, locale)).fetch(withPermit(fetchIfNoneMatch(url -> key, cache), r -> limit.acquirePermit())).expire(Cache.ONE_WEEK).get();
if (asMap(json).isEmpty()) {
throw new FileNotFoundException(String.format("Resource is empty: %s => %s", json, getResource(key, locale)));