Author: etnu
Date: Sat Oct 18 11:38:25 2008
New Revision: 705904

URL: http://svn.apache.org/viewvc?rev=705904&view=rev
Log:
Added negative caching to BasicGadgetSpecFactory to prevent re-parsing / 
re-fetching of gadgets in a known error state. This saves a substantial amount 
of CPU time over the current implementation, which re-parses on every render 
even when caching is turned on.


Modified:
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetSpecFactory.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicGadgetSpecFactoryTest.java

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=705904&r1=705903&r2=705904&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
 Sat Oct 18 11:38:25 2008
@@ -40,7 +40,8 @@
 public class BasicGadgetSpecFactory implements GadgetSpecFactory {
   static final String RAW_GADGETSPEC_XML_PARAM_NAME = "rawxml";
   static final Uri RAW_GADGET_URI = Uri.parse("http://localhost/raw.xml";);
-
+  static final String ERROR_SPEC = "<Module><ModulePrefs 
title='Error'/><Content/></Module>";
+  static final String ERROR_KEY = "parse.exception";
   static final Logger logger = 
Logger.getLogger(BasicGadgetSpecFactory.class.getName());
 
   private final HttpFetcher fetcher;
@@ -48,7 +49,7 @@
   private final long minTtl;
   private final long maxTtl;
 
-   @Inject
+  @Inject
   public BasicGadgetSpecFactory(HttpFetcher fetcher,
                                 CacheProvider cacheProvider,
                                 @Named("shindig.gadget-spec.cache.capacity") 
int capacity,
@@ -89,15 +90,25 @@
       try {
         return fetchObjectAndCache(uri, ignoreCache);
       } catch (GadgetException e) {
-        // Failed to re-fetch raw object. Use cached object if it exists.
-        if (cached.obj == null) {
-          throw e;
+        // Enforce negative caching.
+        GadgetSpec spec;
+        if (cached.obj != null) {
+          spec = cached.obj;
         } else {
-          logger.info("GadgetSpec fetch failed for " + uri + " -  using 
cached.");
+          // We create this dummy spec to avoid the cost of re-parsing when a 
remote site is out.
+          spec = new GadgetSpec(uri, ERROR_SPEC);
+          spec.setAttribute(ERROR_KEY, e);
+          cached.obj = spec;
         }
+        logger.info("GadgetSpec fetch failed for " + uri + " - using cached 
for " + minTtl + " ms");
+        ttlCache.addElementWithTtl(uri, spec, minTtl);
       }
     }
 
+    GadgetException exception = (GadgetException) 
cached.obj.getAttribute(ERROR_KEY);
+    if (exception != null) {
+      throw exception;
+    }
     return cached.obj;
   }
 

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicGadgetSpecFactoryTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicGadgetSpecFactoryTest.java?rev=705904&r1=705903&r2=705904&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicGadgetSpecFactoryTest.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicGadgetSpecFactoryTest.java
 Sat Oct 18 11:38:25 2008
@@ -21,6 +21,7 @@
 import static org.easymock.EasyMock.expect;
 import static org.easymock.classextension.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 import org.apache.shindig.common.cache.CacheProvider;
 import org.apache.shindig.common.cache.DefaultCacheProvider;
@@ -103,7 +104,7 @@
   private final CacheProvider cacheProvider = new DefaultCacheProvider();
 
   private final BasicGadgetSpecFactory specFactory
-      = new BasicGadgetSpecFactory(fetcher, cacheProvider, 5, -1000, 1000);
+      = new BasicGadgetSpecFactory(fetcher, cacheProvider, 5, 1000, 1000);
 
   @Test
   public void specFetched() throws Exception {
@@ -220,6 +221,45 @@
   }
 
   @Test(expected = GadgetException.class)
+  public void badFetchServesCached() throws Exception {
+    HttpRequest firstRequest = new HttpRequest(SPEC_URL).setIgnoreCache(false);
+    expect(fetcher.fetch(firstRequest)).andReturn(new 
HttpResponse(LOCAL_SPEC_XML)).once();
+    HttpRequest secondRequest = new HttpRequest(SPEC_URL).setIgnoreCache(true);
+    
expect(fetcher.fetch(secondRequest)).andReturn(HttpResponse.error()).once();
+    replay(fetcher);
+
+    GadgetSpec original = specFactory.getGadgetSpec(SPEC_URL.toJavaUri(), 
false);
+    GadgetSpec cached = specFactory.getGadgetSpec(SPEC_URL.toJavaUri(), true);
+
+    assertEquals(original.getUrl(), cached.getUrl());
+    assertEquals(original.getChecksum(), cached.getChecksum());
+  }
+
+  @Test(expected = GadgetException.class)
+  public void malformedGadgetSpecThrows() throws Exception {
+    HttpRequest request = new HttpRequest(SPEC_URL).setIgnoreCache(true);
+    expect(fetcher.fetch(request)).andReturn(new HttpResponse("malformed 
junk"));
+    replay(fetcher);
+
+    specFactory.getGadgetSpec(SPEC_URL.toJavaUri(), true);
+  }
+
+  @Test(expected = GadgetException.class)
+  public void malformedGadgetSpecIsCachedAndThrows() throws Exception {
+    HttpRequest request = new HttpRequest(SPEC_URL).setIgnoreCache(false);
+    expect(fetcher.fetch(request)).andReturn(new HttpResponse("malformed 
junk")).once();
+    replay(fetcher);
+
+    try {
+      specFactory.getGadgetSpec(SPEC_URL.toJavaUri(), false);
+      fail("No exception thrown on bad parse");
+    } catch (GadgetException e) {
+      // Expected.
+    }
+    specFactory.getGadgetSpec(SPEC_URL.toJavaUri(), false);
+  }
+
+  @Test(expected = GadgetException.class)
   public void throwingFetcherRethrows() throws Exception {
     HttpRequest request = new HttpRequest(SPEC_URL).setIgnoreCache(true);
     expect(fetcher.fetch(request)).andThrow(


Reply via email to