You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by aw...@apache.org on 2009/04/06 20:25:40 UTC
svn commit: r762448 - in /incubator/shindig/trunk/java/gadgets/src:
main/java/org/apache/shindig/gadgets/preload/
main/java/org/apache/shindig/gadgets/render/
main/java/org/apache/shindig/gadgets/rewrite/
test/java/org/apache/shindig/gadgets/preload/ t...
Author: awiner
Date: Mon Apr 6 18:25:39 2009
New Revision: 762448
URL: http://svn.apache.org/viewvc?rev=762448&view=rev
Log:
Refactor execution of the data pipeline into a new PipelineExecutor class so it can be shared by proxied rendering and templating. In particular, this gives proxied rendering support for multi-batch pipelines with inter-dependent data.
One outcome is that PipelinedDataPreloader is no longer a Preloader - it's not called as such. Subsequent changes will simplify Preloader binding, and subsequent subsequence changes will hopefully make HttpPreloader obsolete and removeable.
Added:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelineExecutor.java (with props)
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelineExecutorTest.java (with props)
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloader.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PreloadModule.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/ProxyRenderer.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriter.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloaderTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/ProxyRendererTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriterTest.java
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelineExecutor.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelineExecutor.java?rev=762448&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelineExecutor.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelineExecutor.java Mon Apr 6 18:25:39 2009
@@ -0,0 +1,179 @@
+/*
+ * 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 org.apache.shindig.expressions.Expressions;
+import org.apache.shindig.expressions.RootELResolver;
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.GadgetELResolver;
+import org.apache.shindig.gadgets.spec.PipelinedData;
+import org.apache.shindig.gadgets.spec.PipelinedData.Batch;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.el.CompositeELResolver;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
+/**
+ * Runs data pipelining, chaining dependencies among batches as needed.
+ */
+public class PipelineExecutor {
+ // TODO: support configuration
+ private static final int MAX_BATCH_COUNT = 3;
+ private static final Logger logger = Logger.getLogger(PipelineExecutor.class.getName());
+
+ private PipelinedDataPreloader preloader;
+ private PreloaderService preloaderService;
+ private Expressions expressions;
+
+ @Inject
+ public PipelineExecutor(PipelinedDataPreloader preloader,
+ PreloaderService preloaderService,
+ Expressions expressions) {
+ this.preloader = preloader;
+ this.preloaderService = preloaderService;
+ this.expressions = expressions;
+ }
+
+ /**
+ * Results from a full pipeline execution.
+ */
+ public static class Results {
+ /**
+ * A collection of the pipelines that could not be fully
+ * evaluated.
+ */
+ public final Collection<PipelinedData> remainingPipelines;
+
+ /**
+ * Results in the form of a full JSON-RPC batch response.
+ */
+ public final JSONArray results;
+
+ /**
+ * Results in the form of a Map from id to JSONObject.
+ */
+ public final Map<String, JSONObject> keyedResults;
+
+ public Results(Collection<PipelinedData> remainingPipelines,
+ JSONArray results,
+ Map<String, JSONObject> keyedResults) {
+ this.remainingPipelines = remainingPipelines;
+ this.results = results;
+ this.keyedResults = keyedResults;
+ }
+ }
+
+ /**
+ * Executes a pipeline, or set of pipelines.
+ * @param context the gadget context for the state in which the pipelines execute
+ * @param pipelines a collection of pipelines
+ * @return results from the pipeline, or null if there are no results
+ */
+ public Results execute(GadgetContext context, Collection<PipelinedData> pipelines) {
+ JSONArray results = new JSONArray();
+ Map<String, JSONObject> elResults = Maps.newHashMap();
+ CompositeELResolver rootObjects = new CompositeELResolver();
+ rootObjects.add(new GadgetELResolver(context));
+ rootObjects.add(new RootELResolver(elResults));
+
+ List<PipelineState> pipelineStates = Lists.newArrayList();
+ for (PipelinedData pipeline : pipelines) {
+ PipelinedData.Batch batch = pipeline.getBatch(expressions, rootObjects);
+ pipelineStates.add(new PipelineState(pipeline, batch));
+ }
+
+ int batchCount = 0;
+ while (true) {
+ List<Callable<PreloadedData>> tasks = Lists.newArrayList();
+ for (PipelineState pipeline : pipelineStates) {
+ if (pipeline.batch != null) {
+ tasks.addAll(preloader.createPreloadTasks(context, pipeline.batch));
+ }
+ }
+
+ if (tasks.isEmpty()) {
+ break;
+ }
+
+ Collection<PreloadedData> preloads = preloaderService.preload(tasks);
+ for (PreloadedData preloaded : preloads) {
+ try {
+ for (Object entry : preloaded.toJson()) {
+ JSONObject obj = (JSONObject) entry;
+ results.put(obj);
+ if (obj.has("data")) {
+ elResults.put(obj.getString("id"), obj.getJSONObject("data"));
+ } else if (obj.has("error")) {
+ elResults.put(obj.getString("id"), obj.getJSONObject("error"));
+ }
+ }
+ } catch (PreloadException pe) {
+ // This will be thrown in the event of some unexpected exception. We can move on.
+ logger.log(Level.WARNING, "Unexpected error when preloading", pe);
+ } catch (JSONException je) {
+ throw new RuntimeException(je);
+ }
+ }
+
+ // Advance to the next batch
+ for (PipelineState pipeline : pipelineStates) {
+ if (pipeline.batch != null) {
+ pipeline.batch = pipeline.batch.getNextBatch(rootObjects);
+ }
+ }
+
+ batchCount++;
+ if (batchCount == MAX_BATCH_COUNT) {
+ break;
+ }
+ }
+
+ List<PipelinedData> remainingPipelines = Lists.newArrayList();
+ for (PipelineState pipeline : pipelineStates) {
+ if (pipeline.batch != null) {
+ remainingPipelines.add(pipeline.pipeline);
+ }
+ }
+
+ return new Results(remainingPipelines, results, elResults);
+ }
+
+ /** State of one of the pipelines */
+ static class PipelineState {
+ public PipelineState(PipelinedData pipeline, Batch batch) {
+ this.pipeline = pipeline;
+ this.batch = batch;
+ }
+
+ public final PipelinedData pipeline;
+ public PipelinedData.Batch batch;
+ }
+}
Propchange: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelineExecutor.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloader.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloader.java?rev=762448&r1=762447&r2=762448&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloader.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloader.java Mon Apr 6 18:25:39 2009
@@ -21,18 +21,14 @@
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.uri.UriBuilder;
import org.apache.shindig.config.ContainerConfig;
-import org.apache.shindig.expressions.Expressions;
import org.apache.shindig.gadgets.AuthType;
-import org.apache.shindig.gadgets.Gadget;
import org.apache.shindig.gadgets.GadgetContext;
-import org.apache.shindig.gadgets.GadgetELResolver;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.http.RequestPipeline;
import org.apache.shindig.gadgets.spec.PipelinedData;
import org.apache.shindig.gadgets.spec.RequestAuthenticationInfo;
-import org.apache.shindig.gadgets.spec.View;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -46,18 +42,15 @@
import java.nio.charset.Charset;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
-import javax.el.ELResolver;
-
/**
- * Preloader for loading Data Pipelining Preload data.
+ * Processes a single batch of pipeline data into tasks.
*/
-public class PipelinedDataPreloader implements Preloader {
+public class PipelinedDataPreloader {
private final RequestPipeline requestPipeline;
private final ContainerConfig config;
@@ -65,36 +58,13 @@
private static Set<String> HTTP_RESPONSE_HEADERS =
ImmutableSet.of("content-type", "location", "set-cookie");
- private final Expressions expressions;
-
@Inject
- public PipelinedDataPreloader(RequestPipeline requestPipeline, ContainerConfig config,
- Expressions expressions) {
+ public PipelinedDataPreloader(RequestPipeline requestPipeline, ContainerConfig config) {
this.requestPipeline = requestPipeline;
this.config = config;
- this.expressions = expressions;
- }
-
- /** Create preloads from a gadget view */
- public Collection<Callable<PreloadedData>> createPreloadTasks(Gadget gadget,
- PreloaderService.PreloadPhase phase) {
- View view = gadget.getCurrentView();
- if (view != null
- && view.getPipelinedData() != null
- && phase == PreloaderService.PreloadPhase.PROXY_FETCH) {
-
- ELResolver resolver = new GadgetELResolver(gadget.getContext());
- PipelinedData.Batch batch = view.getPipelinedData().getBatch(expressions,
- resolver);
- if (batch != null) {
- return createPreloadTasks(gadget.getContext(), batch);
- }
- }
-
- return Collections.emptyList();
}
- /** Create preload tasks from an explicit list of social and http preloads */
+ /** Create preload tasks from a batch of social and http preloads */
public Collection<Callable<PreloadedData>> createPreloadTasks(GadgetContext context,
PipelinedData.Batch batch) {
List<Callable<PreloadedData>> preloadList = Lists.newArrayList();
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PreloadModule.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PreloadModule.java?rev=762448&r1=762447&r2=762448&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PreloadModule.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/PreloadModule.java Mon Apr 6 18:25:39 2009
@@ -20,7 +20,7 @@
import java.util.List;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -39,8 +39,8 @@
private final List<Preloader> preloaders;
@Inject
- public PreloaderProvider(HttpPreloader httpPreloader, PipelinedDataPreloader socialPreloader) {
- preloaders = Lists.newArrayList(httpPreloader, socialPreloader);
+ public PreloaderProvider(HttpPreloader httpPreloader) {
+ preloaders = ImmutableList.of((Preloader) httpPreloader);
}
public List<Preloader> get() {
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/ProxyRenderer.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/ProxyRenderer.java?rev=762448&r1=762447&r2=762448&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/ProxyRenderer.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/ProxyRenderer.java Mon Apr 6 18:25:39 2009
@@ -29,18 +29,14 @@
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.http.RequestPipeline;
import org.apache.shindig.gadgets.oauth.OAuthArguments;
-import org.apache.shindig.gadgets.preload.PreloadException;
-import org.apache.shindig.gadgets.preload.PreloadedData;
-import org.apache.shindig.gadgets.preload.PreloaderService;
+import org.apache.shindig.gadgets.preload.PipelineExecutor;
+import org.apache.shindig.gadgets.spec.PipelinedData;
import org.apache.shindig.gadgets.spec.View;
-import org.json.JSONArray;
import java.nio.charset.Charset;
-import java.util.Collection;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
/**
@@ -49,11 +45,10 @@
public class ProxyRenderer {
public static final String PATH_PARAM = "path";
private static final Charset UTF8 = Charset.forName("UTF-8");
- private static final Logger logger = Logger.getLogger(ProxyRenderer.class.getName());
- private RequestPipeline requestPipeline;
- private HttpCache httpCache;
- private PreloaderService preloader;
+ private final RequestPipeline requestPipeline;
+ private final HttpCache httpCache;
+ private final PipelineExecutor pipelineExecutor;
/**
* @param requestPipeline Used for performing the proxy request. Always ignores caching because
@@ -63,10 +58,10 @@
*/
@Inject
public ProxyRenderer(RequestPipeline requestPipeline,
- HttpCache httpCache, PreloaderService preloader) {
+ HttpCache httpCache, PipelineExecutor pipelineExecutor) {
this.requestPipeline = requestPipeline;
this.httpCache = httpCache;
- this.preloader = preloader;
+ this.pipelineExecutor = pipelineExecutor;
}
public String render(Gadget gadget) throws RenderingException, GadgetException {
@@ -126,33 +121,22 @@
private HttpRequest createPipelinedProxyRequest(Gadget gadget, HttpRequest original) {
HttpRequest request = new HttpRequest(original);
request.setIgnoreCache(true);
- Collection<PreloadedData> proxyPreloads = preloader.preload(gadget,
- PreloaderService.PreloadPhase.PROXY_FETCH);
- // TODO: Add current url to GadgetContext to support transitive proxying.
-
- // POST any preloaded content
- if ((proxyPreloads != null) && !proxyPreloads.isEmpty()) {
- JSONArray array = new JSONArray();
-
- for (PreloadedData preload : proxyPreloads) {
- try {
- for (Object entry : preload.toJson()) {
- array.put(entry);
- }
- } catch (PreloadException pe) {
- // TODO: Determine whether this is a terminal path for the request. The spec is not
- // clear.
- logger.log(Level.WARNING, "Unexpected error when preloading", pe);
- }
+
+ PipelinedData data = gadget.getCurrentView().getPipelinedData();
+ if (data != null) {
+ PipelineExecutor.Results results =
+ pipelineExecutor.execute(gadget.getContext(), ImmutableList.of(data));
+
+ if (results != null && results.results.length() != 0) {
+ String postContent = JsonSerializer.serialize(results.results);
+ // POST the preloaded content, with a method override of GET
+ // to enable caching
+ request.setMethod("POST")
+ .setPostBody(UTF8.encode(postContent).array())
+ .setHeader("Content-Type", "application/json;charset=utf-8");
}
-
- String postContent = JsonSerializer.serialize(array);
- // POST the preloaded content, with a method override of GET
- // to enable caching
- request.setMethod("POST")
- .setPostBody(UTF8.encode(postContent).array())
- .setHeader("Content-Type", "application/json;charset=utf-8");
}
+
return request;
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriter.java?rev=762448&r1=762447&r2=762448&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriter.java Mon Apr 6 18:25:39 2009
@@ -20,23 +20,12 @@
import org.apache.shindig.common.JsonSerializer;
import org.apache.shindig.common.xml.DomUtil;
-import org.apache.shindig.expressions.Expressions;
-import org.apache.shindig.expressions.RootELResolver;
import org.apache.shindig.gadgets.Gadget;
-import org.apache.shindig.gadgets.GadgetELResolver;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
-import org.apache.shindig.gadgets.preload.PipelinedDataPreloader;
-import org.apache.shindig.gadgets.preload.PreloadException;
-import org.apache.shindig.gadgets.preload.PreloadedData;
-import org.apache.shindig.gadgets.preload.PreloaderService;
+import org.apache.shindig.gadgets.preload.PipelineExecutor;
import org.apache.shindig.gadgets.spec.PipelinedData;
import org.apache.shindig.gadgets.spec.SpecParserException;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.inject.Inject;
-import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -45,14 +34,13 @@
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.NodeIterator;
-import javax.el.CompositeELResolver;
-import java.util.Collection;
-import java.util.List;
import java.util.Map;
-import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
/**
* ContentRewriter that resolves opensocial-data elements on the server.
*
@@ -62,20 +50,12 @@
private static final Logger logger = Logger.getLogger(
PipelineDataContentRewriter.class.getName());
- // TODO: support configuration
- private static final int MAX_BATCH_COUNT = 3;
- private final PipelinedDataPreloader preloader;
- private final PreloaderService preloaderService;
- private final Expressions expressions;
+ private final PipelineExecutor executor;
@Inject
- public PipelineDataContentRewriter(PipelinedDataPreloader preloader,
- PreloaderService preloaderService,
- Expressions expressions) {
- this.preloader = preloader;
- this.preloaderService = preloaderService;
- this.expressions = expressions;
+ public PipelineDataContentRewriter(PipelineExecutor executor) {
+ this.executor = executor;
}
public RewriterResults rewrite(HttpRequest request, HttpResponse original, MutableContent content) {
@@ -101,123 +81,59 @@
}
}, false);
-
- Map<String, JSONObject> results = Maps.newHashMap();
-
- // Use the default objects in the GadgetContext, and any objects that
- // have been resolved
- List<PipelineState> pipelines = Lists.newArrayList();
- CompositeELResolver rootObjects = new CompositeELResolver();
- rootObjects.add(new GadgetELResolver(gadget.getContext()));
- rootObjects.add(new RootELResolver(results));
-
+ Map<PipelinedData, Node> pipelineNodes = Maps.newHashMap();
for (Node n = nodeIterator.nextNode(); n != null ; n = nodeIterator.nextNode()) {
try {
PipelinedData pipelineData = new PipelinedData((Element) n, gadget.getSpec().getUrl());
- PipelinedData.Batch batch = pipelineData.getBatch(expressions, rootObjects);
- if (batch == null) {
- // An empty pipeline element - just remove it
- n.getParentNode().removeChild(n);
- } else {
- // Not empty, ready it
- PipelineState state = new PipelineState();
- state.batch = batch;
- state.node = n;
- pipelines.add(state);
- }
+ pipelineNodes.put(pipelineData, n);
} catch (SpecParserException e) {
// Leave the element to the client
logger.log(Level.INFO, "Failed to parse preload in " + gadget.getSpec().getUrl(), e);
}
}
- // No pipline elements found, return early
- if (pipelines.isEmpty()) {
+ if (pipelineNodes.isEmpty()) {
return null;
}
-
- // Run batches until we run out
- int batchCount = 0;
- while (true) {
- // Gather all tasks from the first batch
- List<Callable<PreloadedData>> tasks = Lists.newArrayList();
- for (PipelineState pipeline : pipelines) {
- if (pipeline.batch != null) {
- tasks.addAll(preloader.createPreloadTasks(gadget.getContext(), pipeline.batch));
- }
- }
-
- // No further progress - quit
- if (tasks.isEmpty()) {
- break;
- }
-
- // And run the pipeline
- Collection<PreloadedData> preloads = preloaderService.preload(tasks);
- for (PreloadedData preloaded : preloads) {
- try {
- for (Object entry : preloaded.toJson()) {
- JSONObject obj = (JSONObject) entry;
- if (obj.has("data")) {
- results.put(obj.getString("id"), obj.getJSONObject("data"));
- }
- // TODO: handle errors?
- }
- } catch (PreloadException pe) {
- // This will be thrown in the event of some unexpected exception. We can move on.
- logger.log(Level.WARNING, "Unexpected error when preloading", pe);
- } catch (JSONException je) {
- throw new RuntimeException(je);
- }
- }
-
- // Advance to the next batch
- for (PipelineState pipeline : pipelines) {
- if (pipeline.batch != null) {
- pipeline.batch = pipeline.batch.getNextBatch(rootObjects);
- // Once there are no more batches, delete the associated script node.
- if (pipeline.batch == null) {
- pipeline.node.getParentNode().removeChild(pipeline.node);
- }
- }
- }
-
- // TODO: necessary?
- if (batchCount++ >= MAX_BATCH_COUNT) {
- break;
+
+ PipelineExecutor.Results results =
+ executor.execute(gadget.getContext(), pipelineNodes.keySet());
+
+ // Remove all pipeline entries that were fully evaluated
+ for (Map.Entry<PipelinedData, Node> nodeEntry : pipelineNodes.entrySet()) {
+ if (!results.remainingPipelines.contains(nodeEntry.getKey())) {
+ Node node = nodeEntry.getValue();
+ node.getParentNode().removeChild(node);
+ MutableContent.notifyEdit(doc);
}
}
-
- Element head = (Element) DomUtil.getFirstNamedChildNode(doc.getDocumentElement(), "head");
- Element pipelineScript = doc.createElement("script");
- pipelineScript.setAttribute("type", "text/javascript");
-
- StringBuilder script = new StringBuilder();
- for (Map.Entry<String, JSONObject> entry : results.entrySet()) {
- String key = entry.getKey();
-
- // TODO: escape key
- content.addPipelinedData(key, entry.getValue());
- script.append("opensocial.data.DataContext.putDataSet(\"")
- .append(key)
- .append("\",")
- .append(JsonSerializer.serialize(entry.getValue()))
- .append(");");
- }
-
- pipelineScript.appendChild(doc.createTextNode(script.toString()));
- head.appendChild(pipelineScript);
- MutableContent.notifyEdit(doc);
-
- boolean allBatchesCompleted = true;
- for (PipelineState pipeline : pipelines) {
- if (pipeline.batch != null) {
- allBatchesCompleted = false;
- break;
+
+ // Insert script elements for all the successful results
+ if (!results.keyedResults.isEmpty()) {
+ Element head = (Element) DomUtil.getFirstNamedChildNode(doc.getDocumentElement(), "head");
+ Element pipelineScript = doc.createElement("script");
+ pipelineScript.setAttribute("type", "text/javascript");
+
+ StringBuilder script = new StringBuilder();
+ for (Map.Entry<String, JSONObject> entry : results.keyedResults.entrySet()) {
+ String key = entry.getKey();
+
+ // TODO: escape key
+ content.addPipelinedData(key, entry.getValue());
+ script.append("opensocial.data.DataContext.putDataSet(\"")
+ .append(key)
+ .append("\",")
+ .append(JsonSerializer.serialize(entry.getValue()))
+ .append(");");
}
+
+ pipelineScript.appendChild(doc.createTextNode(script.toString()));
+ head.appendChild(pipelineScript);
+ MutableContent.notifyEdit(doc);
}
- if (allBatchesCompleted) {
+ // And if no pipelines remain unexecuted, remove the opensocial-data feature
+ if (results.remainingPipelines.isEmpty()) {
gadget.addFeature("opensocial-data-context");
gadget.removeFeature("opensocial-data");
}
Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelineExecutorTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelineExecutorTest.java?rev=762448&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelineExecutorTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelineExecutorTest.java Mon Apr 6 18:25:39 2009
@@ -0,0 +1,336 @@
+/*
+ * 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 static org.easymock.EasyMock.and;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.reportMatcher;
+import static org.easymock.EasyMock.same;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.shindig.common.JsonAssert;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.xml.XmlUtil;
+import org.apache.shindig.expressions.Expressions;
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.spec.PipelinedData;
+import org.apache.shindig.gadgets.spec.RequestAuthenticationInfo;
+import org.apache.shindig.gadgets.spec.SpecParserException;
+import org.easymock.Capture;
+import org.easymock.IArgumentMatcher;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Element;
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class PipelineExecutorTest {
+
+ private IMocksControl control;
+ private PipelinedDataPreloader preloader;
+ private PreloaderService preloaderService;
+ private GadgetContext context;
+ private PipelineExecutor executor;
+
+ private static final Uri GADGET_URI = Uri.parse("http://example.org/gadget.php");
+
+ private static final String CONTENT =
+ "<Content xmlns:os=\"http://ns.opensocial.org/2008/markup\">"
+ + " <os:PeopleRequest key=\"me\" userId=\"canonical\"/>"
+ + " <os:HttpRequest key=\"json\" href=\"test.json\"/>"
+ + "</Content>";
+
+ // Two requests, one depends on the other
+ private static final String TWO_BATCH_CONTENT =
+ "<Content xmlns:os=\"http://ns.opensocial.org/2008/markup\">"
+ + " <os:PeopleRequest key=\"me\" userId=\"${json.user}\"/>"
+ + " <os:HttpRequest key=\"json\" href=\"${ViewParams.file}\"/>"
+ + "</Content>";
+
+ // One request, but it requires data that isn\"t present
+ private static final String BLOCKED_FIRST_BATCH_CONTENT =
+ "<Content xmlns:os=\"http://ns.opensocial.org/2008/markup\">"
+ + " <os:PeopleRequest key=\"me\" userId=\"${json.user}\"/>"
+ + "</Content>";
+
+ @Before
+ public void setUp() throws Exception {
+ control = EasyMock.createStrictControl();
+ preloader = control.createMock(PipelinedDataPreloader.class);
+ preloaderService = new ConcurrentPreloaderService(Executors.newSingleThreadExecutor(), null);
+ executor = new PipelineExecutor(preloader, preloaderService, new Expressions());
+
+ context = new GadgetContext(){};
+ }
+
+ private PipelinedData getPipelinedData(String pipelineXml) throws SpecParserException {
+ Element element = XmlUtil.parseSilent(pipelineXml);
+ return new PipelinedData(element, GADGET_URI);
+ }
+
+ @Test
+ public void execute() throws Exception {
+ PipelinedData pipeline = getPipelinedData(CONTENT);
+
+ Capture<PipelinedData.Batch> batchCapture =
+ new Capture<PipelinedData.Batch>();
+
+ JSONObject expectedData = new JSONObject("{data: {foo: 'bar'}}");
+
+ // Dummy return results (the "real" return would have two values)
+ Callable<PreloadedData> callable = createPreloadTask("key", expectedData.toString());
+
+ // One batch with 1 each HTTP and Social preload
+ expect(preloader.createPreloadTasks(same(context),
+ and(eqBatch(1, 1), capture(batchCapture))))
+ .andReturn(ImmutableList.of(callable));
+
+ control.replay();
+
+ PipelineExecutor.Results results = executor.execute(context,
+ ImmutableList.of(pipeline));
+
+ // Verify the data set is injected, and the os-data was deleted
+ assertTrue(batchCapture.getValue().getSocialPreloads().containsKey("me"));
+ assertTrue(batchCapture.getValue().getHttpPreloads().containsKey("json"));
+
+ JSONArray expectedArray = new JSONArray(
+ "[{id: 'key', data: {foo: 'bar'}}]");
+
+ JsonAssert.assertJsonArrayEquals(expectedArray, results.results);
+ JsonAssert.assertJsonObjectEquals(expectedData.getJSONObject("data"), results.keyedResults.get("key"));
+ assertTrue(results.remainingPipelines.isEmpty());
+
+ control.verify();
+ }
+
+ @Test
+ public void executeWithTwoBatches() throws Exception {
+ PipelinedData pipeline = getPipelinedData(TWO_BATCH_CONTENT);
+
+ context = new GadgetContext() {
+ @Override
+ public String getParameter(String property) {
+ // Provide the filename to be requested in the first batch
+ if ("view-params".equals(property)) {
+ return "{'file': 'test.json'}";
+ }
+ return null;
+ }
+ };
+
+ // First batch, the HTTP fetch
+ Capture<PipelinedData.Batch> firstBatch =
+ new Capture<PipelinedData.Batch>();
+ Callable<PreloadedData> firstTask = createPreloadTask("json",
+ "{data: {user: 'canonical'}}");
+
+ // Second batch, the user fetch
+ Capture<PipelinedData.Batch> secondBatch =
+ new Capture<PipelinedData.Batch>();
+ Callable<PreloadedData> secondTask = createPreloadTask("me",
+ "{data: {'id':'canonical'}}");
+
+ // First, a batch with an HTTP request
+ expect(
+ preloader.createPreloadTasks(same(context),
+ and(eqBatch(0, 1), capture(firstBatch))))
+ .andReturn(ImmutableList.of(firstTask));
+ // Second, a batch with a social request
+ expect(
+ preloader.createPreloadTasks(same(context),
+ and(eqBatch(1, 0), capture(secondBatch))))
+ .andReturn(ImmutableList.of(secondTask));
+
+ control.replay();
+
+ PipelineExecutor.Results results = executor.execute(context,
+ ImmutableList.of(pipeline));
+
+ JSONArray expectedArray = new JSONArray(
+ "[{id: 'json', data: {user: 'canonical'}}," +
+ "{id: 'me', data: {id: 'canonical'}}]");
+ JsonAssert.assertJsonArrayEquals(expectedArray, results.results);
+ assertEquals(ImmutableSet.of("json", "me"), results.keyedResults.keySet());
+ assertTrue(results.remainingPipelines.isEmpty());
+
+ control.verify();
+
+ // Verify the data set is injected, and the os-data was deleted
+
+ // Check the evaluated HTTP request
+ RequestAuthenticationInfo request = firstBatch.getValue().getHttpPreloads().get("json");
+ assertEquals("http://example.org/test.json", request.getHref().toString());
+
+ // Check the evaluated person request
+ JSONObject personRequest = (JSONObject) secondBatch.getValue().getSocialPreloads().get("me");
+ assertEquals("canonical", personRequest.getJSONObject("params").getJSONArray("userId").get(0));
+ }
+
+ @Test
+ public void executeWithBlockedBatch() throws Exception {
+ PipelinedData pipeline = getPipelinedData(BLOCKED_FIRST_BATCH_CONTENT);
+
+ // Expect a batch with no content
+ expect(
+ preloader.createPreloadTasks(same(context), eqBatch(0, 0)))
+ .andReturn(ImmutableList.<Callable<PreloadedData>>of());
+
+ control.replay();
+
+ PipelineExecutor.Results results = executor.execute(context,
+ ImmutableList.of(pipeline));
+ assertEquals(0, results.results.length());
+ assertTrue(results.keyedResults.isEmpty());
+ assertEquals(1, results.remainingPipelines.size());
+ assertSame(pipeline, results.remainingPipelines.iterator().next());
+
+ control.verify();
+ }
+
+ @Test
+ public void executeError() throws Exception {
+ PipelinedData pipeline = getPipelinedData(CONTENT);
+
+ Capture<PipelinedData.Batch> batchCapture =
+ new Capture<PipelinedData.Batch>();
+
+ JSONObject expectedData = new JSONObject("{error: {message: 'NO!', code: 500}}");
+
+ // Dummy return results (the "real" return would have two values)
+ Callable<PreloadedData> callable = createPreloadTask("key", expectedData.toString());
+
+ // One batch with 1 each HTTP and Social preload
+ expect(preloader.createPreloadTasks(same(context),
+ and(eqBatch(1, 1), capture(batchCapture))))
+ .andReturn(ImmutableList.of(callable));
+
+ control.replay();
+
+ PipelineExecutor.Results results = executor.execute(context,
+ ImmutableList.of(pipeline));
+
+ // Verify the data set is injected, and the os-data was deleted
+ assertTrue(batchCapture.getValue().getSocialPreloads().containsKey("me"));
+ assertTrue(batchCapture.getValue().getHttpPreloads().containsKey("json"));
+
+ JSONArray expectedArray = new JSONArray(
+ "[{id: 'key', error: {message: 'NO!', code: 500}}]");
+
+ JsonAssert.assertJsonArrayEquals(expectedArray, results.results);
+ JsonAssert.assertJsonObjectEquals(expectedData.getJSONObject("error"), results.keyedResults.get("key"));
+ assertTrue(results.remainingPipelines.isEmpty());
+
+ control.verify();
+ }
+
+ @Test
+ public void executePreloadException() throws Exception {
+ PipelinedData pipeline = getPipelinedData(CONTENT);
+ final PreloadedData willThrow = control.createMock(PreloadedData.class);
+
+ Callable<PreloadedData> callable = new Callable<PreloadedData>() {
+ public PreloadedData call() throws Exception {
+ return willThrow;
+ }
+ };
+
+ // One batch
+ expect(preloader.createPreloadTasks(same(context),
+ isA(PipelinedData.Batch.class))).andReturn(ImmutableList.of(callable));
+ // And PreloadedData that throws an exception
+ expect(willThrow.toJson()).andThrow(new PreloadException("Failed"));
+
+
+ control.replay();
+
+ PipelineExecutor.Results results = executor.execute(context,
+ ImmutableList.of(pipeline));
+
+ // The exception is fully handled, and leads to empty results
+ assertEquals(0, results.results.length());
+ assertTrue(results.keyedResults.isEmpty());
+ assertTrue(results.remainingPipelines.isEmpty());
+
+ control.verify();
+ }
+
+ /** Match a batch with the specified count of social and HTTP data items */
+ private PipelinedData.Batch eqBatch(int socialCount, int httpCount) {
+ reportMatcher(new BatchMatcher(socialCount, httpCount));
+ return null;
+ }
+
+ private static class BatchMatcher implements IArgumentMatcher {
+ private final int socialCount;
+ private final int httpCount;
+
+ public BatchMatcher(int socialCount, int httpCount) {
+ this.socialCount = socialCount;
+ this.httpCount = httpCount;
+ }
+
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("eqBuffer[social=" + socialCount + ",http=" + httpCount + "]");
+ }
+
+ public boolean matches(Object obj) {
+ if (!(obj instanceof PipelinedData.Batch)) {
+ return false;
+ }
+
+ PipelinedData.Batch batch = (PipelinedData.Batch) obj;
+ return (socialCount == batch.getSocialPreloads().size()
+ && httpCount == batch.getHttpPreloads().size());
+ }
+
+ }
+ /** Create a mock Callable for a single preload task */
+ private Callable<PreloadedData> createPreloadTask(final String key, String jsonResult)
+ throws JSONException {
+ final JSONObject value = new JSONObject(jsonResult);
+ value.put("id", key);
+ final PreloadedData preloadResult = new PreloadedData() {
+ public Collection<Object> toJson() throws PreloadException {
+ return ImmutableList.<Object>of(value);
+ }
+ };
+
+ Callable<PreloadedData> callable = new Callable<PreloadedData>() {
+ public PreloadedData call() throws Exception {
+ return preloadResult;
+ }
+ };
+ return callable;
+ }
+}
Propchange: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelineExecutorTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloaderTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloaderTest.java?rev=762448&r1=762447&r2=762448&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloaderTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/PipelinedDataPreloaderTest.java Mon Apr 6 18:25:39 2009
@@ -26,6 +26,7 @@
import org.apache.shindig.config.ContainerConfig;
import org.apache.shindig.expressions.Expressions;
import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetELResolver;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
@@ -33,9 +34,7 @@
import org.apache.shindig.gadgets.http.RequestPipeline;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.PipelinedData;
-
-import com.google.common.collect.Lists;
-
+import org.apache.shindig.gadgets.spec.PipelinedData.Batch;
import org.easymock.EasyMock;
import org.json.JSONObject;
import org.junit.Before;
@@ -46,6 +45,8 @@
import java.util.List;
import java.util.concurrent.Callable;
+import com.google.common.collect.Lists;
+
/**
* Test for PipelinedDataPreloader.
*/
@@ -113,8 +114,7 @@
String socialResult = "[{id:'p', data:1}, {id:'a', data:2}]";
RecordingRequestPipeline pipeline = new RecordingRequestPipeline(socialResult);
- PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig,
- expressions);
+ PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig);
view = "profile";
contextParams.put("st", "token");
@@ -124,8 +124,9 @@
.setSpec(spec)
.setCurrentView(spec.getView("profile"));
- Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(gadget,
- PreloaderService.PreloadPhase.PROXY_FETCH);
+ PipelinedData.Batch batch = getBatch(gadget);
+ Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(
+ context, batch);
assertEquals(1, tasks.size());
// Nothing fetched yet
assertEquals(0, pipeline.requests.size());
@@ -149,6 +150,11 @@
assertTrue(request.getContentType().startsWith("application/json"));
}
+ private Batch getBatch(Gadget gadget) {
+ return gadget.getCurrentView().getPipelinedData().getBatch(expressions,
+ new GadgetELResolver(gadget.getContext()));
+ }
+
@Test
public void testHttpPreloadOfJsonObject() throws Exception {
HttpResponse response = new HttpResponseBuilder()
@@ -232,8 +238,7 @@
GadgetSpec spec = new GadgetSpec(GADGET_URL, xml);
RecordingRequestPipeline pipeline = new RecordingRequestPipeline(response);
- PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig,
- expressions);
+ PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig);
view = "profile";
Gadget gadget = new Gadget()
@@ -241,8 +246,9 @@
.setSpec(spec)
.setCurrentView(spec.getView("profile"));
- Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(gadget,
- PreloaderService.PreloadPhase.PROXY_FETCH);
+ PipelinedData.Batch batch = getBatch(gadget);
+ Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(
+ context, batch);
assertEquals(1, tasks.size());
// Nothing fetched yet
assertEquals(0, pipeline.requests.size());
@@ -267,16 +273,16 @@
String httpResult = "{foo: 'bar'}";
RecordingRequestPipeline pipeline = new RecordingRequestPipeline(httpResult);
- PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig,
- expressions);
+ PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig);
view = "profile";
Gadget gadget = new Gadget()
.setContext(context)
.setSpec(spec)
.setCurrentView(spec.getView("profile"));
- Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(gadget,
- PreloaderService.PreloadPhase.PROXY_FETCH);
+ PipelinedData.Batch batch = getBatch(gadget);
+ Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(
+ context, batch);
tasks.iterator().next().call();
// Should have only fetched one request
@@ -294,16 +300,16 @@
String httpResult = "{foo: 'bar'}";
RecordingRequestPipeline pipeline = new RecordingRequestPipeline(httpResult);
- PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig,
- expressions);
+ PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig);
view = "profile";
Gadget gadget = new Gadget()
.setContext(context)
.setSpec(spec)
.setCurrentView(spec.getView("profile"));
- Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(gadget,
- PreloaderService.PreloadPhase.PROXY_FETCH);
+ PipelinedData.Batch batch = getBatch(gadget);
+ Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(
+ context, batch);
tasks.iterator().next().call();
// Should have only fetched one request
@@ -314,27 +320,6 @@
assertEquals("GET", request.getMethod());
}
-
- @Test
- public void testSocialPreloadForOtherView() throws Exception {
- GadgetSpec spec = new GadgetSpec(GADGET_URL, XML);
-
- String socialResult = "[{id:'p', data:1}, {id:'a', data:2}]";
- RecordingRequestPipeline pipeline = new RecordingRequestPipeline(socialResult);
- PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig,
- expressions);
- view = "canvas";
- contextParams.put("st", "token");
-
- Gadget gadget = new Gadget()
- .setContext(context)
- .setSpec(spec)
- .setCurrentView(spec.getView("canvas"));
- Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(gadget,
- PreloaderService.PreloadPhase.PROXY_FETCH);
- assertTrue(tasks.isEmpty());
- }
-
/**
* Verify that social preloads pay attention to view resolution by
* using gadget.getCurrentView().
@@ -345,8 +330,7 @@
String socialResult = "[{id:'p', data:1}, {id:'a', data:2}]";
RecordingRequestPipeline pipeline = new RecordingRequestPipeline(socialResult);
- PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig,
- expressions);
+ PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig);
view = "profile";
contextParams.put("st", "token");
@@ -357,31 +341,12 @@
// Assume view resolution has behaved correctly
.setCurrentView(spec.getView(GadgetSpec.DEFAULT_VIEW));
- Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(gadget,
- PreloaderService.PreloadPhase.PROXY_FETCH);
+ PipelinedData.Batch batch = getBatch(gadget);
+ Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(
+ context, batch);
assertEquals(1, tasks.size());
}
- @Test
- public void testSocialPreloadForHtmlRender() throws Exception {
- GadgetSpec spec = new GadgetSpec(GADGET_URL, XML);
-
- String socialResult = "[{id:'p', data:1}, {id:'a', data:2}]";
- RecordingRequestPipeline pipeline = new RecordingRequestPipeline(socialResult);
- PipelinedDataPreloader preloader = new PipelinedDataPreloader(pipeline, containerConfig,
- expressions);
- view = "profile";
- contextParams.put("st", "token");
-
- Gadget gadget = new Gadget()
- .setContext(context)
- .setSpec(spec)
- .setCurrentView(spec.getView("profile"));
- Collection<Callable<PreloadedData>> tasks = preloader.createPreloadTasks(gadget,
- PreloaderService.PreloadPhase.HTML_RENDER);
- assertTrue(tasks.isEmpty());
- }
-
private static class RecordingRequestPipeline implements RequestPipeline {
public final List<HttpRequest> requests = Lists.newArrayList();
private final HttpResponse response;
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/ProxyRendererTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/ProxyRendererTest.java?rev=762448&r1=762447&r2=762448&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/ProxyRendererTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/ProxyRendererTest.java Mon Apr 6 18:25:39 2009
@@ -23,6 +23,7 @@
import org.apache.shindig.auth.AnonymousSecurityToken;
import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.common.JsonAssert;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.uri.UriBuilder;
import org.apache.shindig.common.xml.XmlUtil;
@@ -33,22 +34,18 @@
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.http.RequestPipeline;
-import org.apache.shindig.gadgets.preload.PreloadException;
-import org.apache.shindig.gadgets.preload.PreloadedData;
-import org.apache.shindig.gadgets.preload.PreloaderService;
+import org.apache.shindig.gadgets.preload.PipelineExecutor;
import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.PipelinedData;
import org.apache.shindig.gadgets.spec.View;
import org.json.JSONArray;
-import org.json.JSONObject;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
-import java.util.concurrent.Callable;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
/**
@@ -69,8 +66,9 @@
private final FakeHttpCache cache = new FakeHttpCache();
private final FakeRequestPipeline pipeline = new FakeRequestPipeline();
- private final FakePreloaderService preloaderService = new FakePreloaderService();
- private final ProxyRenderer proxyRenderer = new ProxyRenderer(pipeline, cache, preloaderService);
+ private final FakePipelineExecutor pipelineExecutor = new FakePipelineExecutor();
+ private final ProxyRenderer proxyRenderer = new ProxyRenderer(pipeline,
+ cache, pipelineExecutor);
private Gadget makeGadget(String content) throws GadgetException {
GadgetSpec spec = new GadgetSpec(SPEC_URL,
@@ -198,41 +196,11 @@
@Test
public void renderProxiedWithPreload() throws Exception {
- final JSONObject prefetchedJson = new JSONObject("{id: 'foo', data: 'bar'}");
-
- preloaderService.preloads = ImmutableList.of((PreloadedData)
- new PreloadedData() {
- public Collection<Object> toJson() throws PreloadException {
- return ImmutableList.<Object>of(prefetchedJson);
- }
- });
+ JSONArray prefetchedJson = new JSONArray("[{id: 'foo', data: 'bar'}]");
+ pipelineExecutor.results = new PipelineExecutor.Results(null, prefetchedJson, null);
pipeline.plainResponses.put(EXPECTED_PROXIED_HTML_HREF, new HttpResponse(PROXIED_HTML_CONTENT));
- String content = proxyRenderer.render(makeHrefGadget("none"));
- assertEquals(PROXIED_HTML_CONTENT, content);
-
- HttpRequest lastHttpRequest = pipeline.getLastHttpRequest();
- assertEquals("POST", lastHttpRequest.getMethod());
- assertEquals("application/json;charset=utf-8", lastHttpRequest.getHeader("Content-Type"));
- String postBody = lastHttpRequest.getPostBodyAsString();
- JSONArray actualJson = new JSONArray(postBody);
-
- assertEquals(1, actualJson.length());
- assertEquals(prefetchedJson.toString(), actualJson.getJSONObject(0).toString());
- }
-
- @Test
- public void renderProxiedWithFailedPreload() throws Exception {
- new JSONObject("{id: 'foo', data: 'bar'}");
- preloaderService.preloads = ImmutableList.of((PreloadedData)
- new PreloadedData() {
- public Collection<Object> toJson() throws PreloadException {
- throw new PreloadException("test");
- }
- });
-
- pipeline.plainResponses.put(EXPECTED_PROXIED_HTML_HREF, new HttpResponse(PROXIED_HTML_CONTENT));
String content = proxyRenderer.render(makeHrefGadget("none"));
assertEquals(PROXIED_HTML_CONTENT, content);
@@ -240,9 +208,10 @@
assertEquals("POST", lastHttpRequest.getMethod());
assertEquals("application/json;charset=utf-8", lastHttpRequest.getHeader("Content-Type"));
String postBody = lastHttpRequest.getPostBodyAsString();
- JSONArray actualJson = new JSONArray(postBody);
- assertEquals(0, actualJson.length());
+ JSONArray actualJson = new JSONArray(postBody);
+ JsonAssert.assertJsonArrayEquals(prefetchedJson, actualJson);
+ assertTrue(pipelineExecutor.wasPreloaded);
}
private static class FakeHttpCache extends AbstractHttpCache {
@@ -330,21 +299,18 @@
public void normalizeProtocol(HttpRequest request) throws GadgetException { }
}
- private static class FakePreloaderService implements PreloaderService {
+ private static class FakePipelineExecutor extends PipelineExecutor {
protected boolean wasPreloaded;
- protected Collection<PreloadedData> preloads;
-
- protected FakePreloaderService() {
- }
-
- public Collection<PreloadedData> preload(Gadget gadget, PreloadPhase phase) {
- wasPreloaded = true;
- return preloads;
+ protected Results results;
+
+ public FakePipelineExecutor() {
+ super(null, null, null);
}
-
- public Collection<PreloadedData> preload(Collection<Callable<PreloadedData>> tasks) {
+
+ @Override
+ public Results execute(GadgetContext context, Collection<PipelinedData> pipelines) {
wasPreloaded = true;
- return preloads;
+ return results;
}
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriterTest.java?rev=762448&r1=762447&r2=762448&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/PipelineDataContentRewriterTest.java Mon Apr 6 18:25:39 2009
@@ -35,13 +35,13 @@
import org.apache.shindig.gadgets.parse.ParseModule;
import org.apache.shindig.gadgets.parse.nekohtml.SocialMarkupHtmlParser;
import org.apache.shindig.gadgets.preload.ConcurrentPreloaderService;
+import org.apache.shindig.gadgets.preload.PipelineExecutor;
import org.apache.shindig.gadgets.preload.PipelinedDataPreloader;
import org.apache.shindig.gadgets.preload.PreloadException;
import org.apache.shindig.gadgets.preload.PreloadedData;
import org.apache.shindig.gadgets.preload.PreloaderService;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.PipelinedData;
-import org.apache.shindig.gadgets.spec.RequestAuthenticationInfo;
import org.apache.shindig.gadgets.spec.SpecParserException;
import org.easymock.Capture;
import org.easymock.IArgumentMatcher;
@@ -74,37 +74,30 @@
private static final Uri GADGET_URI = Uri.parse("http://example.org/gadget.php");
private static final String CONTENT =
- "<script xmlns:os='http://ns.opensocial.org/2008/markup' type='text/os-data'>"
- + " <os:PeopleRequest key='me' userId='canonical'/>"
- + " <os:HttpRequest key='json' href='test.json'/>"
+ "<script xmlns:os=\"http://ns.opensocial.org/2008/markup\" type=\"text/os-data\">"
+ + " <os:PeopleRequest key=\"me\" userId=\"canonical\"/>"
+ + " <os:HttpRequest key=\"json\" href=\"test.json\"/>"
+ "</script>";
- // Two requests, one depends on the other
- private static final String TWO_BATCH_CONTENT =
- "<script xmlns:os='http://ns.opensocial.org/2008/markup' type='text/os-data'>"
- + " <os:PeopleRequest key='me' userId='${json.user}'/>"
- + " <os:HttpRequest key='json' href='${ViewParams.file}'/>"
- + "</script>";
-
- // One request, but it requires data that isn't present
+ // One request, but it requires data that isn\"t present
private static final String BLOCKED_FIRST_BATCH_CONTENT =
- "<script xmlns:os='http://ns.opensocial.org/2008/markup' type='text/os-data'>"
- + " <os:PeopleRequest key='me' userId='${json.user}'/>"
+ "<script xmlns:os=\"http://ns.opensocial.org/2008/markup\" type=\"text/os-data\">"
+ + " <os:PeopleRequest key=\"me\" userId=\"${json.user}\"/>"
+ "</script>";
- private static final String XML_WITHOUT_FEATURE = "<Module>" + "<ModulePrefs title='Title'>"
+ private static final String XML_WITHOUT_FEATURE = "<Module>" + "<ModulePrefs title=\"Title\">"
+ "</ModulePrefs>" + "<Content>" + " <![CDATA[" + CONTENT + "]]></Content></Module>";
- private static final String XML_WITHOUT_PIPELINE = "<Module>" + "<ModulePrefs title='Title'>"
- + "<Require feature='opensocial-data'/>" + "</ModulePrefs>" + "<Content/></Module>";
+ private static final String XML_WITHOUT_PIPELINE = "<Module>" + "<ModulePrefs title=\"Title\">"
+ + "<Require feature=\"opensocial-data\"/>" + "</ModulePrefs>" + "<Content/></Module>";
@Before
public void setUp() throws Exception {
control = EasyMock.createStrictControl();
preloader = control.createMock(PipelinedDataPreloader.class);
preloaderService = new ConcurrentPreloaderService(Executors.newSingleThreadExecutor(), null);
- rewriter = new PipelineDataContentRewriter(preloader, preloaderService,
- new Expressions());
+ rewriter = new PipelineDataContentRewriter(new PipelineExecutor(preloader, preloaderService,
+ new Expressions()));
}
private void setupGadget(String gadgetXml) throws SpecParserException {
@@ -151,69 +144,6 @@
control.verify();
}
-
- @Test
- public void rewriteWithTwoBatches() throws Exception {
- setupGadget(getGadgetXml(TWO_BATCH_CONTENT));
-
- gadget.setContext(new GadgetContext() {
- @Override
- public String getParameter(String property) {
- // Provide the filename to be requested in the first batch
- if ("view-params".equals(property)) {
- return "{'file': 'test.json'}";
- }
- return null;
- }
- });
-
- // First batch, the HTTP fetch
- Capture<PipelinedData.Batch> firstBatch =
- new Capture<PipelinedData.Batch>();
- Callable<PreloadedData> firstTask = createPreloadTask("json",
- "{data: {user: 'canonical'}}");
-
- // Second batch, the user fetch
- Capture<PipelinedData.Batch> secondBatch =
- new Capture<PipelinedData.Batch>();
- Callable<PreloadedData> secondTask = createPreloadTask("me",
- "{data: {'id':'canonical'}}");
-
- // First, a batch with an HTTP request
- expect(
- preloader.createPreloadTasks(same(gadget.getContext()),
- and(eqBatch(0, 1), capture(firstBatch))))
- .andReturn(ImmutableList.of(firstTask));
- // Second, a batch with a social request
- expect(
- preloader.createPreloadTasks(same(gadget.getContext()),
- and(eqBatch(1, 0), capture(secondBatch))))
- .andReturn(ImmutableList.of(secondTask));
-
- control.replay();
-
- rewriter.rewrite(gadget, content);
-
- control.verify();
-
- // Verify the data set is injected, and the os-data was deleted
- assertTrue("First batch not inserted", content.getContent().contains("DataContext.putDataSet(\"json\",{\"user\":\"canonical\"})"));
- assertTrue("Second batch not inserted", content.getContent().contains("DataContext.putDataSet(\"me\",{\"id\":\"canonical\"})"));
- assertFalse("os-data wasn't deleted",
- content.getContent().contains("type=\"text/os-data\""));
-
- // Check the evaluated HTTP request
- RequestAuthenticationInfo request = firstBatch.getValue().getHttpPreloads().get("json");
- assertEquals("http://example.org/test.json", request.getHref().toString());
-
- // Check the evaluated person request
- JSONObject personRequest = (JSONObject) secondBatch.getValue().getSocialPreloads().get("me");
- assertEquals("canonical", personRequest.getJSONObject("params").getJSONArray("userId").get(0));
-
- assertEquals(ImmutableSet.of("opensocial-data"), gadget.getRemovedFeatures());
- assertEquals(ImmutableSet.of("opensocial-data-context"), gadget.getAddedFeatures());
- }
-
@Test
public void rewriteWithBlockedBatch() throws Exception {
setupGadget(getGadgetXml(BLOCKED_FIRST_BATCH_CONTENT));