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


Reply via email to