From fc0948d7ad308a47a80139a0779e08f24903df46 Mon Sep 17 00:00:00 2001 From: fmoga Date: Sun, 24 Jul 2011 13:32:46 +0000 Subject: Migrate to embedded Jetty as websocket server. Add javascript service proxy injection. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1150357 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/META-INF/MANIFEST.MF | 3 + .../sca/binding/websocket/WebsocketBinding.java | 9 ++ .../sca/binding/websocket/runtime/JSONUtil.java | 59 +++-------- .../websocket/runtime/JavascriptGenerator.java | 99 +++++++++++++++++++ .../runtime/JavascriptResourceServlet.java | 109 +++++++++++++++++++++ .../websocket/runtime/TuscanyWebSocket.java | 61 ++++++++++++ .../runtime/WebSocketBindingDispatcher.java | 39 ++++++++ .../websocket/runtime/WebSocketBindingMessage.java | 47 +++++++++ .../websocket/runtime/WebSocketBindingRequest.java | 57 ----------- .../runtime/WebSocketBindingResponse.java | 47 --------- .../runtime/WebSocketOperationDispatcher.java | 95 ------------------ .../websocket/runtime/WebSocketRequestHandler.java | 76 -------------- .../binding/websocket/runtime/WebSocketServer.java | 56 +++++++++++ .../runtime/WebsocketBindingProviderFactory.java | 7 +- .../runtime/WebsocketReferenceBindingProvider.java | 1 - .../runtime/WebsocketReferenceInvoker.java | 66 +------------ .../runtime/WebsocketServiceBindingProvider.java | 78 ++++++++------- .../websocket/runtime/WebsocketServiceInvoker.java | 73 ++++++++++++++ 18 files changed, 560 insertions(+), 422 deletions(-) create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/META-INF/MANIFEST.MF create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptGenerator.java create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptResourceServlet.java create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/TuscanyWebSocket.java create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingDispatcher.java create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingMessage.java delete mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingRequest.java delete mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingResponse.java delete mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketOperationDispatcher.java delete mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketRequestHandler.java create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketServer.java create mode 100644 sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceInvoker.java (limited to 'sca-java-2.x/contrib/modules/binding-websocket/src/main/java') diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/META-INF/MANIFEST.MF b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..5e9495128c --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/WebsocketBinding.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/WebsocketBinding.java index 8988b376de..a78a6b11c2 100644 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/WebsocketBinding.java +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/WebsocketBinding.java @@ -28,6 +28,7 @@ import org.apache.tuscany.sca.provider.BaseBindingImpl; public class WebsocketBinding extends BaseBindingImpl { public static final QName TYPE = new QName(SCA11_TUSCANY_NS, "binding.websocket"); + private String port; public WebsocketBinding() { } @@ -37,4 +38,12 @@ public class WebsocketBinding extends BaseBindingImpl { return TYPE; } + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + } diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JSONUtil.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JSONUtil.java index 492dfae3dd..3fdb1ee1c1 100644 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JSONUtil.java +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JSONUtil.java @@ -33,6 +33,18 @@ public class JSONUtil { private static Gson gson = new Gson(); + public static String encodeMessage(WebSocketBindingMessage request) { + return gson.toJson(request); + } + + public static WebSocketBindingMessage decodeMessage(String jsonRequest) { + return gson.fromJson(jsonRequest, WebSocketBindingMessage.class); + } + + public static String encodePayload(Object payload) { + return gson.toJson(payload); + } + /** * Convert request parameters from JSON to operation parameter types. * @@ -42,7 +54,7 @@ public class JSONUtil { * the operation to invoke * @return an array of objects */ - public static Object[] decodeJsonParamsForOperation(String jsonData, Operation operation) { + public static Object[] decodePayloadForOperation(String jsonData, Operation operation) { Object[] args = new Object[operation.getInputType().getLogical().size()]; final String[] json = parseArray(jsonData); int index = 0; @@ -100,49 +112,4 @@ public class JSONUtil { private JSONUtil() { } - /** - * Converts a Java object to JSON format. - * - * @param response - * the response to convert - * @return the object in JSON format - */ - public static String encodeResponse(Object response) { - return gson.toJson(response); - } - - /** - * Convert request parameters as JSON array. - * - * @param params - * request parameters - * @return request parameters as JSON array - */ - public static String encodeRequestParams(Object[] params) { - StringBuilder builder = new StringBuilder(); - for (int index = 0; index < params.length; index++) { - Object param = params[index]; - builder.append(index == 0 ? "[" : ","); - builder.append(gson.toJson(param)); - } - builder.append("]"); - return builder.toString(); - } - - public static String encodeRequest(WebSocketBindingRequest request) { - return gson.toJson(request); - } - - public static WebSocketBindingRequest decodeRequest(String jsonRequest) { - return gson.fromJson(jsonRequest, WebSocketBindingRequest.class); - } - - public static WebSocketBindingResponse decodeResponse(String operationResponse) { - return gson.fromJson(operationResponse, WebSocketBindingResponse.class); - } - - public static Object decodeResponsePayload(String payload, Class returnType) { - return gson.fromJson(payload, returnType); - } - } diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptGenerator.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptGenerator.java new file mode 100644 index 0000000000..04faf0113d --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptGenerator.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +/* + * 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.websocket.runtime; + +import java.util.List; + +import org.apache.tuscany.sca.interfacedef.Operation; + +public class JavascriptGenerator { + + private final static String CONTEXT = "this.WebsocketComponentContext"; + private static final String LF = "\n"; + private static StringBuilder builder = new StringBuilder(); + + public static void generateServiceProxy(String component, String service, List operations, int port) { + if (builder.length() == 0) { + builder.append(CONTEXT).append("={};").append(LF); + } + builder.append("if(!" + CONTEXT + "." + component + ")" + CONTEXT + "." + component + "={};").append(LF); + builder.append(CONTEXT + "." + component + "." + service + "={};").append(LF); + for (Operation operation : operations) { + builder.append( + CONTEXT + "." + component + "." + service + "." + operation.getName() + "=" + + generateFunctionHeader(operation)).append(LF); + builder.append(generateFunctionContent(port, component, service, operation)).append(LF); + builder.append("};").append(LF); + } + } + + private static String generateFunctionHeader(Operation operation) { + String header = "function("; + for (int i = 0; i < operation.getInputType().getLogical().size(); i++) { + if (i > 0) + header += ","; + header += "p" + i; + } + header += ") {"; + return header; + } + + private static String generateFunctionContent(int port, String component, String service, Operation operation) { + String content = "sendMessage(" + port + ",'" + component + "." + service + "." + operation.getName() + "',["; + for (int i = 0; i < operation.getInputType().getLogical().size(); i++) { + if (i > 0) + content += ","; + content += "p" + i; + } + content += "]);"; + return content; + } + + public static String getServiceProxies() { + return builder.toString(); + } + + public static void clear() { + builder.setLength(0); + } + + private JavascriptGenerator() { + } + +} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptResourceServlet.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptResourceServlet.java new file mode 100644 index 0000000000..def2783a81 --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/JavascriptResourceServlet.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/* + * 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.websocket.runtime; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class JavascriptResourceServlet extends HttpServlet { + + private static final String JSON_PLUGIN_PATH = "js/jquery.json-2.2.min.js"; + private static final String WEBSOCKET_TOOLKIT_PATH = "js/TuscanyWebsocketToolkit.js"; + + private String jsonPlugin; + private String websocketToolkit; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException { + try { + resp.setContentType("text/javascript"); + OutputStream os = resp.getOutputStream(); + os.write(getJsonPlugin().getBytes()); + os.write("var Tuscany = new function() {\n".getBytes()); + os.write(getWebsocketToolkit().getBytes()); + os.write(JavascriptGenerator.getServiceProxies().getBytes()); + os.write("}\n".getBytes()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private String getJsonPlugin() { + if (jsonPlugin == null) { + jsonPlugin = getResource(JSON_PLUGIN_PATH); + } + return jsonPlugin; + } + + private String getWebsocketToolkit() { + if (websocketToolkit == null) { + websocketToolkit = getResource(WEBSOCKET_TOOLKIT_PATH); + } + return websocketToolkit; + } + + private String getResource(String path) { + InputStream is = getClass().getClassLoader().getResourceAsStream(path); + BufferedReader r = new BufferedReader(new InputStreamReader(is)); + StringBuilder builder = new StringBuilder(); + try { + String line = null; + while ((line = r.readLine()) != null) { + builder.append(line + "\n"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + try { + r.close(); + } catch (IOException ignored) { + } + } + return builder.toString(); + } + +} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/TuscanyWebSocket.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/TuscanyWebSocket.java new file mode 100644 index 0000000000..c267d9e6a4 --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/TuscanyWebSocket.java @@ -0,0 +1,61 @@ +/* + * 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.websocket.runtime; + +import java.io.IOException; + +import org.eclipse.jetty.websocket.WebSocket; + +public class TuscanyWebSocket implements WebSocket, WebSocket.OnTextMessage { + + private Connection connection; + private WebSocketBindingDispatcher dispatcher; + + public TuscanyWebSocket(WebSocketBindingDispatcher dispatcher) { + this.dispatcher = dispatcher; + } + + @Override + public void onOpen(Connection connection) { + this.connection = connection; + } + + @Override + public void onMessage(String jsonRequest) { + WebSocketBindingMessage request = JSONUtil.decodeMessage(jsonRequest); + WebsocketServiceInvoker invoker = dispatcher.dispatch(request.getOperation()); + if (invoker == null) { + throw new RuntimeException("No operation found for " + request.getOperation()); + } else { + WebSocketBindingMessage response = invoker.invokeSync(request); + String jsonResponse = JSONUtil.encodeMessage(response); + try { + connection.sendMessage(jsonResponse); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void onClose(int closeCode, String message) { + } + +} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingDispatcher.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingDispatcher.java new file mode 100644 index 0000000000..4e0dbaffd5 --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingDispatcher.java @@ -0,0 +1,39 @@ +/* + * 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.websocket.runtime; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; + +public class WebSocketBindingDispatcher { + + private Map invokers = new HashMap(); + + public void addOperation(String uri, RuntimeEndpoint endpoint, Operation operation) { + System.out.println("Adding " + uri); + invokers.put(uri, new WebsocketServiceInvoker(operation, endpoint)); + } + + public WebsocketServiceInvoker dispatch(String uri) { + return invokers.get(uri); + } +} \ No newline at end of file diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingMessage.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingMessage.java new file mode 100644 index 0000000000..1ff8c4c10e --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingMessage.java @@ -0,0 +1,47 @@ +/* + * 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.websocket.runtime; + +public class WebSocketBindingMessage { + + private String operation; + private String payload; + + public WebSocketBindingMessage(String operation, String payload) { + this.operation = operation; + this.payload = payload; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getPayload() { + return payload; + } + + public void setPayload(String payload) { + this.payload = payload; + } + +} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingRequest.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingRequest.java deleted file mode 100644 index 19b875805a..0000000000 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingRequest.java +++ /dev/null @@ -1,57 +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.websocket.runtime; - -public class WebSocketBindingRequest { - - private String requestId; - private String uri; - private String payload; - - public WebSocketBindingRequest(String requestId, String uri, String payload) { - this.requestId = requestId; - this.uri = uri; - this.payload = payload; - } - - public String getRequestId() { - return requestId; - } - - public void setRequestId(String requestId) { - this.requestId = requestId; - } - - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public String getPayload() { - return payload; - } - - public void setPayload(String payload) { - this.payload = payload; - } - -} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingResponse.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingResponse.java deleted file mode 100644 index 51664879a3..0000000000 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketBindingResponse.java +++ /dev/null @@ -1,47 +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.websocket.runtime; - -public class WebSocketBindingResponse { - - private String uri; - private String payload; - - public WebSocketBindingResponse(String uri, String payload) { - this.uri = uri; - this.payload = payload; - } - - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public String getPayload() { - return payload; - } - - public void setPayload(String payload) { - this.payload = payload; - } - -} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketOperationDispatcher.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketOperationDispatcher.java deleted file mode 100644 index c33b3ca12a..0000000000 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketOperationDispatcher.java +++ /dev/null @@ -1,95 +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.websocket.runtime; - -import java.io.IOException; -import java.nio.channels.SocketChannel; -import java.util.HashMap; -import java.util.Map; - -import org.apache.tuscany.sca.interfacedef.Operation; -import org.apache.tuscany.sca.runtime.RuntimeEndpoint; -import org.apache.websocket.ServerWebSocket; -import org.apache.websocket.WebSocket; -import org.apache.websocket.WebSocketApplication; -import org.apache.websocket.WebSocketException; - -public class WebSocketOperationDispatcher implements WebSocketApplication { - - private ServerWebSocket server; - private Map endpoints = new HashMap(); - private Map operations = new HashMap(); - - public WebSocketOperationDispatcher(ServerWebSocket server) { - this.server = server; - } - - public void addOperation(String uri, RuntimeEndpoint endpoint, Operation operation) { - endpoints.put(uri, endpoint); - operations.put(uri, operation); - } - - public Operation getOperation(String uri) { - return operations.get(uri); - } - - public RuntimeEndpoint getEndpoint(String uri) { - return endpoints.get(uri); - } - - @Override - public void onConnection(WebSocket socket) { - // release server thread - new Thread(new WebSocketRequestHandler(socket, this)).start(); - } - - @Override - public void onHandshakeError(IOException e) { - throw new RuntimeException(e); - } - - @Override - public String acceptProtocol(String protocol) { - // don't accept any subprotocols - return null; - } - - @Override - public boolean acceptOrigin(String origin) { - // accept all clients - return true; - } - - @Override - public Map acceptExtensions(Map headers) throws WebSocketException { - // don't accept any extensions - return null; - } - - public void shutdown() { - try { - server.close(); - endpoints.clear(); - operations.clear(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - -} \ No newline at end of file diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketRequestHandler.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketRequestHandler.java deleted file mode 100644 index 59d8af3133..0000000000 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketRequestHandler.java +++ /dev/null @@ -1,76 +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.websocket.runtime; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.channels.SocketChannel; - -import org.apache.tuscany.sca.interfacedef.Operation; -import org.apache.tuscany.sca.runtime.RuntimeEndpoint; -import org.apache.websocket.WebSocket; - -public class WebSocketRequestHandler implements Runnable { - - private WebSocket websocket; - private WebSocketOperationDispatcher dispatcher; - - public WebSocketRequestHandler(WebSocket socket, WebSocketOperationDispatcher dispatcher) { - this.websocket = socket; - this.dispatcher = dispatcher; - } - - @Override - public void run() { - while (true) { - try { - // TODO use Java NIO selectors on websockets - String request = websocket.receiveText(); - String response = handleRequest(request); - websocket.sendText(response); - } catch (IOException e) { - if (!websocket.isOpen()) { - System.out.println("Client disconnected. Stopping WebSocketRequestHandler."); - break; - } else { - throw new RuntimeException(e); - } - } - } - } - - // TODO handle request asynchronously in a background thread - private String handleRequest(String jsonRequest) { - WebSocketBindingRequest request = JSONUtil.decodeRequest(jsonRequest); - RuntimeEndpoint wire = dispatcher.getEndpoint(request.getUri()); - Operation operation = dispatcher.getOperation(request.getUri()); - System.out.println("handleRequest - " + request.getUri() + " - " + wire + " - " + operation); - String jsonParams = request.getPayload(); - Object[] args = JSONUtil.decodeJsonParamsForOperation(jsonParams, operation); - try { - Object operationResponse = wire.invoke(operation, args); - String payload = JSONUtil.encodeResponse(operationResponse); - WebSocketBindingResponse response = new WebSocketBindingResponse(request.getRequestId(), payload); - return JSONUtil.encodeResponse(response); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketServer.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketServer.java new file mode 100644 index 0000000000..e470ddfde0 --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebSocketServer.java @@ -0,0 +1,56 @@ +/* + * 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.websocket.runtime; + +import java.net.URISyntaxException; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.websocket.WebSocket; +import org.eclipse.jetty.websocket.WebSocketHandler; + +public class WebSocketServer extends Server { + + private WebSocketBindingDispatcher dispatcher; + + public WebSocketServer(int port) throws URISyntaxException { + SelectChannelConnector connector = new SelectChannelConnector(); + connector.setPort(port); + addConnector(connector); + + setHandler(new WebSocketHandler() { + + @Override + public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) { + System.out.println("Connection established"); + return new TuscanyWebSocket(dispatcher); + } + }); + + dispatcher = new WebSocketBindingDispatcher(); + } + + public WebSocketBindingDispatcher getDispatcher() { + return dispatcher; + } + +} diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketBindingProviderFactory.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketBindingProviderFactory.java index d7f8ef98a5..1f750234ae 100644 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketBindingProviderFactory.java +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketBindingProviderFactory.java @@ -21,6 +21,8 @@ package org.apache.tuscany.sca.binding.websocket.runtime; import org.apache.tuscany.sca.binding.websocket.WebsocketBinding; import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.host.http.ServletHostHelper; import org.apache.tuscany.sca.provider.BindingProviderFactory; import org.apache.tuscany.sca.provider.ReferenceBindingProvider; import org.apache.tuscany.sca.provider.ServiceBindingProvider; @@ -29,7 +31,10 @@ import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; public class WebsocketBindingProviderFactory implements BindingProviderFactory { + private ServletHost servletHost; + public WebsocketBindingProviderFactory(ExtensionPointRegistry extensionPoints) { + this.servletHost = ServletHostHelper.getServletHost(extensionPoints); } public Class getModelType() { @@ -41,7 +46,7 @@ public class WebsocketBindingProviderFactory implements BindingProviderFactory> persistentWebsockets = new ConcurrentHashMap>(); - protected Operation operation; protected EndpointReference endpoint; @@ -48,58 +35,7 @@ public class WebsocketReferenceInvoker implements Invoker { } public Message invoke(Message msg) { - try { - WebSocket websocket = initWebsocketConnection(endpoint.getBinding().getURI()); - return doInvoke(msg, websocket); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private WebSocket initWebsocketConnection(String uri) throws IOException, URISyntaxException { - WebSocket websocket = null; - synchronized (persistentWebsockets) { - websocket = persistentWebsockets.get(uri); - if (websocket == null) { - WebSocketConnector connector = new WebSocketConnector(); - websocket = connector.connect(new URI(uri), null, "apache-tuscany", null); - persistentWebsockets.put(uri, websocket); - } - } - return websocket; - } - - public Message doInvoke(Message msg, WebSocket websocket) throws IOException { - String componentName = endpoint.getTargetEndpoint().getComponent().getName(); - String serviceName = endpoint.getTargetEndpoint().getService().getName(); - String operationName = operation.getName(); - String uri = componentName + "/" + serviceName + "/" + operationName; - String payload = JSONUtil.encodeRequestParams((Object[]) msg.getBody()); - WebSocketBindingRequest request = new WebSocketBindingRequest(UUID.randomUUID().toString(), uri, payload); - - String operationResponse = invokeViaWebsocket(websocket, JSONUtil.encodeRequest(request)); - - WebSocketBindingResponse response = JSONUtil.decodeResponse(operationResponse); - Class returnType = operation.getOutputType().getLogical().get(0).getPhysical(); - Object invocationResponse = JSONUtil.decodeResponsePayload(response.getPayload(), returnType); - msg.setBody(invocationResponse); - return msg; - } - - private String invokeViaWebsocket(WebSocket websocket, String request) throws IOException { - websocket.sendText(request); - return websocket.receiveText(); - } - - public static void shutdown() { - for (WebSocket websocket : persistentWebsockets.values()) { - try { - websocket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - persistentWebsockets.clear(); + throw new RuntimeException("Not implemented yet"); } } diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceBindingProvider.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceBindingProvider.java index fe5efcffef..7f89a523c3 100644 --- a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceBindingProvider.java +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceBindingProvider.java @@ -19,65 +19,75 @@ package org.apache.tuscany.sca.binding.websocket.runtime; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; +import org.apache.tuscany.sca.binding.websocket.WebsocketBinding; +import org.apache.tuscany.sca.host.http.ServletHost; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.interfacedef.Operation; import org.apache.tuscany.sca.provider.ServiceBindingProvider; import org.apache.tuscany.sca.runtime.RuntimeEndpoint; -import org.apache.websocket.ServerWebSocket; public class WebsocketServiceBindingProvider implements ServiceBindingProvider { - private static Map dispatchers = new HashMap(); - + private static final String JAVASCRIPT_RESOURCE_PATH = "/org.apache.tuscany.sca.WebsocketComponentContext.js"; + private static Map servers = new HashMap(); private RuntimeEndpoint endpoint; + private ServletHost servletHost; - public WebsocketServiceBindingProvider(RuntimeEndpoint endpoint) { + public WebsocketServiceBindingProvider(RuntimeEndpoint endpoint, ServletHost servletHost) { this.endpoint = endpoint; + this.servletHost = servletHost; } public void start() { - String uri = endpoint.getBinding().getURI(); - WebSocketOperationDispatcher dispatcher = initDispatcherForURI(uri); - String component = endpoint.getComponent().getName(); - String service = endpoint.getService().getName(); - for (Operation op : getBindingInterfaceContract().getInterface().getOperations()) { - String operation = op.getName(); - dispatcher.addOperation(component + "/" + service + "/" + operation, endpoint, op); + WebsocketBinding binding = (WebsocketBinding) endpoint.getBinding(); + int port = Integer.parseInt(binding.getPort()); + try { + WebSocketServer server = initServerForURI(port); + String component = endpoint.getComponent().getName(); + String service = endpoint.getService().getName(); + for (Operation op : getBindingInterfaceContract().getInterface().getOperations()) { + String operation = op.getName(); + server.getDispatcher().addOperation(component + "." + service + "." + operation, endpoint, op); + } + JavascriptGenerator.generateServiceProxy(component, service, getBindingInterfaceContract().getInterface() + .getOperations(), port); + } catch (Exception e) { + throw new RuntimeException(e); } + initJavascriptResource(); + } + private WebSocketServer initServerForURI(int port) throws Exception { + WebSocketServer server = servers.get(port); + if (server == null) { + server = new WebSocketServer(port); + server.start(); + servers.put(port, server); + } + return server; } - private WebSocketOperationDispatcher initDispatcherForURI(String uri) { - WebSocketOperationDispatcher dispatcher = dispatchers.get(uri); - if (dispatcher == null) { - try { - ServerWebSocket server = new ServerWebSocket(new URI(uri)); - System.out.println("Starting websocket server " + server + " at " + uri + "..."); - dispatcher = new WebSocketOperationDispatcher(server); - System.out.println("Created new dispatcher for " + uri + " " + dispatcher); - dispatchers.put(uri, dispatcher); - server.register("/", dispatcher); - new Thread(server).start(); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } + private void initJavascriptResource() { + if (servletHost.getServletMapping(JAVASCRIPT_RESOURCE_PATH) == null) { + System.out.println("Adding javascript servlet"); + servletHost.addServletMapping(JAVASCRIPT_RESOURCE_PATH, new JavascriptResourceServlet()); } - return dispatcher; } public void stop() { - for (WebSocketOperationDispatcher dispatcher : dispatchers.values()) { - dispatcher.shutdown(); + for (WebSocketServer server : servers.values()) { + try { + server.stop(); + } catch (Exception e) { + throw new RuntimeException(e); + } } - dispatchers.clear(); + servers.clear(); + servletHost.removeServletMapping(JAVASCRIPT_RESOURCE_PATH); + JavascriptGenerator.clear(); } public InterfaceContract getBindingInterfaceContract() { diff --git a/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceInvoker.java b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceInvoker.java new file mode 100644 index 0000000000..7615be916c --- /dev/null +++ b/sca-java-2.x/contrib/modules/binding-websocket/src/main/java/org/apache/tuscany/sca/binding/websocket/runtime/WebsocketServiceInvoker.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +/* + * 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.websocket.runtime; + +import java.lang.reflect.InvocationTargetException; + +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; + +public class WebsocketServiceInvoker { + + protected Operation operation; + protected RuntimeEndpoint endpoint; + + public WebsocketServiceInvoker(Operation operation, RuntimeEndpoint endpoint) { + this.operation = operation; + this.endpoint = endpoint; + } + + public WebSocketBindingMessage invokeSync(WebSocketBindingMessage request) { + String jsonParams = request.getPayload(); + Object[] args = JSONUtil.decodePayloadForOperation(jsonParams, operation); + try { + Object operationResponse = endpoint.invoke(operation, args); + String payload = JSONUtil.encodePayload(operationResponse); + WebSocketBindingMessage response = new WebSocketBindingMessage(request.getOperation(), payload); + return response; + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public void invokeAsync(WebSocketBindingMessage request, TuscanyWebSocket channel) { + // TODO add multiple response support + } + +} -- cgit v1.2.3