Author: lryan
Date: Wed May 21 16:00:01 2008
New Revision: 658918
URL: http://svn.apache.org/viewvc?rev=658918&view=rev
Log:
Make message bundle and spec caching respect http expiration with a min TTL
Modified:
incubator/shindig/trunk/java/gadgets/conf/gadgets.properties
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetSpecFactory.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicMessageBundleFactory.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpUtil.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
Modified: incubator/shindig/trunk/java/gadgets/conf/gadgets.properties
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/conf/gadgets.properties?rev=658918&r1=658917&r2=658918&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/conf/gadgets.properties (original)
+++ incubator/shindig/trunk/java/gadgets/conf/gadgets.properties Wed May 21
16:00:01 2008
@@ -11,3 +11,5 @@
cache.capacity=10000
gadget-spec.cache.capacity=0
message-bundle.cache.capacity=0
+gadget-spec.cache.minTTL=300000
+message-bundle.cache.minTTL=300000
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetSpecFactory.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetSpecFactory.java?rev=658918&r1=658917&r2=658918&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetSpecFactory.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetSpecFactory.java
Wed May 21 16:00:01 2008
@@ -51,7 +51,10 @@
private final boolean enableRewrite;
- private final Cache<URI, GadgetSpec> inMemorySpecCache;
+ private final long specMinTTL;
+
+ // A cache of GadgetSpecs with expirations
+ private final Cache<URI, SpecTimeoutPair> inMemorySpecCache;
public GadgetSpec getGadgetSpec(GadgetContext context)
throws GadgetException {
@@ -60,11 +63,16 @@
public GadgetSpec getGadgetSpec(URI gadgetUri, boolean ignoreCache)
throws GadgetException {
- GadgetSpec spec;
+ GadgetSpec spec = null;
+ long expiration = -1;
synchronized (inMemorySpecCache) {
- spec = inMemorySpecCache.getElement(gadgetUri);
+ SpecTimeoutPair gadgetSpecEntry =
inMemorySpecCache.getElement(gadgetUri);
+ if (gadgetSpecEntry != null) {
+ spec = gadgetSpecEntry.spec;
+ expiration = gadgetSpecEntry.timeout;
+ }
}
- if (ignoreCache || spec == null) {
+ if (ignoreCache || spec == null || expiration <
System.currentTimeMillis()) {
try {
HttpRequest request = HttpRequest.getRequest(
gadgetUri, ignoreCache);
@@ -84,9 +92,11 @@
}
}
}
- // Add the updated spec back to the cache
+ // Add the updated spec back to the cache and force the min TTL
+ expiration = Math
+ .max(response.getCacheExpiration(), System.currentTimeMillis() +
specMinTTL);
synchronized (inMemorySpecCache) {
- inMemorySpecCache.addElement(gadgetUri, spec);
+ inMemorySpecCache.addElement(gadgetUri, new SpecTimeoutPair(spec,
expiration));
}
}
} catch (GadgetException ge) {
@@ -105,10 +115,23 @@
public BasicGadgetSpecFactory(HttpFetcher specFetcher,
ContentRewriter rewriter,
@Named("content-rewrite.enabled")boolean defaultEnableRewrite,
- @Named("gadget-spec.cache.capacity")int gadgetSpecCacheCapacity) {
+ @Named("gadget-spec.cache.capacity")int gadgetSpecCacheCapacity,
+ @Named("gadget-spec.cache.minTTL")long minTTL) {
this.specFetcher = specFetcher;
this.rewriter = rewriter;
this.enableRewrite = defaultEnableRewrite;
- inMemorySpecCache = new LruCache<URI, GadgetSpec>(gadgetSpecCacheCapacity);
+ this.inMemorySpecCache = new LruCache<URI, SpecTimeoutPair>(
+ gadgetSpecCacheCapacity);
+ this.specMinTTL = minTTL;
+ }
+
+ private static class SpecTimeoutPair {
+ private GadgetSpec spec;
+ private long timeout;
+
+ private SpecTimeoutPair(GadgetSpec spec, long timeout) {
+ this.spec = spec;
+ this.timeout = timeout;
+ }
}
}
\ No newline at end of file
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicMessageBundleFactory.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicMessageBundleFactory.java?rev=658918&r1=658917&r2=658918&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicMessageBundleFactory.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicMessageBundleFactory.java
Wed May 21 16:00:01 2008
@@ -43,7 +43,9 @@
private final HttpFetcher bundleFetcher;
- private final Cache<URI, MessageBundle> inMemoryBundleCache;
+ private final Cache<URI, BundleTimeoutPair> inMemoryBundleCache;
+
+ private final long bundleMinTTL;
public MessageBundle getBundle(LocaleSpec localeSpec, GadgetContext context)
throws GadgetException {
@@ -52,11 +54,16 @@
public MessageBundle getBundle(URI bundleUrl, boolean ignoreCache)
throws GadgetException {
- MessageBundle bundle;
+ MessageBundle bundle = null;
+ long expiration = -1;
synchronized (inMemoryBundleCache) {
- bundle = inMemoryBundleCache.getElement(bundleUrl);
+ BundleTimeoutPair entry = inMemoryBundleCache.getElement(bundleUrl);
+ if (entry != null) {
+ bundle = entry.bundle;
+ expiration = entry.timeout;
+ }
}
- if (ignoreCache || bundle == null) {
+ if (ignoreCache || bundle == null || expiration <
System.currentTimeMillis()) {
try {
HttpRequest request
= HttpRequest.getRequest(bundleUrl, ignoreCache);
@@ -68,8 +75,12 @@
response.getHttpStatusCode());
}
bundle = new MessageBundle(bundleUrl, response.getResponseAsString());
+
+ // Add the updated bundle back to the cache and force the min TTL
+ expiration = Math
+ .max(response.getCacheExpiration(), System.currentTimeMillis() +
bundleMinTTL);
synchronized (inMemoryBundleCache) {
- inMemoryBundleCache.addElement(bundleUrl, bundle);
+ inMemoryBundleCache.addElement(bundleUrl, new
BundleTimeoutPair(bundle, expiration));
}
} catch (GadgetException ge) {
if (bundle == null) {
@@ -85,8 +96,21 @@
@Inject
public BasicMessageBundleFactory(HttpFetcher bundleFetcher,
- @Named("message-bundle.cache.capacity")int messageBundleCacheCapacity) {
+ @Named("message-bundle.cache.capacity")int messageBundleCacheCapacity,
+ @Named("message-bundle.cache.minTTL")long minTTL) {
this.bundleFetcher = bundleFetcher;
- this.inMemoryBundleCache = new LruCache<URI,
MessageBundle>(messageBundleCacheCapacity);
+ this.inMemoryBundleCache =
+ new LruCache<URI, BundleTimeoutPair>(messageBundleCacheCapacity);
+ this.bundleMinTTL = minTTL;
+ }
+
+ private static class BundleTimeoutPair {
+ private MessageBundle bundle;
+ private long timeout;
+
+ private BundleTimeoutPair(MessageBundle bundle, long timeout) {
+ this.bundle = bundle;
+ this.timeout = timeout;
+ }
}
}
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java?rev=658918&r1=658917&r2=658918&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpResponse.java
Wed May 21 16:00:01 2008
@@ -17,12 +17,15 @@
*/
package org.apache.shindig.gadgets.http;
+import org.apache.shindig.gadgets.servlet.HttpUtil;
+
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -241,4 +244,83 @@
public void setRewritten(HttpResponse rewritten) {
this.rewritten = rewritten;
}
+
+ /**
+ * @return consolidated cache expiration time or -1
+ */
+ public long getCacheExpiration() {
+ if (isStrictNoCache()) return -1;
+ long maxAgeExpiration = getCacheControlMaxAge() +
System.currentTimeMillis();
+ long expiration = getExpiration();
+ if (expiration == -1) {
+ return maxAgeExpiration;
+ }
+ return expiration;
+ }
+
+ /**
+ * @return the expiration time from the Expires header or -1 if not set
+ */
+ public long getExpiration() {
+ String expires = getHeader("Expires");
+ if (expires != null) {
+ Date expiresDate = HttpUtil.parseDate(expires);
+ if (expiresDate != null) {
+ return expiresDate.getTime();
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * @return max-age value or -1 if invalid or not set
+ */
+ public long getCacheControlMaxAge() {
+ String cacheControl = getHeader("Cache-Control");
+ if (cacheControl != null) {
+ String[] directives = cacheControl.split(",");
+ for (String directive : directives) {
+ directive = directive.trim();
+ if (directive.startsWith("max-age")) {
+ String[] parts = directive.split("=");
+ if (parts.length == 2) {
+ try {
+ return Long.parseLong(parts[1]) * 1000;
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * @return true if a strict no-cache header is set in Cache-Control or Pragma
+ */
+ public boolean isStrictNoCache() {
+ String cacheControl = getHeader("Cache-Control");
+ if (cacheControl != null) {
+ String[] directives = cacheControl.split(",");
+ for (String directive : directives) {
+ directive = directive.trim();
+ if (directive.equalsIgnoreCase("no-cache")
+ || directive.equalsIgnoreCase("no-store")
+ || directive.equalsIgnoreCase("private")) {
+ return true;
+ }
+ }
+ }
+
+ List<String> pragmas = getHeaders("Pragma");
+ if (pragmas != null) {
+ for (String pragma : pragmas) {
+ if ("no-cache".equalsIgnoreCase(pragma)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpUtil.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpUtil.java?rev=658918&r1=658917&r2=658918&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpUtil.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpUtil.java
Wed May 21 16:00:01 2008
@@ -23,7 +23,6 @@
import org.apache.shindig.gadgets.GadgetContext;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.View;
-
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
Modified:
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java?rev=658918&r1=658917&r2=658918&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
Wed May 21 16:00:01 2008
@@ -40,9 +40,9 @@
public final HttpFetcher fetcher = mock(HttpFetcher.class);
public final GadgetBlacklist blacklist = mock(GadgetBlacklist.class);
public final GadgetSpecFactory specFactory =
- new BasicGadgetSpecFactory(fetcher, new NoOpContentRewriter(), true, 0);
+ new BasicGadgetSpecFactory(fetcher, new NoOpContentRewriter(), true, 0,
0L);
public final MessageBundleFactory bundleFactory =
- new BasicMessageBundleFactory(fetcher, 0);
+ new BasicMessageBundleFactory(fetcher, 0, 0L);
public GadgetFeatureRegistry registry;
public ContainerConfig containerConfig;
public final Executor executor = new Executor() {
Modified:
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java?rev=658918&r1=658917&r2=658918&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpResponseTest.java
Wed May 21 16:00:01 2008
@@ -17,10 +17,10 @@
*/
package org.apache.shindig.gadgets.http;
-import org.apache.shindig.common.util.InputStreamConsumer;
-
import junit.framework.TestCase;
+import org.apache.shindig.common.util.InputStreamConsumer;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
@@ -90,4 +90,32 @@
byte[] out = InputStreamConsumer.readToByteArray(response.getResponse());
assertTrue(Arrays.equals(data, out));
}
+
+ public void testStrictCacheControlNoCache() throws Exception {
+ addHeader("Cache-Control", "no-cache");
+ HttpResponse response = new HttpResponse(200, new byte[0], headers);
+ assertTrue(response.isStrictNoCache());
+ }
+
+ public void testStrictPragmaNoCache() throws Exception {
+ addHeader("Pragma", "no-cache");
+ HttpResponse response = new HttpResponse(200, new byte[0], headers);
+ assertTrue(response.isStrictNoCache());
+ }
+
+ public void testStrictPragmaJunk() throws Exception {
+ addHeader("Pragma", "junk");
+ HttpResponse response = new HttpResponse(200, new byte[0], headers);
+ assertFalse(response.isStrictNoCache());
+ }
+
+ /*
+ There seems to be some issue with the date parsing in joda?
+ public void testExpires() throws Exception {
+ long time = System.currentTimeMillis() + 10000L;
+ addHeader("Expires", HttpUtil.formatDate(new Date(time)));
+ HttpResponse response = new HttpResponse(200, new byte[0], headers);
+ assertEquals(response.getExpiration(), time);
+ }
+ */
}