Author: lryan
Date: Wed May 21 12:21:13 2008
New Revision: 658818
URL: http://svn.apache.org/viewvc?rev=658818&view=rev
Log:
Add LRU caching of specs and message bundles
Move content rewriting into caching layer
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/SigningFetcher.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/AbstractHttpCache.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpCache.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.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=658818&r1=658817&r2=658818&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/conf/gadgets.properties (original)
+++ incubator/shindig/trunk/java/gadgets/conf/gadgets.properties Wed May 21
12:21:13 2008
@@ -9,3 +9,5 @@
locked-domain.embed-host=127.0.0.1:8080
content-rewrite.enabled=true
cache.capacity=10000
+gadget-spec.cache.capacity=0
+message-bundle.cache.capacity=0
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=658818&r1=658817&r2=658818&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 12:21:13 2008
@@ -18,6 +18,12 @@
*/
package org.apache.shindig.gadgets;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+
+import org.apache.shindig.common.cache.Cache;
+import org.apache.shindig.common.cache.LruCache;
import org.apache.shindig.gadgets.http.HttpFetcher;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
@@ -26,11 +32,9 @@
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.View;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-
import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Basic implementation of a gadget spec factory
@@ -38,10 +42,17 @@
@Singleton
public class BasicGadgetSpecFactory implements GadgetSpecFactory {
+ private static final Logger logger
+ = Logger.getLogger(BasicGadgetSpecFactory.class.getName());
+
private final HttpFetcher specFetcher;
+
private final ContentRewriter rewriter;
+
private final boolean enableRewrite;
+ private final Cache<URI, GadgetSpec> inMemorySpecCache;
+
public GadgetSpec getGadgetSpec(GadgetContext context)
throws GadgetException {
return getGadgetSpec(context.getUrl(), context.getIgnoreCache());
@@ -49,22 +60,41 @@
public GadgetSpec getGadgetSpec(URI gadgetUri, boolean ignoreCache)
throws GadgetException {
- HttpRequest request = HttpRequest.getRequest(
- gadgetUri, ignoreCache);
- HttpResponse response = specFetcher.fetch(request);
- if (response.getHttpStatusCode() != HttpResponse.SC_OK) {
- throw new GadgetException(
- GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT,
- "Unable to retrieve gadget xml. HTTP error " +
- response.getHttpStatusCode());
+ GadgetSpec spec;
+ synchronized (inMemorySpecCache) {
+ spec = inMemorySpecCache.getElement(gadgetUri);
}
- GadgetSpec spec
- = new GadgetSpec(gadgetUri, response.getResponseAsString());
- if (new ContentRewriterFeature(spec, enableRewrite).isRewriteEnabled()) {
- for (View v : spec.getViews().values()) {
- if (v.getType() == View.ContentType.HTML && rewriter != null) {
- v.setRewrittenContent(
- rewriter.rewrite(gadgetUri, v.getContent(), "text/html"));
+ if (ignoreCache || spec == null) {
+ try {
+ HttpRequest request = HttpRequest.getRequest(
+ gadgetUri, ignoreCache);
+ HttpResponse response = specFetcher.fetch(request);
+ if (response.getHttpStatusCode() != HttpResponse.SC_OK) {
+ throw new GadgetException(
+ GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT,
+ "Unable to retrieve gadget xml. HTTP error " +
+ response.getHttpStatusCode());
+ } else {
+ spec = new GadgetSpec(gadgetUri, response.getResponseAsString());
+ if (new ContentRewriterFeature(spec,
enableRewrite).isRewriteEnabled()) {
+ for (View v : spec.getViews().values()) {
+ if (v.getType() == View.ContentType.HTML && rewriter != null) {
+ v.setRewrittenContent(
+ rewriter.rewrite(gadgetUri, v.getContent(), "text/html"));
+ }
+ }
+ }
+ // Add the updated spec back to the cache
+ synchronized (inMemorySpecCache) {
+ inMemorySpecCache.addElement(gadgetUri, spec);
+ }
+ }
+ } catch (GadgetException ge) {
+ if (spec == null) {
+ throw ge;
+ } else {
+ logger.log(Level.WARNING,
+ "Gadget spec fetch failed for " + gadgetUri + " - using cached
", ge);
}
}
}
@@ -74,9 +104,11 @@
@Inject
public BasicGadgetSpecFactory(HttpFetcher specFetcher,
ContentRewriter rewriter,
- @Named("content-rewrite.enabled") boolean defaultEnableRewrite) {
+ @Named("content-rewrite.enabled")boolean defaultEnableRewrite,
+ @Named("gadget-spec.cache.capacity")int gadgetSpecCacheCapacity) {
this.specFetcher = specFetcher;
this.rewriter = rewriter;
this.enableRewrite = defaultEnableRewrite;
+ inMemorySpecCache = new LruCache<URI, GadgetSpec>(gadgetSpecCacheCapacity);
}
}
\ 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=658818&r1=658817&r2=658818&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 12:21:13 2008
@@ -18,22 +18,32 @@
*/
package org.apache.shindig.gadgets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+import org.apache.shindig.common.cache.Cache;
+import org.apache.shindig.common.cache.LruCache;
import org.apache.shindig.gadgets.http.HttpFetcher;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.spec.LocaleSpec;
import org.apache.shindig.gadgets.spec.MessageBundle;
-import com.google.inject.Inject;
-
import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Basic implementation of a message bundle factory
*/
public class BasicMessageBundleFactory implements MessageBundleFactory {
- private HttpFetcher bundleFetcher;
+ private static final Logger logger
+ = Logger.getLogger(BasicMessageBundleFactory.class.getName());
+
+ private final HttpFetcher bundleFetcher;
+
+ private final Cache<URI, MessageBundle> inMemoryBundleCache;
public MessageBundle getBundle(LocaleSpec localeSpec, GadgetContext context)
throws GadgetException {
@@ -42,22 +52,41 @@
public MessageBundle getBundle(URI bundleUrl, boolean ignoreCache)
throws GadgetException {
- HttpRequest request
- = HttpRequest.getRequest(bundleUrl, ignoreCache);
- HttpResponse response = bundleFetcher.fetch(request);
- if (response.getHttpStatusCode() != HttpResponse.SC_OK) {
- throw new GadgetException(
- GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT,
- "Unable to retrieve message bundle xml. HTTP error " +
- response.getHttpStatusCode());
+ MessageBundle bundle;
+ synchronized (inMemoryBundleCache) {
+ bundle = inMemoryBundleCache.getElement(bundleUrl);
+ }
+ if (ignoreCache || bundle == null) {
+ try {
+ HttpRequest request
+ = HttpRequest.getRequest(bundleUrl, ignoreCache);
+ HttpResponse response = bundleFetcher.fetch(request);
+ if (response.getHttpStatusCode() != HttpResponse.SC_OK) {
+ throw new GadgetException(
+ GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT,
+ "Unable to retrieve message bundle xml. HTTP error " +
+ response.getHttpStatusCode());
+ }
+ bundle = new MessageBundle(bundleUrl, response.getResponseAsString());
+ synchronized (inMemoryBundleCache) {
+ inMemoryBundleCache.addElement(bundleUrl, bundle);
+ }
+ } catch (GadgetException ge) {
+ if (bundle == null) {
+ throw ge;
+ } else {
+ logger.log(Level.WARNING,
+ "Msg bundle fetch failed for " + bundleUrl + " - using cached
", ge);
+ }
+ }
}
- MessageBundle bundle
- = new MessageBundle(bundleUrl, response.getResponseAsString());
return bundle;
}
@Inject
- public BasicMessageBundleFactory(HttpFetcher bundleFetcher) {
+ public BasicMessageBundleFactory(HttpFetcher bundleFetcher,
+ @Named("message-bundle.cache.capacity")int messageBundleCacheCapacity) {
this.bundleFetcher = bundleFetcher;
+ this.inMemoryBundleCache = new LruCache<URI,
MessageBundle>(messageBundleCacheCapacity);
}
}
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java?rev=658818&r1=658817&r2=658818&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
Wed May 21 12:21:13 2008
@@ -14,14 +14,6 @@
package org.apache.shindig.gadgets;
-import org.apache.shindig.common.SecurityToken;
-import org.apache.shindig.common.crypto.Crypto;
-import org.apache.shindig.common.util.TimeSource;
-import org.apache.shindig.gadgets.http.HttpCache;
-import org.apache.shindig.gadgets.http.HttpFetcher;
-import org.apache.shindig.gadgets.http.HttpResponse;
-import org.apache.shindig.gadgets.http.HttpRequest;
-
import net.oauth.OAuth;
import net.oauth.OAuth.Parameter;
import net.oauth.OAuthAccessor;
@@ -29,6 +21,14 @@
import net.oauth.OAuthMessage;
import net.oauth.signature.RSA_SHA1;
+import org.apache.shindig.common.SecurityToken;
+import org.apache.shindig.common.crypto.Crypto;
+import org.apache.shindig.common.util.TimeSource;
+import org.apache.shindig.gadgets.http.HttpCache;
+import org.apache.shindig.gadgets.http.HttpFetcher;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.http.HttpResponse;
+
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
@@ -161,9 +161,7 @@
result = nextFetcher.fetch(signedRequest);
// Try and cache the response
- cache.addResponse(cacheableRequest, result);
-
- return result;
+ return cache.addResponse(cacheableRequest, result);
} catch (GadgetException e) {
throw e;
} catch (Exception e) {
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/AbstractHttpCache.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/AbstractHttpCache.java?rev=658818&r1=658817&r2=658818&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/AbstractHttpCache.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/AbstractHttpCache.java
Wed May 21 12:21:13 2008
@@ -26,7 +26,8 @@
/**
* Base class for content caches. Defines cache expiration rules and
- * and restrictions on allowed content.
+ * and restrictions on allowed content. Also enforces rewriting
+ * on cacheable content.
*
* TODO: Move cache checking code into HttpUtil
*/
@@ -34,7 +35,8 @@
public final HttpResponse getResponse(HttpRequest request) {
if (canCacheRequest(request)) {
- return getResponse(request.getUri());
+ HttpResponse response = getResponse(request.getUri());
+ return checkRewrite(request, response);
}
return null;
}
@@ -46,17 +48,23 @@
protected abstract HttpResponse getResponseImpl(URI uri);
- public void addResponse(HttpRequest request, HttpResponse response) {
+ public HttpResponse addResponse(HttpRequest request, HttpResponse response) {
if (canCacheRequest(request)) {
+ // !!! Note that we only rewrite cacheable content. Move this call above
the if
+ // to rewrite all content that passes through the cache regardless of
cacheability
+ rewrite(request, response);
addResponse(request.getUri(), response);
+ return checkRewrite(request, response);
}
+ return response;
}
- public void addResponse(URI uri, HttpResponse response) {
+ public HttpResponse addResponse(URI uri, HttpResponse response) {
+ if (uri == null || response == null) return response;
response = checkResponse(response);
- if (uri == null || response == null) return;
// Clone the URI to prevent outside references from preventing collection
addResponseImpl(URI.create(uri.toString()), response);
+ return response;
}
protected abstract void addResponseImpl(URI uri, HttpResponse response);
@@ -164,6 +172,49 @@
}
/**
+ * Add rewritten content to the response if its not there and
+ * we can add it. Re-cache if we created rewritten content.
+ * Return the appropriately re-written version if requested
+ */
+ protected HttpResponse checkRewrite(HttpRequest request, HttpResponse
response) {
+ if (response == null) return null;
+
+ // Perform a rewrite and store the content back to the cache if the
+ // content is actually rewritten
+ if (rewrite(request, response)) {
+ addResponseImpl(request.getUri(), response);
+ }
+
+ // Return the rewritten version if requested
+ if (request.getOptions() != null &&
+ !request.getOptions().ignoreCache &&
+ request.getOptions().rewriter != null &&
+ response.getRewritten() != null &&
+ response.getRewritten().getResponseAsBytes().length > 0) {
+ return response.getRewritten();
+ }
+ return response;
+ }
+
+ /**
+ * Rewrite the content
+ * @return true if rewritten content was generated
+ */
+ protected boolean rewrite(HttpRequest request, HttpResponse response) {
+ if (response == null) return false;
+ // TODO - Make this sensitive to custom rewriting rules
+ if (response.getRewritten() == null &&
+ request.getOptions() != null &&
+ request.getOptions().rewriter != null) {
+ response.setRewritten(request.getOptions().rewriter.rewrite(request,
response));
+ if (response.getRewritten() != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Default TTL for an entry in the cache that does not have any
* cache controlling headers
* @return default TTL for cache entries
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java?rev=658818&r1=658817&r2=658818&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/BasicHttpFetcher.java
Wed May 21 12:21:13 2008
@@ -137,13 +137,7 @@
/** [EMAIL PROTECTED] */
public HttpResponse fetch(HttpRequest request) {
HttpResponse response = cache.getResponse(request);
- // TODO - Make this sensitive to custom rewriting rules
if (response != null) {
- if (request.getOptions().rewriter != null &&
- response.getRewritten() != null &&
- response.getRewritten().getResponseAsBytes().length > 0) {
- return response.getRewritten();
- }
return response;
}
try {
@@ -160,13 +154,7 @@
fetcher.getOutputStream());
}
response = makeResponse(fetcher);
- if (request.getOptions().rewriter != null) {
- // TODO - Make this sensitive to different rewriting rules
- response.setRewritten(
- request.getOptions().rewriter.rewrite(request, response));
- }
- cache.addResponse(request, response);
- return response;
+ return cache.addResponse(request, response);
} catch (IOException e) {
if (e instanceof FileNotFoundException) {
return HttpResponse.NOT_FOUND;
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpCache.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpCache.java?rev=658818&r1=658817&r2=658818&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpCache.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpCache.java
Wed May 21 12:21:13 2008
@@ -28,9 +28,9 @@
public HttpResponse getResponse(HttpRequest request);
- public void addResponse(URI uri, HttpResponse response);
+ public HttpResponse addResponse(URI uri, HttpResponse response);
- public void addResponse(HttpRequest request, HttpResponse response);
+ public HttpResponse addResponse(HttpRequest request, HttpResponse response);
public HttpResponse removeResponse(URI uri);
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=658818&r1=658817&r2=658818&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 12:21:13 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);
+ new BasicGadgetSpecFactory(fetcher, new NoOpContentRewriter(), true, 0);
public final MessageBundleFactory bundleFactory =
- new BasicMessageBundleFactory(fetcher);
+ new BasicMessageBundleFactory(fetcher, 0);
public GadgetFeatureRegistry registry;
public ContainerConfig containerConfig;
public final Executor executor = new Executor() {