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/02/08 12:48:25 UTC

svn commit: r619845 - in /incubator/shindig/trunk: java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ javascript/container/

Author: etnu
Date: Fri Feb  8 03:48:23 2008
New Revision: 619845

URL: http://svn.apache.org/viewvc?rev=619845&view=rev
Log:
Initial commit of RpcServlet. This version only handles JSON (no XML), and it's error handling is kind of rough. I've also included a simple demo page showing how you can use the rpc from javascript, though in practice you'll probably actually want to do this from your server-side programming language of choice so that you can inject security tokens and other custom data.


Added:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcContext.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadget.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcProcessingOptions.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcException.java
    incubator/shindig/trunk/javascript/container/sample-rpc.html
Modified:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java?rev=619845&r1=619844&r2=619845&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java Fri Feb  8 03:48:23 2008
@@ -95,6 +95,10 @@
   /**
    * Constructs a url for generating an iframe for the given gadget.
    * This only applies for RPC calls that must generate an iframe.
+   *
+   * TODO: The second parameter here should be something else (perhaps a
+   * context object). A better choice would probably be to add the view params
+   * to ProcessingOptions and pass that here.
    */
   public abstract String getIframeUrl(Gadget gadget,  HttpServletRequest req);
 

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java?rev=619845&r1=619844&r2=619845&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java Fri Feb  8 03:48:23 2008
@@ -34,6 +34,7 @@
 import org.apache.shindig.gadgets.JsLibraryFeatureFactory;
 import org.apache.shindig.gadgets.MessageBundle;
 import org.apache.shindig.gadgets.RenderingContext;
+import org.apache.shindig.gadgets.UserPrefs;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
@@ -85,11 +86,30 @@
     // We don't have any meaningful data in the current request anyway, so
     // we'll just do this statically.
     StringBuilder buf = new StringBuilder();
+
     try {
-      buf.append(iframePath)
-          .append("url=")
-          .append(
-              URLEncoder.encode(gadget.getId().getURI().toString(),"UTF-8"));
+      String url = gadget.getId().getURI().toString();
+      if (gadget.getContentType().equals(GadgetSpec.ContentType.HTML)) {
+        buf.append(iframePath)
+           .append("url=")
+           .append(URLEncoder.encode(url, "UTF-8"));
+      } else {
+        // type = url
+        buf.append(url);
+        if (url.indexOf('?') == -1) {
+          buf.append('?');
+        } else {
+          buf.append('&');
+        }
+      }
+
+      UserPrefs prefs = gadget.getUserPrefValues();
+      for (Map.Entry<String, String> entry : prefs.getPrefs().entrySet()) {
+        buf.append("&up_")
+           .append(entry.getKey())
+           .append("=")
+           .append(URLEncoder.encode(entry.getValue(), "UTF-8"));
+      }
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException("UTF-8 Not supported!", e);
     }

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcContext.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcContext.java?rev=619845&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcContext.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcContext.java Fri Feb  8 03:48:23 2008
@@ -0,0 +1,64 @@
+/*
+ * 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.http;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Handles pulling out context from a JSON object.
+ */
+public class JsonRpcContext {
+  private final String language;
+  private final String country;
+  private final String view;
+  private final boolean ignoreCache;
+
+  public String getLanguage() {
+    return language;
+  }
+
+  public String getCountry() {
+    return country;
+  }
+
+  public String getView() {
+    return view;
+  }
+
+  public boolean getIgnoreCache() {
+    return ignoreCache;
+  }
+
+  /**
+   * @param json
+   * @throws JSONException
+   */
+  public JsonRpcContext(JSONObject json) throws JSONException {
+    language = json.getString("language");
+    country = json.getString("country");
+    view = json.getString("view");
+    if (json.has("ignoreCache")) {
+      ignoreCache = json.getBoolean("ignoreCache");
+    } else {
+      ignoreCache = false;
+    }
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadget.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadget.java?rev=619845&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadget.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadget.java Fri Feb  8 03:48:23 2008
@@ -0,0 +1,67 @@
+/*
+ * 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.http;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents an individual gadget.
+ */
+public class JsonRpcGadget {
+  private final String url;
+  public String getUrl() {
+    return url;
+  }
+
+  private final int moduleId;
+  public int getModuleId() {
+    return moduleId;
+  }
+
+  private final Map<String, String> userPrefs;
+  public Map<String, String> getUserPrefs() {
+    return userPrefs;
+  }
+
+  public JsonRpcGadget(JSONObject json) throws JSONException {
+    url = json.getString("url");
+    moduleId = json.getInt("moduleId");
+
+    JSONObject tmpObj = json.optJSONObject("userPrefs");
+    if (tmpObj == null) {
+     userPrefs = Collections.emptyMap();
+    } else {
+      JSONArray keyNames = tmpObj.names();
+      Map<String, String> prefs = new HashMap<String, String>();
+      for (int i = 0, j = keyNames.length(); i < j; ++i) {
+        String key = keyNames.getString(i);
+        String value = tmpObj.getString(key);
+        prefs.put(key, value);
+      }
+      userPrefs = Collections.unmodifiableMap(prefs);
+    }
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java?rev=619845&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java Fri Feb  8 03:48:23 2008
@@ -0,0 +1,71 @@
+/*
+ * 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.http;
+
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetServer;
+import org.apache.shindig.gadgets.GadgetView;
+import org.apache.shindig.gadgets.RenderingContext;
+import org.apache.shindig.gadgets.UserPrefs;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Locale;
+import java.util.concurrent.Callable;
+
+/**
+ * Handles processing a single gadget
+ */
+public class JsonRpcGadgetJob implements Callable<Gadget> {
+  private final GadgetServer gadgetServer;
+  private final JsonRpcContext context;
+  private final JsonRpcGadget gadget;
+
+  /**
+   * {@inheritDoc}
+   *
+   *  @throws RpcException
+   */
+  public Gadget call() throws RpcException {
+    GadgetView.ID gadgetId;
+    try {
+      gadgetId = new Gadget.GadgetId(new URI(gadget.getUrl()),
+                                     gadget.getModuleId());
+      return gadgetServer.processGadget(gadgetId,
+                                        new UserPrefs(gadget.getUserPrefs()),
+                                        new Locale(context.getLanguage(),
+                                                   context.getCountry()),
+                                        RenderingContext.CONTAINER,
+                                        new JsonRpcProcessingOptions(context));
+    } catch (URISyntaxException e) {
+      throw new RpcException("Bad url");
+    } catch (GadgetServer.GadgetProcessException e) {
+      throw new RpcException("Failed to process gadget.", e);
+    }
+  }
+
+  public JsonRpcGadgetJob(GadgetServer gadgetServer,
+                          JsonRpcContext context,
+                          JsonRpcGadget gadget) {
+    this.gadgetServer = gadgetServer;
+    this.context = context;
+    this.gadget = gadget;
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcProcessingOptions.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcProcessingOptions.java?rev=619845&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcProcessingOptions.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcProcessingOptions.java Fri Feb  8 03:48:23 2008
@@ -0,0 +1,38 @@
+/*
+ * 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.http;
+
+import org.apache.shindig.gadgets.ProcessingOptions;
+
+/**
+ * Extracts processing options from the request context.
+ */
+public class JsonRpcProcessingOptions extends ProcessingOptions {
+  private final JsonRpcContext context;
+
+  @Override
+  public boolean getIgnoreCache() {
+    return context.getIgnoreCache();
+  }
+
+  public JsonRpcProcessingOptions(JsonRpcContext context) {
+    this.context = context;
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.java?rev=619845&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.java Fri Feb  8 03:48:23 2008
@@ -0,0 +1,156 @@
+/*
+ * 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.http;
+
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.GadgetServer;
+import org.apache.shindig.gadgets.GadgetSpec;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+
+/**
+ * Validates and wraps a JSON input object into a
+ *
+ */
+public class JsonRpcRequest {
+  private final JsonRpcContext context;
+  private final List<JsonRpcGadget> gadgets;
+
+  /**
+   * Processes the request and returns a JSON object
+   * That can be emitted as output.
+   */
+  public JSONObject process(CrossServletState servletState)
+      throws RpcException {
+    GadgetServer server = servletState.getGadgetServer();
+
+    JSONObject out = new JSONObject();
+
+    // Dispatch a separate thread for each gadget that we wish to render.
+    CompletionService<Gadget> processor =
+      new ExecutorCompletionService<Gadget>(server.getConfig().getExecutor());
+
+    for (JsonRpcGadget gadget : gadgets) {
+      processor.submit(new JsonRpcGadgetJob(server, context, gadget));
+    }
+
+    int numJobs = gadgets.size();
+    do {
+      try {
+        Gadget outGadget = processor.take().get();
+        JSONObject gadgetJson = new JSONObject();
+
+        if (outGadget.getTitleURI() != null) {
+          gadgetJson.put("titleUrl", outGadget.getTitleURI().toString());
+        }
+        gadgetJson.put("url", outGadget.getId().getURI().toString())
+                  .put("moduleId", outGadget.getId().getModuleId())
+                  .put("title", outGadget.getTitle())
+                  .put("contentType",
+                      outGadget.getContentType().toString().toLowerCase());
+
+        // Features.
+        gadgetJson.put("features", new JSONArray());
+        for (String feature : outGadget.getRequires().keySet()) {
+          gadgetJson.append("features", feature);
+        }
+
+        JSONObject prefs = new JSONObject();
+
+        // User pref specs
+        for (GadgetSpec.UserPref pref : outGadget.getUserPrefs()) {
+          JSONObject up = new JSONObject()
+              .put("displayName", pref.getDisplayName())
+              .put("type", pref.getDataType().toString().toLowerCase())
+              .put("default", pref.getDefaultValue())
+              .put("enumValues", pref.getEnumValues());
+        }
+        gadgetJson.put("userPrefs", prefs);
+
+        // Content
+        String iframeUrl = servletState.getIframeUrl(outGadget, null);
+        gadgetJson.put("content", iframeUrl);
+        out.append("gadgets", gadgetJson);
+      } catch (InterruptedException e) {
+        throw new RpcException("Incomplete processing", e);
+      } catch (ExecutionException e) {
+        throw new RpcException("Incomplete processing", e);
+      } catch (RuntimeException rte) {
+        if (!(rte.getCause() instanceof RpcException)) {
+          throw rte;
+        }
+        RpcException e = (RpcException)rte.getCause();
+        // Just one gadget failed; mark it as such.
+        try {
+          JSONObject errorObj = new JSONObject();
+          errorObj.put("url", e.getGadget().getUrl())
+                  .put("moduleId", e.getGadget().getModuleId());
+          if (e.getCause() instanceof GadgetServer.GadgetProcessException) {
+            GadgetServer.GadgetProcessException gpe
+                = (GadgetServer.GadgetProcessException)e.getCause();
+            for (GadgetException ge : gpe.getComponents()) {
+              errorObj.append("errors", e.getMessage());
+            }
+          } else {
+            errorObj.append("errors", e.getMessage());
+          }
+          out.append("gadgets", errorObj);
+        } catch (JSONException je) {
+          throw new RpcException("Unable to write JSON", je);
+        }
+      } catch (JSONException e) {
+        throw new RpcException("Unable to write JSON", e);
+      } finally {
+        numJobs--;
+      }
+    } while (numJobs > 0);
+
+    return out;
+  }
+
+  public JsonRpcRequest(String content) throws RpcException {
+    try {
+      JSONObject json = new JSONObject(content);
+      JSONObject context = json.getJSONObject("context");
+      JSONArray gadgets = json.getJSONArray("gadgets");
+      if (gadgets.length() == 0) {
+        throw new RpcException("No gadgets requested.");
+      }
+      this.context = new JsonRpcContext(context);
+
+      List<JsonRpcGadget> gadgetList = new LinkedList<JsonRpcGadget>();
+      for (int i = 0, j = gadgets.length(); i < j; ++i) {
+        gadgetList.add(new JsonRpcGadget(gadgets.getJSONObject(i)));
+      }
+      this.gadgets = Collections.unmodifiableList(gadgetList);
+    } catch (JSONException e) {
+      throw new RpcException("Malformed JSON input.", e);
+    }
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcException.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcException.java?rev=619845&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcException.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcException.java Fri Feb  8 03:48:23 2008
@@ -0,0 +1,46 @@
+/*
+ * 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.http;
+
+/**
+ * Contains RPC-specific exceptions.
+ */
+public class RpcException extends Exception {
+  private final JsonRpcGadget gadget;
+
+  public JsonRpcGadget getGadget() {
+    return gadget;
+  }
+
+  public RpcException(String message) {
+    super(message);
+    gadget = null;
+  }
+
+  public RpcException(String message, Throwable cause) {
+    super(message, cause);
+    gadget = null;
+  }
+
+  public RpcException(JsonRpcGadget gadget, Throwable cause) {
+    super(cause);
+    this.gadget = gadget;
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java?rev=619845&r1=619844&r2=619845&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcServlet.java Fri Feb  8 03:48:23 2008
@@ -19,10 +19,17 @@
 
 package org.apache.shindig.gadgets.http;
 
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -32,17 +39,63 @@
  */
 public class RpcServlet extends HttpServlet {
   private CrossServletState state;
+  private static final int MAX_REQUEST_SIZE = 1024 * 128;
+  private static final Logger logger
+      = Logger.getLogger("org.apache.shindig.gadgets");
 
   @Override
-  protected void doGet(HttpServletRequest request, HttpServletResponse response)
-      throws ServletException, IOException {
+  protected void doPost(HttpServletRequest request,
+      HttpServletResponse response) throws IOException {
+    int length = request.getContentLength();
+    if (length <= 0) {
+      logger.info("No Content-Length specified.");
+      response.setStatus(HttpServletResponse.SC_LENGTH_REQUIRED);
+      return;
+    }
+    if (length > MAX_REQUEST_SIZE) {
+      logger.info("Request size too large: " + length);
+      response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
+      return;
+    }
+
+    ServletInputStream reader = request.getInputStream();
+    ByteArrayOutputStream os = new ByteArrayOutputStream();
+    byte[] buf = new byte[1024 * 8];
+    int read = 0;
+
+    while ((read = reader.read(buf, 0, buf.length)) > 0) {
+      os.write(buf, 0, read);
+      if (os.size() > length) {
+        // Bad request, we're leaving now.
+        logger.info("Wrong size. Length: " + length + " real: " + os.size());
+        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+        return;
+      }
+    }
+
+    try {
+      String encoding = request.getCharacterEncoding();
+      if (encoding == null) {
+        encoding = "UTF-8";
+      }
+      String postBody = new String(os.toByteArray(), encoding);
+      JsonRpcRequest req = new JsonRpcRequest(postBody);
+      JSONObject out = req.process(state);
+      response.setStatus(HttpServletResponse.SC_OK);
+      response.getWriter().write(out.toString());
+    } catch (UnsupportedEncodingException e) {
+      response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+      response.getWriter().write("Unsupported input character set");
+      logger.log(Level.INFO, e.getMessage(), e);
+    } catch (RpcException e) {
+      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+      response.getWriter().write(e.getMessage());
+      logger.log(Level.INFO, e.getMessage(), e);
+    }
   }
 
   @Override
   public void init(ServletConfig config) throws ServletException {
     state = CrossServletState.get(config);
-  }
-
-  public RpcServlet() {
   }
 }

Added: incubator/shindig/trunk/javascript/container/sample-rpc.html
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/javascript/container/sample-rpc.html?rev=619845&view=auto
==============================================================================
--- incubator/shindig/trunk/javascript/container/sample-rpc.html (added)
+++ incubator/shindig/trunk/javascript/container/sample-rpc.html Fri Feb  8 03:48:23 2008
@@ -0,0 +1,92 @@
+<html>
+<head>
+<title>RPC Demo</title>
+<style>
+  .gadget {
+    border: solid 1px #000;
+    margin: 10px;
+    float: left;
+    text-align: center;
+  }
+  .gadget h2 {
+    background: #ccf;
+    border-bottom: solid 1px #000;
+    margin: 0;
+    padding: 5px;
+  }
+  .gadget iframe {
+    margin: 5px;
+    border: none;
+    height: 300px;
+    width: 300px;
+  }
+</style>
+</head>
+<body>
+<script src="../../js/core.js"></script>
+<script>
+  function makeXhr() {
+    if (window.XMLHttpRequest) {
+      return new XMLHttpRequest();
+    } else if (window.ActiveXObject) {
+      var x = new ActiveXObject("Msxml2.XMLHTTP");
+      if (!x) {
+        x = new ActiveXObject("Microsoft.XMLHTTP");
+      }
+      return x;
+    }
+  }
+
+  function renderGadgets(obj) {
+    var gadgetList = obj.gadgets;
+    var features = {};
+    for (var i = 0, gadget; gadget = gadgetList[i]; ++i) {
+      for (var j = 0, feature; feature = gadget.features[i]; ++i) {
+        features[feature] = true;
+      }
+    }
+    var libs = [];
+    for (var lib in features) {libs.push(lib);}
+    libs.sort();
+    libs = libs.join("");
+    for (var i = 0, gadget; gadget = gadgetList[i]; ++i) {
+      var newGadget = document.createElement("div");
+      newGadget.innerHTML = ['<h2>', gadget.title, '</h2>',
+        '<iframe src="', gadget.content, '&libs=', libs ,'" id="remote_iframe_', gadget.moduleId, '"></iframe>'
+      ].join("");
+      newGadget.className = "gadget";
+      document.body.appendChild(newGadget);
+    }
+  }
+
+  function processResp(xhr, callback) {
+    if (xhr.readyState !== 4) {return;}
+    callback(gadgets.json.parse(xhr.responseText));
+  }
+
+  var request = {
+    context: {
+      country: "US",
+      language: "en",
+      view: "default"
+    },
+    gadgets: [
+      {
+        url: "http://www.google.com/ig/modules/hello.xml",
+        moduleId: 1
+      },
+      {
+        url: "http://www.labpixies.com/campaigns/todo/todo.xml",
+        moduleId: 2
+      }
+    ]
+  };
+
+  var xhr = makeXhr();
+  xhr.open("POST", "../../rpc", true);
+  xhr.onreadystatechange = gadgets.util.makeClosure(null, processResp, xhr, renderGadgets);
+  var req = gadgets.json.stringify(request);
+  xhr.send(req);
+</script>
+</body>
+</html>