You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by et...@apache.org on 2008/09/24 18:37:43 UTC

svn commit: r698638 - in /incubator/shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/ main/java/org/apache/shindig/gadgets/preload/ main/java/org/apache/shindig/gadgets/render/ test/java/org/apache/shindig/gadgets/render/

Author: etnu
Date: Wed Sep 24 09:37:42 2008
New Revision: 698638

URL: http://svn.apache.org/viewvc?rev=698638&view=rev
Log:
Added Preloads to RenderingContentRewriter.

This rewriter now covers everything in GadgetRenderingTask, so we can swap them. Big patch coming...


Added:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/NullPreloads.java
Modified:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java?rev=698638&r1=698637&r2=698638&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/Gadget.java Wed Sep 24 09:37:42 2008
@@ -28,13 +28,12 @@
 import org.apache.shindig.gadgets.spec.Preload;
 import org.apache.shindig.gadgets.spec.View;
 
-import edu.emory.mathcs.backport.java.util.Collections;
+import com.google.common.collect.Maps;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Future;
 
@@ -49,25 +48,27 @@
   private MutableContent mutableContent;
 
   @Deprecated
-  private Collection<JsLibrary> jsLibraries = Collections.emptyList();
+  private Collection<JsLibrary> jsLibraries;
 
   @Deprecated
-  private final Map<Preload, Future<HttpResponse>> preloadMap
-      = new HashMap<Preload, Future<HttpResponse>>();
+  private Map<Preload, Future<HttpResponse>> preloadMap;
 
   @Deprecated
   private View currentView;
 
-  public Gadget() {}
+  public Gadget() { }
 
   /**
    * @deprecated Use default ctor and setter methods instead.
+   *
+   * TODO: Remove this entirely. The only code paths using it should be for the old rendering
+   * pipeline, so this can be removed once that's gone.
    */
   @Deprecated
   public Gadget(GadgetContext context, GadgetSpec spec,
       Collection<JsLibrary> jsLibraries, ContainerConfig containerConfig,
       GadgetHtmlParser contentParser) {
-
+    this.preloadMap = Maps.newHashMap();
     this.context = context;
     this.spec = spec;
     this.jsLibraries = jsLibraries;

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/NullPreloads.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/NullPreloads.java?rev=698638&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/NullPreloads.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/NullPreloads.java Wed Sep 24 09:37:42 2008
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.preload;
+
+import java.util.Collections;
+import java.util.Set;
+
+public class NullPreloads implements Preloads {
+  public PreloadedData getData(String key) {
+    throw new UnsupportedOperationException();
+  }
+  public Set<String> getKeys() {
+    return Collections.emptySet();
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java?rev=698638&r1=698637&r2=698638&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/RenderingContentRewriter.java Wed Sep 24 09:37:42 2008
@@ -33,6 +33,8 @@
 import org.apache.shindig.gadgets.UrlGenerator;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.preload.PreloadException;
+import org.apache.shindig.gadgets.preload.Preloads;
 import org.apache.shindig.gadgets.rewrite.ContentRewriter;
 import org.apache.shindig.gadgets.rewrite.RewriterResults;
 import org.apache.shindig.gadgets.spec.Feature;
@@ -51,6 +53,8 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -71,6 +75,7 @@
  * - html document normalization
  */
 public class RenderingContentRewriter implements ContentRewriter {
+  private static final Logger LOG = Logger.getLogger(RenderingContentRewriter.class.getName());
   static final Pattern DOCUMENT_SPLIT_PATTERN = Pattern.compile(
       "(.*)<head>(.*?)<\\/head>(?:.*)<body(.*?)>(.*?)<\\/body>(?:.*)", Pattern.DOTALL);
   static final int BEFORE_HEAD_GROUP = 1;
@@ -104,17 +109,21 @@
     this.urlGenerator = urlGenerator;
   }
 
-  public RewriterResults rewrite(HttpRequest request, HttpResponse original,
-      MutableContent content) {
-    throw new UnsupportedOperationException();
+  public RewriterResults rewrite(HttpRequest req, HttpResponse resp,  MutableContent content) {
+    return RewriterResults.notCacheable();
   }
 
   public RewriterResults rewrite(Gadget gadget) {
     try {
       GadgetContent content = createGadgetContent(gadget);
+
       injectFeatureLibraries(gadget, content);
-      injectOnLoadHandlers(content);
+      // This can be one script block.
+      content.appendHead("<script>");
       injectMessageBundles(gadget, content);
+      injectPreloads(gadget, content);
+      content.appendHead("</script>");
+      injectOnLoadHandlers(content);
       // TODO: Use preloads when RenderedGadget gets promoted to Gadget.
       finalizeDocument(gadget, content);
       return RewriterResults.notCacheable();
@@ -305,10 +314,35 @@
         gadget.getSpec(), context.getLocale(), context.getIgnoreCache());
 
     String msgs = new JSONObject(bundle.getMessages()).toString();
-    // TODO: Figure out a simple way to merge scripts.
-    content.appendHead("<script>gadgets.Prefs.setMessages_(")
+    content.appendHead("gadgets.Prefs.setMessages_(")
            .appendHead(msgs)
-           .appendHead(");</script>");
+           .appendHead(");");
+  }
+
+  /**
+   * Injects preloads into the gadget output.
+   *
+   * If preloading fails for any reason, we just output an empty object.
+   */
+  private void injectPreloads(Gadget gadget, GadgetContent content) {
+    JSONObject preload = new JSONObject();
+    Preloads preloads = gadget.getPreloads();
+
+    for (String name : preloads.getKeys()) {
+      try {
+        preload.put(name, preloads.getData(name).toJson());
+      } catch (PreloadException e) {
+        // This will be thrown in the event of some unexpected exception. We can move on.
+        LOG.log(Level.WARNING, "Unexpected error attempting to preload " + name, e);
+      } catch (JSONException e) {
+        // Shouldn't ever happen. Probably indicates a big problem, so we'll abort.
+        throw new RuntimeException(e);
+      }
+    }
+
+    content.appendHead("gadgets.io.preloaded_=")
+           .appendHead(preload.toString())
+           .appendHead(";");
   }
 
   /**

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java?rev=698638&r1=698637&r2=698638&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java Wed Sep 24 09:37:42 2008
@@ -36,7 +36,12 @@
 import org.apache.shindig.gadgets.GadgetFeatureRegistry;
 import org.apache.shindig.gadgets.JsLibrary;
 import org.apache.shindig.gadgets.MessageBundleFactory;
+import org.apache.shindig.gadgets.MutableContent;
 import org.apache.shindig.gadgets.UrlGenerator;
+import org.apache.shindig.gadgets.preload.NullPreloads;
+import org.apache.shindig.gadgets.preload.PreloadException;
+import org.apache.shindig.gadgets.preload.PreloadedData;
+import org.apache.shindig.gadgets.preload.Preloads;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 import org.apache.shindig.gadgets.spec.LocaleSpec;
 import org.apache.shindig.gadgets.spec.MessageBundle;
@@ -48,6 +53,7 @@
 
 import org.easymock.classextension.EasyMock;
 import org.easymock.classextension.IMocksControl;
+import org.json.JSONException;
 import org.json.JSONObject;
 import org.junit.Before;
 import org.junit.Test;
@@ -55,7 +61,6 @@
 import java.net.URI;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
@@ -84,16 +89,24 @@
         = new RenderingContentRewriter(messageBundleFactory, config, featureRegistry, urlGenerator);
   }
 
+  private Gadget makeGadgetWithSpec(String gadgetXml) throws GadgetException {
+    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
+    return new Gadget()
+        .setContext(new GadgetContext())
+        .setMutableContent(new MutableContent(null))
+        .setPreloads(new NullPreloads())
+        .setSpec(spec)
+        .setContent(spec.getView("default").getContent());
+  }
+
+  private Gadget makeGadgetWithContent(String content) throws GadgetException {
+    String defaultXml = "<Module><ModulePrefs title=''/><Content type='html'/></Module>";
+    return makeGadgetWithSpec(defaultXml).setContent(content);
+  }
+
   @Test
   public void defaultOutput() throws Exception {
-    String gadgetXml =
-        "<Module><ModulePrefs title=''/>" +
-        "<Content type='html'>" + BODY_CONTENT + "</Content>" +
-        "</Module>";
-
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithContent(BODY_CONTENT);
 
     control.replay();
 
@@ -127,12 +140,7 @@
         .append(body)
         .append("</body></html>")
         .toString();
-    String gadgetXml =
-        "<Module><ModulePrefs title=''/>" +
-        "<Content type='html'><![CDATA[" + doc + "]]></Content>" +
-        "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
     GadgetContext context = new GadgetContext() {
       @Override
       public String getParameter(String name) {
@@ -143,7 +151,8 @@
       }
     };
 
-    Gadget gadget = new Gadget(context, spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithContent(doc)
+        .setContext(context);
 
     featureRegistry.addInline("foo", "does-not-matter");
     control.replay();
@@ -173,12 +182,10 @@
       "<Module><ModulePrefs title=''>" +
       "  <Locale language_direction='rtl'/>" +
       "</ModulePrefs>" +
-      "<Content type='html'>" + BODY_CONTENT + "</Content>" +
+      "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml);
 
     control.replay();
 
@@ -207,8 +214,6 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-
     final Collection<String> libs = Arrays.asList("foo", "bar", "baz");
     GadgetContext context = new GadgetContext() {
       @Override
@@ -220,7 +225,7 @@
       }
     };
 
-    Gadget gadget = new Gadget(context, spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml).setContext(context);
 
     featureRegistry.addInline("foo", "does-not-matter");
     featureRegistry.addInline("bar", "does-not-matter");
@@ -243,10 +248,7 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml);
 
     featureRegistry.addInline("foo", "foo_content();");
     control.replay();
@@ -265,8 +267,6 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-
     final Collection<String> libs = Arrays.asList("bar", "baz");
     GadgetContext context = new GadgetContext() {
       @Override
@@ -278,7 +278,7 @@
       }
     };
 
-    Gadget gadget = new Gadget(context, spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml).setContext(context);
 
     featureRegistry.addInline("foo", "foo_content();");
     featureRegistry.addInline("bar", "does-not-matter");
@@ -303,8 +303,6 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-
     GadgetContext context = new GadgetContext() {
       @Override
       public String getParameter(String name) {
@@ -315,7 +313,7 @@
       }
     };
 
-    Gadget gadget = new Gadget(context, spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml).setContext(context);
 
     featureRegistry.addInline("foo", "foo_content();");
     featureRegistry.addExternal("bar", "http://example.org/external.js");
@@ -332,7 +330,7 @@
         gadget.getContent().contains("<script src=\"http://example.org/external.js\">"));
   }
 
-  private JSONObject getJson(Gadget gadget) throws Exception {
+  private JSONObject getConfigJson(Gadget gadget) throws JSONException {
     Pattern prefsPattern
         = Pattern.compile("(?:.*)gadgets\\.config\\.init\\((.*)\\);(?:.*)", Pattern.DOTALL);
     Matcher matcher = prefsPattern.matcher(gadget.getContent());
@@ -349,9 +347,7 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml);
 
     featureRegistry.addInline("foo", "");
 
@@ -362,7 +358,7 @@
 
     rewriter.rewrite(gadget);
 
-    JSONObject json = getJson(gadget);
+    JSONObject json = getConfigJson(gadget);
     assertEquals("blah", json.get("foo"));
   }
 
@@ -375,8 +371,6 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-
     GadgetContext context = new GadgetContext() {
       @Override
       public String getParameter(String name) {
@@ -387,7 +381,7 @@
       }
     };
 
-    Gadget gadget = new Gadget(context, spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml).setContext(context);
 
     featureRegistry.addInline("foo", "");
     featureRegistry.addInline("bar", "");
@@ -399,7 +393,7 @@
 
     rewriter.rewrite(gadget);
 
-    JSONObject json = getJson(gadget);
+    JSONObject json = getConfigJson(gadget);
     assertEquals("blah", json.get("foo"));
     assertEquals("baz", json.get("bar"));
   }
@@ -415,9 +409,7 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml);
 
     featureRegistry.addInline("foo", "");
     JSONObject conf = new JSONObject();
@@ -427,7 +419,7 @@
 
     rewriter.rewrite(gadget);
 
-    JSONObject json = getJson(gadget);
+    JSONObject json = getConfigJson(gadget);
     assertEquals("blah", json.get("foo"));
 
     JSONObject util = json.getJSONObject("core.util");
@@ -449,9 +441,7 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml);
 
     control.replay();
 
@@ -475,9 +465,7 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml);
 
     control.replay();
 
@@ -493,9 +481,7 @@
       "<Content type='html'/>" +
       "</Module>";
 
-    GadgetSpec spec = new GadgetSpec(URI.create("#"), gadgetXml);
-    Gadget gadget
-        = new Gadget(new GadgetContext(), spec, Collections.<JsLibrary>emptySet(), config, null);
+    Gadget gadget = makeGadgetWithSpec(gadgetXml);
 
     control.replay();
 
@@ -504,6 +490,74 @@
     // rewrite will throw if the optional unsupported feature doesn't work.
   }
 
+  private JSONObject getPreloadedJson(Gadget gadget) throws JSONException {
+    Pattern preloadPattern
+        = Pattern.compile("(?:.*)gadgets\\.io\\.preloaded_=\\{(.*?)\\};(?:.*)", Pattern.DOTALL);
+    Matcher matcher = preloadPattern.matcher(gadget.getContent());
+    assertTrue("gadgets.io.preloaded not set.", matcher.matches());
+    return new JSONObject('{' + matcher.group(1) + '}');
+  }
+
+  @Test
+  public void preloadsInjected() throws Exception {
+    final Map<String, Object> preloadData = Maps.newHashMap();
+
+    // We want a variety of data.
+    preloadData.put("string", "string");
+    preloadData.put("integer", 99);
+    preloadData.put("double", 4343434.345345d);
+
+    // Other types are supported (anything valid for org.json.JSONObject), but equality comparisons
+    // are more complicated because JSON doesn't implement interfaces like Collection or Map, or
+    // implementing equals.
+
+    Preloads preloads = new Preloads() {
+
+      public PreloadedData getData(final String key) {
+        return new PreloadedData() {
+          public Object toJson() {
+            return preloadData.get(key);
+          }
+        };
+      }
+
+      public Set<String> getKeys() {
+        return preloadData.keySet();
+      }
+    };
+
+    Gadget gadget = makeGadgetWithContent("").setPreloads(preloads);
+    control.replay();
+
+    rewriter.rewrite(gadget);
+
+    JSONObject json = getPreloadedJson(gadget);
+    for (Map.Entry<String, Object> entry : preloadData.entrySet()) {
+      assertEquals(entry.getValue(), json.get(entry.getKey()));
+    }
+  }
+
+  @Test
+  public void failedPreloadHandledGracefully() throws Exception {
+    Preloads preloads = new Preloads() {
+      public PreloadedData getData(final String key) throws PreloadException {
+        throw new PreloadException("broken");
+      }
+      public Set<String> getKeys() {
+        return Sets.immutableSortedSet("foo");
+      }
+    };
+
+    Gadget gadget = makeGadgetWithContent("").setPreloads(preloads);
+    control.replay();
+
+    rewriter.rewrite(gadget);
+
+    JSONObject json = getPreloadedJson(gadget);
+
+    assertEquals(0, json.length());
+  }
+
   /**
    * Simple message bundle factory -- only honors inline bundles.
    */