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>