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.
*/