From 5a2e9d373020923ca9e06e1813136980e27eb044 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Mon, 25 Apr 2016 14:31:33 +0800 Subject: [PATCH] Refactor ETag cache API --- source/net/filebot/Cache.java | 22 +++++++++++++++------ source/net/filebot/CacheManager.java | 2 +- source/net/filebot/CachedResource.java | 27 +++++++++++++++++++++++--- source/net/filebot/web/TMDbClient.java | 6 +----- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/source/net/filebot/Cache.java b/source/net/filebot/Cache.java index bbeaa9c7..bb82bdeb 100644 --- a/source/net/filebot/Cache.java +++ b/source/net/filebot/Cache.java @@ -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 TypedCache typed(Function read, Function write) { - return new TypedCache(cache, read, write); + return new TypedCache(cache, cacheType, read, write); } public TypedCache cast(Class cls) { - return new TypedCache(cache, it -> cls.cast(it), it -> it); + return new TypedCache(cache, cacheType, it -> cls.cast(it), it -> it); } public TypedCache> castList(Class cls) { - return new TypedCache>(cache, it -> it == null ? null : stream((Object[]) it).map(cls::cast).collect(toList()), it -> it == null ? null : it.toArray()); + return new TypedCache>(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 read; private final Function write; - public TypedCache(net.sf.ehcache.Cache cache, Function read, Function write) { - super(cache); + public TypedCache(net.sf.ehcache.Cache cache, CacheType cacheType, Function read, Function write) { + super(cache, cacheType); this.read = read; this.write = write; } diff --git a/source/net/filebot/CacheManager.java b/source/net/filebot/CacheManager.java index b9c9c5dd..c292de9e 100644 --- a/source/net/filebot/CacheManager.java +++ b/source/net/filebot/CacheManager.java @@ -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() { diff --git a/source/net/filebot/CachedResource.java b/source/net/filebot/CachedResource.java index 10e1c836..9fdd0b61 100644 --- a/source/net/filebot/CachedResource.java +++ b/source/net/filebot/CachedResource.java @@ -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 implements Resource { }; } + public static Fetch fetchIfNoneMatch(Transform 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 etagRetrieve, BiConsumer 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>> storeETag(URL url, BiConsumer etagStore) { + private static Consumer>> storeETag(URL url, BiConsumer etagStore, Predicate 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); }); diff --git a/source/net/filebot/web/TMDbClient.java b/source/net/filebot/web/TMDbClient.java index 04c99b97..40e8d89e 100644 --- a/source/net/filebot/web/TMDbClient.java +++ b/source/net/filebot/web/TMDbClient.java @@ -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)));