From 54d2f552f064b26098f79ddf9389de0b405e3d7e Mon Sep 17 00:00:00 2001 From: fmoga Date: Mon, 30 May 2011 19:49:17 +0000 Subject: Move from relying on the HTTP session to manual session management using sessionIds generated by the javascript on page load. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1129323 13f79535-47bb-0310-9956-ffa450edef68 --- .../comet/runtime/CometComponentContext.java | 59 ---- .../sca/binding/comet/runtime/CometInvoker.java | 59 ++-- .../comet/runtime/CometServiceBindingProvider.java | 28 +- .../sca/binding/comet/runtime/ServletFactory.java | 64 +---- .../comet/runtime/handler/CometBindingHandler.java | 316 +++++++++------------ .../runtime/javascript/JavascriptResource.java | 4 +- .../runtime/manager/CometEndpointManager.java | 30 ++ .../runtime/manager/CometOperationManager.java | 30 ++ .../comet/runtime/manager/CometSessionManager.java | 30 ++ .../src/main/resources/cometComponentContext.js | 14 +- .../src/main/resources/jquery.guid.js | 75 +++++ 11 files changed, 349 insertions(+), 360 deletions(-) delete mode 100644 sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java create mode 100644 sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java create mode 100644 sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java create mode 100644 sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java create mode 100644 sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java deleted file mode 100644 index 9e93457c7e..0000000000 --- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.tuscany.sca.binding.comet.runtime; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.tuscany.sca.interfacedef.Operation; -import org.apache.tuscany.sca.runtime.RuntimeEndpoint; -import org.atmosphere.cpr.Broadcaster; - -import com.google.gson.Gson; - -public class CometComponentContext { - - public static Map broadcasters = new ConcurrentHashMap(); - public static Gson gson = new Gson(); - private Map endpoints; - private Map operations; - - public CometComponentContext() { - endpoints = new ConcurrentHashMap(); - operations = new ConcurrentHashMap(); - } - - public void addEndpoint(String key, RuntimeEndpoint endpoint) { - endpoints.put(key, endpoint); - } - - public void addOperation(String key, Operation operation) { - operations.put(key, operation); - } - - public RuntimeEndpoint getEndpoint(String key) { - return endpoints.get(key); - } - - public Operation getOperation(String key) { - return operations.get(key); - } - -} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java index ef8d1179a0..1835c062c3 100644 --- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java @@ -21,6 +21,7 @@ package org.apache.tuscany.sca.binding.comet.runtime; 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.Invoker; 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; + } - 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; - @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; - } } diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java index 96b688aa4f..6c1d002575 100644 --- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java @@ -21,6 +21,9 @@ package org.apache.tuscany.sca.binding.comet.runtime; 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.RuntimeEndpoint; */ 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 implements ServiceBindingProvider { 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 implements ServiceBindingProvider { @Override public void stop() { ServletFactory.unregisterServlet(this.servletHost); + CometEndpointManager.clear(); + CometOperationManager.clear(); + CometSessionManager.clear(); } @Override diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java index 150d6977e2..3d32c7ad4e 100644 --- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java @@ -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); } } diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java index 3cd90304b8..c2d2181814 100644 --- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java @@ -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 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().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 objects = new ArrayList(); - 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 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().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 objects = new ArrayList(); + 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[] {}); + } } diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java index 4f301a4d0b..6131cec7cd 100644 --- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java @@ -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. diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java new file mode 100644 index 0000000000..9fe0353f03 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometEndpointManager.java @@ -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 endpoints = new ConcurrentHashMap(); + + 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(); + } +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java new file mode 100644 index 0000000000..3179603b96 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometOperationManager.java @@ -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 operations = new ConcurrentHashMap(); + + 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(); + } +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java new file mode 100644 index 0000000000..a34a3615d5 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/manager/CometSessionManager.java @@ -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 broadcasters = new ConcurrentHashMap(); + + 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(); + } +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js index 589ae73e7f..cddbaa3fa0 100644 --- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js @@ -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 + '¶ms=' + params + data : 'sessionId=' + this.sessionId + '&callbackMethod=' + callbackMethod.name + '¶ms=' + 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(); diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js new file mode 100644 index 0000000000..1c7ad4e2fb --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.guid.js @@ -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 -- cgit v1.2.3