You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by fm...@apache.org on 2011/05/30 21:49:18 UTC

svn commit: r1129323 - in /tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main: java/org/apache/tuscany/sca/binding/comet/runtime/ java/org/apache/tuscany/sca/binding/comet/runtime/handler/ java/org/apache/tuscany/sca/binding/comet/runtim...

Author: fmoga
Date: Mon May 30 19:49:17 2011
New Revision: 1129323

URL: http://svn.apache.org/viewvc?rev=1129323&view=rev
Log:
Move from relying on the HTTP session to manual session management using sessionIds generated by the javascript on page load.

Added:
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js
Removed:
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java
Modified:
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java
    tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js

Modified: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java?rev=1129323&r1=1129322&r2=1129323&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java Mon May 30 19:49:17 2011
@@ -21,6 +21,7 @@ package org.apache.tuscany.sca.binding.c
 
 import org.apache.tuscany.sca.assembly.EndpointReference;
 import org.apache.tuscany.sca.binding.comet.runtime.callback.Status;
+import org.apache.tuscany.sca.binding.comet.runtime.manager.CometSessionManager;
 import org.apache.tuscany.sca.core.invocation.Constants;
 import org.apache.tuscany.sca.core.invocation.impl.MessageImpl;
 import org.apache.tuscany.sca.interfacedef.Operation;
@@ -28,37 +29,39 @@ import org.apache.tuscany.sca.invocation
 import org.apache.tuscany.sca.invocation.Message;
 import org.atmosphere.cpr.Broadcaster;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
 public class CometInvoker implements Invoker {
 
-	protected Operation operation;
-	protected EndpointReference endpoint;
+    private static Gson gson = new GsonBuilder().serializeNulls().create();
+
+    protected Operation operation;
+    protected EndpointReference endpoint;
+
+    public CometInvoker(final Operation operation, final EndpointReference endpoint) {
+        this.operation = operation;
+        this.endpoint = endpoint;
+    }
+
+    @Override
+    public Message invoke(final Message msg) {
+        String sessionId = (String) msg.getHeaders().get(Constants.RELATES_TO);
+        Broadcaster broadcaster = CometSessionManager.get(sessionId);
+        Message response = new MessageImpl();
+        if (broadcaster == null) {
+            response.setBody(Status.CLIENT_DISCONNECTED);
+        } else if (broadcaster.getAtmosphereResources().isEmpty()) {
+            CometSessionManager.remove(sessionId);
+            response.setBody(Status.CLIENT_DISCONNECTED);
+        } else {
+            String callbackMethod = msg.getTo().getURI();
+            Object[] body = msg.getBody();
+            broadcaster.broadcast(callbackMethod + "($.secureEvalJSON('" + gson.toJson(body[0]) + "'))");
+            response.setBody(Status.OK);
+        }
+        return response;
+
+    }
 
-	public CometInvoker(final Operation operation, final EndpointReference endpoint) {
-		this.operation = operation;
-		this.endpoint = endpoint;
-	}
-
-	@Override
-	public Message invoke(final Message msg) {
-		return handleSendMessage(msg);
-	}
-
-	private Message handleSendMessage(Message msg) {
-		String sessionId = (String) msg.getHeaders().get(Constants.RELATES_TO);
-		Broadcaster broadcaster = CometComponentContext.broadcasters.get(sessionId);
-		Message response = new MessageImpl();
-		if (broadcaster == null) {
-			response.setBody(Status.CLIENT_DISCONNECTED);
-		} else if (broadcaster.getAtmosphereResources().isEmpty()) {
-			CometComponentContext.broadcasters.remove(sessionId);
-			response.setBody(Status.CLIENT_DISCONNECTED);
-		} else {
-			String callbackMethod = msg.getTo().getURI();
-			Object[] body = msg.getBody();
-			broadcaster.broadcast(callbackMethod + "($.secureEvalJSON('" + CometComponentContext.gson.toJson(body[0])
-					+ "'))");
-			response.setBody(Status.OK);
-		}
-		return response;
-	}
 }

Modified: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java?rev=1129323&r1=1129322&r2=1129323&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java Mon May 30 19:49:17 2011
@@ -21,6 +21,9 @@ package org.apache.tuscany.sca.binding.c
 
 import org.apache.tuscany.sca.assembly.ComponentService;
 import org.apache.tuscany.sca.binding.comet.runtime.javascript.JavascriptGenerator;
+import org.apache.tuscany.sca.binding.comet.runtime.manager.CometEndpointManager;
+import org.apache.tuscany.sca.binding.comet.runtime.manager.CometOperationManager;
+import org.apache.tuscany.sca.binding.comet.runtime.manager.CometSessionManager;
 import org.apache.tuscany.sca.host.http.ServletHost;
 import org.apache.tuscany.sca.interfacedef.Interface;
 import org.apache.tuscany.sca.interfacedef.InterfaceContract;
@@ -33,32 +36,14 @@ import org.apache.tuscany.sca.runtime.Ru
  */
 public class CometServiceBindingProvider implements ServiceBindingProvider {
 
-	/**
-	 * Service's endpoint.
-	 */
 	private final RuntimeEndpoint endpoint;
-
-	/**
-	 * The underlying servlet host.
-	 */
 	private final ServletHost servletHost;
 
-	/**
-	 * Constructor.
-	 * 
-	 * @param endpoint
-	 *            the given endpoint
-	 * @param servletHost
-	 *            the given servlet host
-	 */
 	public CometServiceBindingProvider(final RuntimeEndpoint endpoint, final ServletHost servletHost) {
 		this.endpoint = endpoint;
 		this.servletHost = servletHost;
 	}
 
-	/**
-	 * This method is used to start the provider.
-	 */
 	@Override
 	public void start() {
 		String deployedURI = ServletFactory.registerServlet(this.servletHost);
@@ -67,8 +52,10 @@ public class CometServiceBindingProvider
 		final Interface serviceInterface = service.getInterfaceContract().getInterface();
 		JavascriptGenerator.generateServiceProxy(service);
 		for (final Operation operation : serviceInterface.getOperations()) {
+			final String url = "/" + endpoint.getService().getName() + "/" + operation.getName();
+			CometEndpointManager.add(url, endpoint);
+			CometOperationManager.add(url, operation);
 			JavascriptGenerator.generateMethodProxy(service, operation);
-			ServletFactory.registerOperation(this.endpoint, operation);
 		}
 	}
 
@@ -78,6 +65,9 @@ public class CometServiceBindingProvider
 	@Override
 	public void stop() {
 		ServletFactory.unregisterServlet(this.servletHost);
+		CometEndpointManager.clear();
+		CometOperationManager.clear();
+		CometSessionManager.clear();
 	}
 
 	@Override

Modified: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java?rev=1129323&r1=1129322&r2=1129323&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java Mon May 30 19:49:17 2011
@@ -20,8 +20,6 @@
 package org.apache.tuscany.sca.binding.comet.runtime;
 
 import org.apache.tuscany.sca.host.http.ServletHost;
-import org.apache.tuscany.sca.interfacedef.Operation;
-import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
 import org.atmosphere.cpr.AtmosphereServlet;
 
 /**
@@ -84,15 +82,7 @@ public final class ServletFactory {
 	private ServletFactory() {
 	}
 
-	/**
-	 * Method called by CometServiceBindingProvider for each endpoint in order
-	 * to create the two singleton servlets.
-	 * 
-	 * @param servletHost
-	 *            the underlying servlet host
-	 */
-	public static synchronized String registerServlet(
-			final ServletHost servletHost) {
+	public static synchronized String registerServlet(final ServletHost servletHost) {
 		String uri = registerCometServlet(servletHost);
 		registerJavascriptServlet(servletHost);
 		return uri;
@@ -101,61 +91,25 @@ public final class ServletFactory {
 	private static String registerCometServlet(ServletHost servletHost) {
 		if (ServletFactory.cometServlet == null) {
 			ServletFactory.cometServlet = new AtmosphereServlet();
-			ServletFactory.cometServlet.addInitParameter(
-					ServletFactory.PACKAGE_KEY, ServletFactory.PACKAGE_VALUE);
-			String uri = servletHost.addServletMapping(ServletFactory.PATH,
-					ServletFactory.cometServlet);
-			final CometComponentContext context = new CometComponentContext();
-			ServletFactory.cometServlet.getServletContext().setAttribute(
-					ServletFactory.COMET_COMPONENT_CONTEXT_KEY, context);
+			ServletFactory.cometServlet.addInitParameter(ServletFactory.PACKAGE_KEY, ServletFactory.PACKAGE_VALUE);
+			String uri = servletHost.addServletMapping(ServletFactory.PATH, ServletFactory.cometServlet);
 			return uri;
-		} else {
-		    return null;
 		}
+		return null;
 	}
 
 	private static void registerJavascriptServlet(ServletHost servletHost) {
 		if (ServletFactory.javascriptServlet == null) {
 			ServletFactory.javascriptServlet = new AtmosphereServlet();
-			ServletFactory.javascriptServlet
-					.addInitParameter(ServletFactory.PACKAGE_KEY,
-							ServletFactory.JS_PACKAGE_VALUE);
-			servletHost.addServletMapping(ServletFactory.JS_PATH,
-					ServletFactory.javascriptServlet);
+			ServletFactory.javascriptServlet.addInitParameter(ServletFactory.PACKAGE_KEY,
+					ServletFactory.JS_PACKAGE_VALUE);
+			servletHost.addServletMapping(ServletFactory.JS_PATH, ServletFactory.javascriptServlet);
 		}
 	}
 
-	/**
-	 * Method called by CometServiceBindingProvider for each endpoint operation
-	 * in order to store all the operations the servlet will serve.
-	 * 
-	 * @param endpoint
-	 *            the endpoint
-	 * @param operation
-	 *            the operation
-	 */
-	public static void registerOperation(final RuntimeEndpoint endpoint,
-			final Operation operation) {
-		final String url = "/" + endpoint.getService().getName() + "/"
-				+ operation.getName();
-		CometComponentContext context = (CometComponentContext) cometServlet
-				.getServletContext().getAttribute(COMET_COMPONENT_CONTEXT_KEY);
-		context.addEndpoint(url, endpoint);
-		context.addOperation(url, operation);
-	}
-
-	/**
-	 * Method called by CometServiceBindingProvider for each endpoint operation
-	 * in order to remove the two servlets.
-	 * 
-	 * @param servletHost
-	 *            the underlying servlet host
-	 */
 	public static void unregisterServlet(final ServletHost servletHost) {
-		synchronized (servletHost) {
-			servletHost.removeServletMapping(ServletFactory.PATH);
-			servletHost.removeServletMapping(ServletFactory.JS_PATH);
-		}
+		servletHost.removeServletMapping(ServletFactory.PATH);
+		servletHost.removeServletMapping(ServletFactory.JS_PATH);
 	}
 
 }

Modified: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java?rev=1129323&r1=1129322&r2=1129323&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java Mon May 30 19:49:17 2011
@@ -19,26 +19,21 @@
 
 package org.apache.tuscany.sca.binding.comet.runtime.handler;
 
-import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.UUID;
 
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
+import javax.ws.rs.QueryParam;
 
 import org.apache.tuscany.sca.assembly.EndpointReference;
-import org.apache.tuscany.sca.binding.comet.runtime.CometComponentContext;
-import org.apache.tuscany.sca.binding.comet.runtime.ServletFactory;
+import org.apache.tuscany.sca.binding.comet.runtime.manager.CometEndpointManager;
+import org.apache.tuscany.sca.binding.comet.runtime.manager.CometOperationManager;
+import org.apache.tuscany.sca.binding.comet.runtime.manager.CometSessionManager;
 import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointImpl;
 import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointReferenceImpl;
 import org.apache.tuscany.sca.core.invocation.Constants;
@@ -51,186 +46,131 @@ import org.atmosphere.cpr.Broadcaster;
 import org.atmosphere.jersey.JerseyBroadcaster;
 import org.atmosphere.jersey.SuspendResponse;
 
-import com.sun.jersey.spi.container.servlet.PerSession;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 
-/**
- * Class serving calls coming for comet services and operations.
- */
 @Path("/")
-@Produces("text/html;charset=ISO-8859-1")
-@PerSession
-public class CometBindingHandler implements Serializable {
-
-	/**
-	 * The object used to suspend the response and send async responses back to
-	 * client.
-	 */
-	private Broadcaster broadcaster;
-
-	/**
-	 * The underlying servlet context.
-	 */
-	@Context
-	private ServletContext sc;
-
-	@Context
-	private HttpServletRequest request;
-
-	private CometComponentContext context;
-
-	@GET
-	@Path("/sessionId")
-	@Produces(MediaType.TEXT_PLAIN)
-	public String establishSessionId() {
-		request.getSession().invalidate();
-		request.getSession(true);
-		return "OK";
-	}
-
-	/**
-	 * Method called at comet connect time. This suspends the response and keeps
-	 * the connection opened.
-	 * 
-	 * @return the suspended response
-	 */
-	@GET
-	@Path("/connect")
-	public SuspendResponse<String> connect() {
-		// System.out.println("-- connect -- Session Id: " +
-		// request.getSession().getId());
-		if (broadcaster == null) {
-			broadcaster = new JerseyBroadcaster(UUID.randomUUID().toString());
-			// broadcaster.setBroadcasterLifeCyclePolicy(new
-			// Builder().policy(ATMOSPHERE_RESOURCE_POLICY.IDLE_DESTROY)
-			// .idleTimeInMS(5000).build());
-			context = (CometComponentContext) sc.getAttribute(ServletFactory.COMET_COMPONENT_CONTEXT_KEY);
-		}
-		CometComponentContext.broadcasters.put(request.getSession().getId(), broadcaster);
-		return new SuspendResponse.SuspendResponseBuilder<String>().broadcaster(this.broadcaster).outputComments(true)
-				.build();
-	}
-
-	/**
-	 * Method called on service calls.
-	 * 
-	 * @param service
-	 *            service called
-	 * @param method
-	 *            operation called
-	 * @param callbackMethod
-	 *            the callback method from Javascript
-	 * @param jsonData
-	 *            arguments for the method sent as JSON array
-	 * @return object used by the Broadcaster to send response through the
-	 *         persisted connection
-	 * @throws InvocationTargetException
-	 *             if problems occur at service invocation
-	 */
-	@POST
-	@Path("/{service}/{method}")
-	public void handleRequest(@PathParam("service") final String service, @PathParam("method") final String method,
-			@FormParam("callbackMethod") final String callbackMethod, @FormParam("params") final String jsonData)
-			throws InvocationTargetException {
-		// System.out.println("-- handleRequest -- Session Id: " +
-		// request.getSession().getId());
-		final String url = "/" + service + "/" + method;
-		final RuntimeEndpoint wire = context.getEndpoint(url);
-		final Operation operation = context.getOperation(url);
-
-		final Object[] args = decodeJsonDataForOperation(jsonData, operation);
-		Message msg = createMessageWithMockedCometReference(args, callbackMethod);
-		boolean isVoidReturnType = operation.getOutputType().getLogical().isEmpty();
-		if (!isVoidReturnType) {
-			Object response = wire.invoke(operation, args);
-			broadcaster.broadcast(callbackMethod + "($.secureEvalJSON('" + CometComponentContext.gson.toJson(response)
-					+ "'))");
-			if (broadcaster.getAtmosphereResources().isEmpty()) {
-				CometComponentContext.broadcasters.remove(request.getSession().getId());
-			}
-		} else {
-			wire.invoke(operation, msg);
-		}
-	}
-
-	/**
-	 * Convert request parameters from JSON to operation parameter types.
-	 * 
-	 * @param jsonData
-	 * @param operation
-	 * @return
-	 */
-	private Object[] decodeJsonDataForOperation(String jsonData, Operation operation) {
-		Object[] args = new Object[operation.getInputType().getLogical().size()];
-		final String[] json = this.parseArray(jsonData);
-		int index = 0;
-		// convert each argument to the corresponding class
-		for (final DataType<?> dataType : operation.getInputType().getLogical()) {
-			args[index] = CometComponentContext.gson.fromJson(json[index], dataType.getPhysical());
-			index++;
-		}
-		return args;
-	}
-
-	/**
-	 * Creates the message to be sent with a mocked EndpointReference in the
-	 * 'from' field as the request comes from a browser (there is no actual
-	 * comet reference running in a controlled environment).
-	 * 
-	 * @param args
-	 * @param callbackMethod
-	 * @return
-	 */
-	private Message createMessageWithMockedCometReference(Object[] args, String callbackMethod) {
-		Message msg = new MessageImpl();
-		msg.getHeaders().put(Constants.MESSAGE_ID, request.getSession().getId());
-		msg.setBody(args);
-		EndpointReference re = new RuntimeEndpointReferenceImpl();
-		RuntimeEndpointImpl callbackEndpoint = new RuntimeEndpointImpl();
-		callbackEndpoint.setURI(callbackMethod);
-		re.setCallbackEndpoint(callbackEndpoint);
-		msg.setFrom(re);
-		return msg;
-	}
-
-	/**
-	 * Parse the JSON array containing the arguments for the method call in
-	 * order to avoid converting JSON to Object[]. Converting each object
-	 * separately to it's corresponding type avoids type mismatch problems at
-	 * service invocation.
-	 * 
-	 * @param jsonArray
-	 *            the JSON array
-	 * @return an array of JSON formatted objects
-	 */
-	private String[] parseArray(final String jsonArray) {
-		final List<String> objects = new ArrayList<String>();
-		int bracketNum = 0;
-		int parNum = 0;
-		int startPos = 1;
-		for (int i = 0; i < jsonArray.length(); i++) {
-			switch (jsonArray.charAt(i)) {
-			case '{':
-				bracketNum++;
-				break;
-			case '}':
-				bracketNum--;
-				break;
-			case '[':
-				parNum++;
-				break;
-			case ']':
-				parNum--;
-				break;
-			case ',':
-				if ((bracketNum == 0) && (parNum == 1)) {
-					objects.add(jsonArray.substring(startPos, i));
-					startPos = i + 1;
-				}
-			}
-		}
-		// add last object
-		objects.add(jsonArray.substring(startPos, jsonArray.length() - 1));
-		return objects.toArray(new String[] {});
-	}
+public class CometBindingHandler {
+
+    private static Gson gson = new GsonBuilder().serializeNulls().create();
+
+    @GET
+    @Path("/connect")
+    public SuspendResponse<String> connect(@QueryParam("sessionId") String sessionId) {
+        System.out.println("-- connect -- Session Id: " + sessionId);
+        Broadcaster broadcaster = CometSessionManager.get(sessionId);
+        if (broadcaster == null) {
+            broadcaster = new JerseyBroadcaster(sessionId);
+            CometSessionManager.add(sessionId, broadcaster);
+        }
+        return new SuspendResponse.SuspendResponseBuilder<String>().broadcaster(broadcaster).outputComments(true)
+                .build();
+    }
+
+    @POST
+    @Path("/{service}/{method}")
+    public void handleRequest(@PathParam("service") String service, @PathParam("method") String method,
+            @FormParam("sessionId") String sessionId, @FormParam("callbackMethod") String callbackMethod,
+            @FormParam("params") String jsonData) throws InvocationTargetException {
+        System.out.println("-- handleRequest -- Session Id: " + sessionId);
+        String url = "/" + service + "/" + method;
+        RuntimeEndpoint wire = CometEndpointManager.get(url);
+        Operation operation = CometOperationManager.get(url);
+
+        final Object[] args = decodeJsonDataForOperation(jsonData, operation);
+        Message msg = createMessageWithMockedCometReference(args, sessionId, callbackMethod);
+        boolean isVoidReturnType = operation.getOutputType().getLogical().isEmpty();
+        if (!isVoidReturnType) {
+            Object response = wire.invoke(operation, args);
+            Broadcaster broadcaster = CometSessionManager.get(sessionId);
+            broadcaster.broadcast(callbackMethod + "($.secureEvalJSON('" + gson.toJson(response) + "'))");
+            if (broadcaster.getAtmosphereResources().isEmpty()) {
+                CometSessionManager.remove(sessionId);
+            }
+        } else {
+            wire.invoke(operation, msg);
+        }
+    }
+
+    /**
+     * Convert request parameters from JSON to operation parameter types.
+     * 
+     * @param jsonData
+     * @param operation
+     * @return
+     */
+    private Object[] decodeJsonDataForOperation(String jsonData, Operation operation) {
+        Object[] args = new Object[operation.getInputType().getLogical().size()];
+        final String[] json = this.parseArray(jsonData);
+        int index = 0;
+        // convert each argument to the corresponding class
+        for (final DataType<?> dataType : operation.getInputType().getLogical()) {
+            args[index] = gson.fromJson(json[index], dataType.getPhysical());
+            index++;
+        }
+        return args;
+    }
+
+    /**
+     * Creates the message to be sent with a mocked EndpointReference in the
+     * 'from' field as the request comes from a browser (there is no actual
+     * comet reference running in a controlled environment).
+     * 
+     * @param args
+     * @param callbackMethod
+     * @return
+     */
+    private Message createMessageWithMockedCometReference(Object[] args, String sessionId, String callbackMethod) {
+        Message msg = new MessageImpl();
+        msg.getHeaders().put(Constants.MESSAGE_ID, sessionId);
+        msg.setBody(args);
+        EndpointReference re = new RuntimeEndpointReferenceImpl();
+        RuntimeEndpointImpl callbackEndpoint = new RuntimeEndpointImpl();
+        callbackEndpoint.setURI(callbackMethod);
+        re.setCallbackEndpoint(callbackEndpoint);
+        msg.setFrom(re);
+        return msg;
+    }
+
+    /**
+     * Parse the JSON array containing the arguments for the method call in
+     * order to avoid converting JSON to Object[]. Converting each object
+     * separately to it's corresponding type avoids type mismatch problems at
+     * service invocation.
+     * 
+     * @param jsonArray
+     *            the JSON array
+     * @return an array of JSON formatted objects
+     */
+    private String[] parseArray(final String jsonArray) {
+        final List<String> objects = new ArrayList<String>();
+        int bracketNum = 0;
+        int parNum = 0;
+        int startPos = 1;
+        for (int i = 0; i < jsonArray.length(); i++) {
+            switch (jsonArray.charAt(i)) {
+            case '{':
+                bracketNum++;
+                break;
+            case '}':
+                bracketNum--;
+                break;
+            case '[':
+                parNum++;
+                break;
+            case ']':
+                parNum--;
+                break;
+            case ',':
+                if ((bracketNum == 0) && (parNum == 1)) {
+                    objects.add(jsonArray.substring(startPos, i));
+                    startPos = i + 1;
+                }
+            }
+        }
+        // add last object
+        objects.add(jsonArray.substring(startPos, jsonArray.length() - 1));
+        return objects.toArray(new String[] {});
+    }
 
 }

Modified: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java?rev=1129323&r1=1129322&r2=1129323&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java Mon May 30 19:49:17 2011
@@ -37,8 +37,8 @@ public class JavascriptResource {
     /**
      * Dependencies for the Tuscany Comet Javascript API.
      */
-    private static final String[] DEPENDENCIES = {"/jquery.atmosphere.js", "/jquery.json-2.2.min.js",
-                                                  "/cometComponentContext.js"};
+    private static final String[] DEPENDENCIES = { "/jquery.atmosphere.js", "/jquery.json-2.2.min.js",
+            "/jquery.guid.js", "/cometComponentContext.js" };
 
     /**
      * Method called when the Javascript toolkit is requested.

Added: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java?rev=1129323&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java Mon May 30 19:49:17 2011
@@ -0,0 +1,30 @@
+package org.apache.tuscany.sca.binding.comet.runtime.manager;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+
+public class CometEndpointManager {
+
+	private static final ConcurrentMap<String, RuntimeEndpoint> endpoints = new ConcurrentHashMap<String, RuntimeEndpoint>();
+
+	private CometEndpointManager() {
+	}
+
+	public static void add(String url, RuntimeEndpoint endpoint) {
+		endpoints.put(url, endpoint);
+	}
+
+	public static RuntimeEndpoint get(String url) {
+		return endpoints.get(url);
+	}
+
+	public static void remove(String url) {
+		endpoints.remove(url);
+	}
+
+	public static void clear() {
+		endpoints.clear();
+	}
+}

Added: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java?rev=1129323&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java Mon May 30 19:49:17 2011
@@ -0,0 +1,30 @@
+package org.apache.tuscany.sca.binding.comet.runtime.manager;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.tuscany.sca.interfacedef.Operation;
+
+public class CometOperationManager {
+
+	private static final ConcurrentMap<String, Operation> operations = new ConcurrentHashMap<String, Operation>();
+
+	private CometOperationManager() {
+	}
+
+	public static void add(String url, Operation operation) {
+		operations.put(url, operation);
+	}
+
+	public static Operation get(String url) {
+		return operations.get(url);
+	}
+
+	public static void remove(String url) {
+		operations.remove(url);
+	}
+
+	public static void clear() {
+		operations.clear();
+	}
+}

Added: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java?rev=1129323&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java Mon May 30 19:49:17 2011
@@ -0,0 +1,30 @@
+package org.apache.tuscany.sca.binding.comet.runtime.manager;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.atmosphere.cpr.Broadcaster;
+
+public class CometSessionManager {
+
+    private static final ConcurrentMap<String, Broadcaster> broadcasters = new ConcurrentHashMap<String, Broadcaster>();
+
+    private CometSessionManager() {
+    }
+
+    public static void add(String sessionId, Broadcaster broadcaster) {
+        broadcasters.put(sessionId, broadcaster);
+    }
+
+    public static Broadcaster get(String sessionId) {
+        return broadcasters.get(sessionId);
+    }
+
+    public static void remove(String sessionId) {
+        broadcasters.remove(sessionId);
+    }
+
+    public static void clear() {
+        broadcasters.clear();
+    }
+}

Modified: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js?rev=1129323&r1=1129322&r2=1129323&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js (original)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js Mon May 30 19:49:17 2011
@@ -21,15 +21,17 @@ var SCA = new function() {
 this.TuscanyComet = {
 	appUrl: 'tuscany-comet',
 	connectedEndpoint : null,
+    sessionId : $.Guid.New(),	
 	connect : function(transport) {
 		if(transport == null) {
 			transport = 'streaming';
 		}
-		$.atmosphere.subscribe(document.location.toString() + this.appUrl + "/connect",
+		$.atmosphere.subscribe(document.location.toString() + this.appUrl + "/connect?sessionId=" + this.sessionId,
 				this.callback, 
 				$.atmosphere.request = {
+					method : 'GET',
 					transport : transport,
-					maxRequest: 1000000000
+					maxRequest: 1000000,
 				});
 		this.connectedEndpoint = $.atmosphere.response;
 	},
@@ -39,7 +41,7 @@ this.TuscanyComet = {
 				null, 
 				$.atmosphere.request = {
 					method : 'POST',
-					data : 'callbackMethod=' + callbackMethod.name + '&params=' + params 
+					data : 'sessionId=' + this.sessionId + '&callbackMethod=' + callbackMethod.name + '&params=' + params
 				});
 	},
 	callback : function(response) {
@@ -48,10 +50,4 @@ this.TuscanyComet = {
 };
 
 
-$.ajax({
-	url: document.location.toString() + this.TuscanyComet.appUrl + '/sessionId',
-	type: 'GET',
-	async: false,
-});
-
 this.CometComponentContext = new Object();

Added: tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js?rev=1129323&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js (added)
+++ tuscany/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js Mon May 30 19:49:17 2011
@@ -0,0 +1,75 @@
+/**
+ * jQuery Guid v1.0.0-1
+ * Requires jQuery 1.2.6+ (Not tested with earlier versions).
+ * Copyright (c) 2010 Aaron E. [jquery at happinessinmycheeks dot com] 
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ *	Usage:
+ *		jQuery.Guid.Value() // Returns value of internal Guid. If no guid has been specified, returns a new one (value is then stored internally).
+ *		jQuery.Guid.New() // Returns a new Guid and sets it's value internally. Also accepts GUID, Sets it internally.
+ *		jQuery.Guid.Empty() // Returns an empty Guid 00000000-0000-0000-0000-000000000000.
+ *		jQuery.Guid.IsEmpty() // Returns boolean. True if empty/undefined/blank/null.
+ *		jQuery.Guid.IsValid() // Returns boolean. True valid guid, false if not.
+ *		jQuery.Guid.Set() // Retrns Guid. Sets Guid to user specified Guid, if invalid, returns an empty guid.
+ *
+ */
+
+jQuery.extend({
+	Guid: {
+		Set: function(val) {
+			var value;
+			if (arguments.length == 1) {
+				if (this.IsValid(arguments[0])) {
+					value = arguments[0];
+				} else {
+					value = this.Empty();
+				}
+			}
+			$(this).data("value", value);
+			return value;
+		},
+
+		Empty: function() {
+			return "00000000-0000-0000-0000-000000000000";
+		},
+
+		IsEmpty: function(gid) {
+			return gid == this.Empty() || typeof (gid) == 'undefined' || gid == null || gid == '';
+		},
+
+		IsValid: function(value) {
+			rGx = new RegExp("\\b(?:[A-F0-9]{8})(?:-[A-F0-9]{4}){3}-(?:[A-F0-9]{12})\\b");
+			return rGx.exec(value) != null;
+		},
+
+		New: function() {
+			if (arguments.length == 1 && this.IsValid(arguments[0])) {
+				$(this).data("value", arguments[0]);
+				value = arguments[0];
+				return value;
+			}
+
+			var res = [], hv;
+			var rgx = new RegExp("[2345]");
+			for (var i = 0; i < 8; i++) {
+				hv = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+				if (rgx.exec(i.toString()) != null) {
+					if (i == 3) { hv = "6" + hv.substr(1, 3); }
+					res.push("-");
+				}
+				res.push(hv.toUpperCase());
+			}
+			value = res.join('');
+			$(this).data("value", value);
+			return value;
+		},
+
+		Value: function() {
+			if ($(this).data("value")) {
+				return $(this).data("value");
+			}
+			var val = this.New();
+			$(this).data("value", val);
+			return val;
+		}
+	}
+})();
\ No newline at end of file