diff options
Diffstat (limited to 'sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime')
37 files changed, 4096 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/LICENSE b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/LICENSE new file mode 100644 index 0000000000..8aa906c321 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/LICENSE @@ -0,0 +1,205 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + + + diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/META-INF/MANIFEST.MF b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..55a028261d --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/META-INF/MANIFEST.MF @@ -0,0 +1,45 @@ +Manifest-Version: 1.0
+SCA-Version: 1.1
+Bundle-Name: Apache Tuscany SCA JSON-RPC Binding Runtime
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 0
+Bundle-ManifestVersion: 2
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Description: Apache Tuscany SCA JSON-RPC Binding Runtime
+Import-Package: javax.security.auth.login,
+ javax.servlet,
+ javax.servlet.http,
+ org.apache.http,
+ org.apache.http.client,
+ org.apache.http.client.methods,
+ org.apache.http.conn,
+ org.apache.http.entity,
+ org.apache.http.util,
+ org.apache.tuscany.sca.assembly;version="2.0.0",
+ org.apache.tuscany.sca.binding.jsonrpc;version="2.0.0",
+ org.apache.tuscany.sca.common.http;version="2.0.0",
+ org.apache.tuscany.sca.core;version="2.0.0",
+ org.apache.tuscany.sca.databinding.javabeans;version="2.0.0",
+ org.apache.tuscany.sca.databinding.json;version="2.0.0",
+ org.apache.tuscany.sca.databinding.json.jackson;version="2.0.0",
+ org.apache.tuscany.sca.host.http;version="2.0.0",
+ org.apache.tuscany.sca.host.http.client;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef.java;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef.util;version="2.0.0",
+ org.apache.tuscany.sca.invocation;version="2.0.0",
+ org.apache.tuscany.sca.node;version="2.0.0",
+ org.apache.tuscany.sca.provider;version="2.0.0",
+ org.apache.tuscany.sca.runtime;version="2.0.0",
+ org.apache.tuscany.sca.web.javascript;version="2.0.0",
+ org.json,
+ org.oasisopen.sca;version="2.0.0",
+ org.oasisopen.sca.annotation;version="2.0.0"
+Bundle-SymbolicName: org.apache.tuscany.sca.binding.jsonrpc.runtime
+Bundle-DocURL: http://www.apache.org/
+Export-Package: org.apache.tuscany.sca.binding.jsonrpc.js.dojo;version="2.0.0";
+ uses:="org.apache.tuscany.sca.binding.jsonrpc,
+ org.apache.tuscany.sca.assembly,
+ org.apache.tuscany.sca.web.javascript,
+ javax.xml.namespace"
+
diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/NOTICE b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/NOTICE new file mode 100644 index 0000000000..28064e5de1 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/NOTICE @@ -0,0 +1,11 @@ +${pom.name} +Copyright (c) 2005 - 2008 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +This product includes/uses JSON-RPC JavaScript client (jsonrpc.js) + Copyright (c) 2003-2004 Jan-Klaas Kollhof + Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd + + diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/pom.xml b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/pom.xml new file mode 100644 index 0000000000..28df35f73c --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/pom.xml @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<project> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-modules</artifactId> + <version>2.0</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>tuscany-binding-jsonrpc-runtime</artifactId> + <name>Apache Tuscany SCA JSON-RPC Binding Runtime</name> + + <dependencies> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-binding-jsonrpc</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-core-spi</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-core</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-databinding</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-databinding-json</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-host-http</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-common-http</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-web-javascript</artifactId> + <version>2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.1.3</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-host-jetty</artifactId> + <version>2.0</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20090211</version> + </dependency> + + <!-- Explicitly add slf4j so that jabsorb uses the latest versions --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.6.1</version> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-jdk14</artifactId> + <version>1.6.1</version> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.5</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + <exclusions> + <exclusion> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </exclusion> + <exclusion> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </exclusion> + </exclusions> + </dependency> + + + <!-- Test Dependencies --> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-node-impl</artifactId> + <version>2.0</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-implementation-java-runtime</artifactId> + <version>2.0</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.8.1</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>httpunit</groupId> + <artifactId>httpunit</artifactId> + <version>1.7</version> + <scope>test</scope> + </dependency> + </dependencies> + +</project> diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/js/dojo/JSONRPCBindingJavascriptProxyFactory.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/js/dojo/JSONRPCBindingJavascriptProxyFactory.java new file mode 100644 index 0000000000..59a804a561 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/js/dojo/JSONRPCBindingJavascriptProxyFactory.java @@ -0,0 +1,77 @@ +/* + * 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.jsonrpc.js.dojo; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.web.javascript.JavascriptProxyFactory; + +public class JSONRPCBindingJavascriptProxyFactory implements JavascriptProxyFactory { + private static final QName NAME = JSONRPCBinding.TYPE; + + public Class<?> getModelType() { + return JSONRPCBinding.class; + } + + public QName getQName() { + return NAME; + } + + public String getJavascriptProxyFile() { + return null; + } + + public InputStream getJavascriptProxyFileAsStream() throws IOException { + return null; + } + + public String createJavascriptHeader(ComponentReference componentReference) throws IOException { + return "dojo.require('dojo.rpc.JsonService');"; + } + + public String createJavascriptReference(ComponentReference componentReference) throws IOException { + EndpointReference epr = componentReference.getEndpointReferences().get(0); + Endpoint targetEndpoint = epr.getTargetEndpoint(); + if (targetEndpoint.isUnresolved()) { + //force resolution and targetEndpoint binding calculations + //by calling the getInvocationChain + ((RuntimeEndpointReference) epr).getInvocationChains(); + targetEndpoint = epr.getTargetEndpoint(); + } + + Binding binding = targetEndpoint.getBinding(); + + URI targetURI = URI.create(binding.getURI()); + String targetPath = targetURI.getPath(); + + return "dojo.rpc.JsonService(\"" + targetPath + "?smd\")"; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc10Request.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc10Request.java new file mode 100644 index 0000000000..547d36abaf --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc10Request.java @@ -0,0 +1,70 @@ +/* + * 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.jsonrpc.protocol; + +import java.io.OutputStream; + +import org.apache.tuscany.sca.databinding.json.jackson.JacksonHelper; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; + +/** + * http://json-rpc.org/wiki/specification + * A remote method is invoked by sending a request to a remote service. The request is a single object serialized using JSON. + * <br>It has three properties: + * <ul> + * <li>method - A String containing the name of the method to be invoked. + * <li>params - An Array of objects to pass as arguments to the method. + * <li>id - The request id. This can be of any type. It is used to match the response with the request that it is replying to. + * </ul> + */ +public class JsonRpc10Request extends JsonRpcRequest { + + public JsonRpc10Request(String id, String method, Object[] params) { + super(JsonNodeFactory.instance.textNode(id), method, params); + } + + public JsonRpc10Request(ObjectNode req) { + super(req); + method = req.get("method").getTextValue(); + id = req.get("id"); + JsonNode args = req.get("params"); + if (args instanceof ArrayNode) { + // Positional parameters + ArrayNode array = (ArrayNode)args; + params = new Object[array.size()]; + for (int i = 0; i < params.length; i++) { + params[i] = array.get(i); + } + } else if (args == null) { + params = new Object[0]; + } else { + throw new IllegalArgumentException("Invalid request: params is not a JSON array - " + args); + } + } + + public void write(OutputStream os) throws Exception { + JacksonHelper.MAPPER.writeValue(os, getJsonNode()); + + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc10Response.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc10Response.java new file mode 100644 index 0000000000..4ca941580a --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc10Response.java @@ -0,0 +1,50 @@ +/* + * 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.jsonrpc.protocol; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ObjectNode; + +/** + * When the method invocation completes, the service must reply with a response. The response is a single object serialized using JSON. + * <br> + * It has three properties: + * + * <ul> + * <li>result - The Object that was returned by the invoked method. This must be null in case there was an error invoking the method. + * <li>error - An Error object if there was an error invoking the method. It must be null if there was no error. + * <li>id - This must be the same id as the request it is responding to. + * </ul> + */ +public class JsonRpc10Response extends JsonRpcResponse { + + public JsonRpc10Response(JsonNode id, JsonNode result) { + super(id, result); + } + + public JsonRpc10Response(JsonNode id, Throwable t) { + super(id, t); + } + + public JsonRpc10Response(ObjectNode response) { + super(response); + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20BatchRequest.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20BatchRequest.java new file mode 100644 index 0000000000..44627ddb08 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20BatchRequest.java @@ -0,0 +1,66 @@ +/* + * 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.jsonrpc.protocol; + +import java.util.ArrayList; +import java.util.List; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; +import org.codehaus.jackson.node.ObjectNode; + +public class JsonRpc20BatchRequest { + private List<JsonRpc20Request> requests = new ArrayList<JsonRpc20Request>(); + // The corresponding batch response + private JsonRpc20BatchResponse batchResponse; + + public JsonRpc20BatchRequest(ArrayNode array) { + super(); + batchResponse = new JsonRpc20BatchResponse(); + for (int i = 0; i < array.size(); i++) { + JsonNode req = array.get(i); + if (req instanceof ObjectNode) { + try { + requests.add(new JsonRpc20Request((ObjectNode)req)); + batchResponse.getResponses().add(null); + } catch (Exception e) { + // We should return invalid request errors + JsonRpc20Error error = + new JsonRpc20Error(null, JsonRpc20Error.PARSE_ERROR, JsonRpc20Error.PARSE_ERROR_MSG, req); + batchResponse.getResponses().add(error); + } + } else { + // We should return invalid request errors + JsonRpc20Error error = + new JsonRpc20Error(null, JsonRpc20Error.INVALID_REQUEST, JsonRpc20Error.INVALID_REQUEST_MSG, req); + batchResponse.getResponses().add(error); + } + } + } + + public List<JsonRpc20Request> getRequests() { + return requests; + } + + public JsonRpc20BatchResponse getBatchResponse() { + return batchResponse; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20BatchResponse.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20BatchResponse.java new file mode 100644 index 0000000000..d571458192 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20BatchResponse.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.jsonrpc.protocol; + +import java.util.ArrayList; +import java.util.List; + +import org.codehaus.jackson.node.ArrayNode; +import org.codehaus.jackson.node.JsonNodeFactory; + +public class JsonRpc20BatchResponse { + private List<JsonRpcResponse> results = new ArrayList<JsonRpcResponse>(); + + public JsonRpc20BatchResponse() { + super(); + } + + public List<JsonRpcResponse> getResponses() { + return results; + } + + public ArrayNode toJSONArray() { + ArrayNode jsonArray = JsonNodeFactory.instance.arrayNode(); + for (JsonRpcResponse result : results) { + jsonArray.add(result.getJsonNode()); + } + return jsonArray; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Error.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Error.java new file mode 100644 index 0000000000..30c61515ee --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Error.java @@ -0,0 +1,66 @@ +/* + * 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.jsonrpc.protocol; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; + +public class JsonRpc20Error extends JsonRpcResponse { + + public static final int PARSE_ERROR = 32700; + public static final String PARSE_ERROR_MSG = + "Parse error: Invalid JSON was received by the server. " + "An error occurred on the server while parsing the JSON text."; + + public static final int INVALID_REQUEST = -32600; + public static final String INVALID_REQUEST_MSG = "Invalid Request: The JSON sent is not a valid Request object."; + + public static final int METHOD_NOT_FOUND = -32601; + public static final String METHOD_NOT_FOUND_MSG = "Method not found: The method does not exist / is not available."; + + public static final int INVALID_PARAMS = -32602; + public static final String INVALID_PARAMS_MSG = "Invalid params Invalid method parameter(s)."; + + public static final int INTERNAL_ERROR = -32603; + public static final String INTERNAL_ERROR_MSG = "Internal error Internal JSON-RPC error."; + + // -32099 to -32000 Server error Reserved for implementation-defined server-errors. + + public JsonRpc20Error(JsonNode id, Throwable t) { + super(id, t); + this.jsonNode.put("jsonrpc", "2.0"); + this.jsonNode.put("code", INTERNAL_ERROR); + } + + public JsonRpc20Error(JsonNode id, int code, String message, JsonNode data) { + super(id, JsonNodeFactory.instance.nullNode()); + this.jsonNode.put("jsonrpc", "2.0"); + ObjectNode error = JsonNodeFactory.instance.objectNode(); + error.put("code", code); + error.put("message", message); + error.put("data", data); + this.jsonNode.put("error", error); + } + + public JsonRpc20Error(ObjectNode jsonNode) { + super(jsonNode); + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Request.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Request.java new file mode 100644 index 0000000000..22b3b7057f --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Request.java @@ -0,0 +1,113 @@ +/* + * 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.jsonrpc.protocol; + +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.databinding.json.jackson.JacksonHelper; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; +import org.json.JSONException; + +public class JsonRpc20Request extends JsonRpcRequest { + + protected ObjectNode mappedParams; + + public JsonRpc20Request(String id, String method, Object[] params) { + super(JsonNodeFactory.instance.textNode(id), method, params); + this.jsonNode.put("jsonrpc", "2.0"); + this.mappedParams = null; + } + + public JsonRpc20Request(String id, String method, ObjectNode mappedParams) { + super(JsonNodeFactory.instance.textNode(id), method, null); + this.jsonNode.put("jsonrpc", "2.0"); + this.mappedParams = mappedParams; + this.jsonNode.put("params", mappedParams); + } + + public JsonRpc20Request(ObjectNode req) throws JSONException { + super(req); + JsonNode node = req.get("jsonrpc"); + boolean v20 = node != null && "2.0".equals(node.getTextValue()); + if (!v20) { + throw new IllegalArgumentException("Invalid request: jsonrpc attribute must be \"2.0\""); + } + method = req.get("method").getTextValue(); + JsonNode idNode = req.get("id"); + if (idNode != null) { + id = idNode; + } + JsonNode args = req.get("params"); + if (args instanceof ArrayNode) { + // Positional parameters + ArrayNode array = (ArrayNode)args; + params = new Object[array.size()]; + for (int i = 0; i < params.length; i++) { + params[i] = array.get(i); + } + } else if (args instanceof ObjectNode) { + ObjectNode map = (ObjectNode)args; + mappedParams = map; + params = null; + } else if (args == null) { + params = new Object[0]; + } else { + throw new IllegalArgumentException("Invalid request: params is not a JSON array - " + args); + } + } + + public void write(OutputStream os) throws Exception { + // Construct a map to hold JSON-RPC request + final Map<String, Object> jsonRequest = new HashMap<String, Object>(); + jsonRequest.put("jsonrpc", "2.0"); + jsonRequest.put("id", id); + jsonRequest.put("method", method); + + if (mappedParams != null) { + jsonRequest.put("params", mappedParams); + } + + else { + List<Object> parameters = null; + + if (params != null) { + parameters = Arrays.asList(params); + } else { + parameters = Collections.emptyList(); + } + + jsonRequest.put("params", parameters); + } + JacksonHelper.MAPPER.writeValue(os, jsonRequest); + + } + + public ObjectNode getMappedParams() { + return mappedParams; + } +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Response.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Response.java new file mode 100644 index 0000000000..aa433ede6c --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpc20Response.java @@ -0,0 +1,37 @@ +/* + * 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.jsonrpc.protocol; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ObjectNode; + +public class JsonRpc20Response extends JsonRpcResponse { + + public JsonRpc20Response(JsonNode id, JsonNode result) { + super(id, result); + this.jsonNode.put("jsonrpc", "2.0"); + + } + + public JsonRpc20Response(ObjectNode jsonNode) { + super(jsonNode); + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpcRequest.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpcRequest.java new file mode 100644 index 0000000000..cd98a30976 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpcRequest.java @@ -0,0 +1,92 @@ +/* + * 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.jsonrpc.protocol; + +import java.io.OutputStream; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.NullNode; +import org.codehaus.jackson.node.ObjectNode; + +/** + * http://json-rpc.org/wiki/specification + * A remote method is invoked by sending a request to a remote service. The request is a single object serialized using JSON. + * <br>It has three properties: + * <ul> + * <li>method - A String containing the name of the method to be invoked. + * <li>params - An Array of objects to pass as arguments to the method. + * <li>id - The request id. This can be of any type. It is used to match the response with the request that it is replying to. + * </ul> + */ +public abstract class JsonRpcRequest { + protected String method; + protected JsonNode id; + protected Object[] params; + + protected ObjectNode jsonNode; + + public JsonRpcRequest(ObjectNode jsonNode) { + super(); + this.jsonNode = jsonNode; + } + + public JsonRpcRequest(JsonNode id, String method, Object[] params) { + super(); + this.id = id; + this.method = method; + this.params = params; + ObjectNode req = JsonNodeFactory.instance.objectNode(); + req.put("method", method); + req.put("id", id); + if (params != null) { + ArrayNode args = JsonNodeFactory.instance.arrayNode(); + for (Object p : params) { + args.add(JsonNodeFactory.instance.POJONode(p)); + } + req.put("params", args); + } + this.jsonNode = req; + } + + public abstract void write(OutputStream os) throws Exception; + + public boolean isNotification() { + return id == null || (id instanceof NullNode); + } + + public String getMethod() { + return method; + } + + public JsonNode getId() { + return id; + } + + public Object[] getParams() { + return params; + } + + public ObjectNode getJsonNode() { + return jsonNode; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpcResponse.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpcResponse.java new file mode 100644 index 0000000000..8186d89030 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/protocol/JsonRpcResponse.java @@ -0,0 +1,98 @@ +/* + * 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.jsonrpc.protocol; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; + +import org.apache.tuscany.sca.databinding.json.jackson.JacksonHelper; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; + +/** + * When the method invocation completes, the service must reply with a response. The response is a single object serialized using JSON. + * <br> + * It has three properties: + * + * <ul> + * <li>result - The Object that was returned by the invoked method. This must be null in case there was an error invoking the method. + * <li>error - An Error object if there was an error invoking the method. It must be null if there was no error. + * <li>id - This must be the same id as the request it is responding to. + * </ul> + */ +public abstract class JsonRpcResponse { + public static final int REMOTE_EXCEPTION = 490; + + protected ObjectNode jsonNode; + + public JsonRpcResponse(ObjectNode response) { + super(); + this.jsonNode = response; + } + + public JsonRpcResponse(JsonNode id, Throwable t) { + super(); + ObjectNode response = JsonNodeFactory.instance.objectNode(); + response.put("id", id); + // response.put("result", JsonNodeFactory.instance.nullNode()); + response.put("error", mapError(t)); + this.jsonNode = response; + } + + public JsonRpcResponse(JsonNode id, JsonNode result) { + super(); + ObjectNode response = JsonNodeFactory.instance.objectNode(); + response.put("id", id); + response.put("result", result); + // response.put("error", JsonNodeFactory.instance.nullNode()); + this.jsonNode = response; + } + + private ObjectNode mapError(Throwable t) { + ObjectNode obj = JsonNodeFactory.instance.objectNode(); + // obj.put("msg", t.getMessage()); + obj.put("code", REMOTE_EXCEPTION); + obj.put("message", t.getMessage()); + ObjectNode exception = JsonNodeFactory.instance.objectNode(); + exception.put("class", t.getClass().getName()); + exception.put("message", t.getMessage()); + exception.put("stackTrace", JsonRpc20Error.stackTrace(t)); + obj.put("data", exception); + return obj; + } + + public void write(Writer writer) throws IOException { + JacksonHelper.MAPPER.writeValue(writer, jsonNode); + } + + public static String stackTrace(Throwable t) { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + return sw.toString(); + } + + public ObjectNode getJsonNode() { + return jsonNode; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCBindingProviderFactory.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCBindingProviderFactory.java new file mode 100644 index 0000000000..8ecadf4a92 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCBindingProviderFactory.java @@ -0,0 +1,66 @@ +/* + * 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.jsonrpc.provider; + +import org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.host.http.ServletHostHelper; +import org.apache.tuscany.sca.host.http.client.HttpClientFactory; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +/** + * JSON-RPC Provider Factory + * + * @version $Rev$ $Date$ + */ +public class JSONRPCBindingProviderFactory implements BindingProviderFactory<JSONRPCBinding> { + + private MessageFactory messageFactory; + private ServletHost servletHost; + private HttpClientFactory httpClientFactory; + + public JSONRPCBindingProviderFactory(ExtensionPointRegistry extensionPoints) { + this.servletHost = ServletHostHelper.getServletHost(extensionPoints); + FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + messageFactory = modelFactories.getFactory(MessageFactory.class); + this.httpClientFactory = HttpClientFactory.getInstance(extensionPoints); + } + + public ReferenceBindingProvider createReferenceBindingProvider(RuntimeEndpointReference endpointReference) { + + return new JSONRPCReferenceBindingProvider(httpClientFactory, endpointReference); + } + + public ServiceBindingProvider createServiceBindingProvider(RuntimeEndpoint endpoint) { + return new JSONRPCServiceBindingProvider(endpoint, messageFactory, servletHost); + } + + public Class<JSONRPCBinding> getModelType() { + return JSONRPCBinding.class; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCDatabindingHelper.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCDatabindingHelper.java new file mode 100644 index 0000000000..059e44cc7e --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCDatabindingHelper.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.jsonrpc.provider; + +import java.util.List; + +import org.apache.tuscany.sca.databinding.json.JSONDataBinding; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.codehaus.jackson.JsonNode; + +/** + * JSONRPC Binding helper class to handle setting the proper + * data binding in the interface contract for JSONRPC + * services and references + * + * @version $Rev$ $Date$ + */ +public class JSONRPCDatabindingHelper { + + @SuppressWarnings("unchecked") + static void setDataBinding(Interface interfaze) { + List<Operation> operations = interfaze.getOperations(); + for (Operation operation : operations) { + operation.setDataBinding(JSONDataBinding.NAME); + DataType<List<DataType>> inputType = operation.getInputType(); + if (inputType != null) { + List<DataType> logical = inputType.getLogical(); + for (DataType inArg : logical) { + inArg.setDataBinding(JSONDataBinding.NAME); + inArg.setPhysical(JsonNode.class); +// if (!SimpleJavaDataBinding.NAME.equals(inArg.getDataBinding()) || inArg.getPhysical() == BigDecimal.class) { +// inArg.setDataBinding(JSONDataBinding.NAME); +// } + } + } + + for (DataType outputType : operation.getOutputType().getLogical()) { + if (outputType != null) { + outputType.setDataBinding(JSONDataBinding.NAME); + outputType.setPhysical(JsonNode.class); +// if (!SimpleJavaDataBinding.NAME.equals(outputType.getDataBinding()) || outputType.getPhysical() == BigDecimal.class) { +// outputType.setDataBinding(JSONDataBinding.NAME); +// } + } + } + } + } +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCReferenceBindingProvider.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCReferenceBindingProvider.java new file mode 100644 index 0000000000..38688a8d34 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCReferenceBindingProvider.java @@ -0,0 +1,91 @@ +/* + * 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.jsonrpc.provider; + +import org.apache.http.client.HttpClient; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.host.http.client.HttpClientFactory; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; + +/** + * Implementation of the JSONRPC Binding Provider for References + * + * @version $Rev$ $Date$ + */ +public class JSONRPCReferenceBindingProvider implements ReferenceBindingProvider { + + private EndpointReference endpointReference; + private RuntimeComponentReference reference; + private InterfaceContract referenceContract; + + private HttpClientFactory httpClientFactory; + private HttpClient httpClient; + + public JSONRPCReferenceBindingProvider(HttpClientFactory httpClientFactory, EndpointReference endpointReference) { + this.httpClientFactory = httpClientFactory; + this.endpointReference = endpointReference; + this.reference = (RuntimeComponentReference)endpointReference.getReference(); + + + //clone the service contract to avoid databinding issues + /* + try { + this.referenceContract = (InterfaceContract)reference.getInterfaceContract().clone(); + } catch(CloneNotSupportedException e) { + this.referenceContract = reference.getInterfaceContract(); + } + + JSONRPCDatabindingHelper.setDataBinding(referenceContract.getInterface()); + */ + + // Create an HTTP client + // httpClient = createHttpClient(); + } + + public InterfaceContract getBindingInterfaceContract() { + //return referenceContract; + return reference.getInterfaceContract(); + } + + public Invoker createInvoker(Operation operation) { + // final Interface intf = reference.getInterfaceContract().getInterface(); + return new JsonRpcInvoker(endpointReference, operation, httpClient); + } + + public void start() { + // Create an HTTP client + httpClient = httpClientFactory.createHttpClient(); + } + + public void stop() { + if (httpClient != null) { + httpClient.getConnectionManager().shutdown(); + } + } + + public boolean supportsOneWayInvocation() { + return false; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCServiceBindingProvider.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCServiceBindingProvider.java new file mode 100644 index 0000000000..82b4c351a3 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCServiceBindingProvider.java @@ -0,0 +1,137 @@ +/* + * 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.jsonrpc.provider; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.Servlet; + +import org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding; +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; + + +/** + * Implementation of the JSONRPC Binding Provider for Services + * + * @version $Rev$ $Date$ + */ +public class JSONRPCServiceBindingProvider implements ServiceBindingProvider { + private MessageFactory messageFactory; + + private RuntimeEndpoint endpoint; + private RuntimeComponent component; + private RuntimeComponentService service; + private InterfaceContract serviceContract; + private JSONRPCBinding binding; + private ServletHost servletHost; + private List<String> servletMappings = new ArrayList<String>(); + + public JSONRPCServiceBindingProvider(RuntimeEndpoint endpoint, + MessageFactory messageFactory, + ServletHost servletHost) { + this.endpoint = endpoint; + this.component = (RuntimeComponent)endpoint.getComponent(); + this.service = (RuntimeComponentService)endpoint.getService(); + this.binding = (JSONRPCBinding) endpoint.getBinding(); + this.messageFactory = messageFactory; + this.servletHost = servletHost; + + //clone the service contract to avoid databinding issues + try { + this.serviceContract = (InterfaceContract)service.getInterfaceContract().clone(); + } catch(CloneNotSupportedException e) { + this.serviceContract = service.getInterfaceContract(); + } + + JSONRPCDatabindingHelper.setDataBinding(serviceContract.getInterface()); + } + + public InterfaceContract getBindingInterfaceContract() { + return serviceContract; + } + + public boolean supportsOneWayInvocation() { + return false; + } + + public void start() { + // Set default databinding to json + // replaced by JSONRPCDatabindingHelper.setDataBinding(serviceContract.getInterface()); above + //serviceContract.getInterface().resetDataBinding(JSONDataBinding.NAME); + + // Determine the service business interface + Class<?> serviceInterface = getTargetJavaClass(serviceContract.getInterface()); + + // Create a Java proxy to the target service + Object proxy = component.getComponentContext().getServiceReference(serviceInterface, endpoint).getService(); + + // Create and register a Servlet for this service + JsonRpcServlet serviceServlet = + new JsonRpcServlet(messageFactory, endpoint, serviceInterface, proxy); + String mapping = registerServlet(serviceServlet); + servletMappings.add(mapping); + } + + public String registerServlet(Servlet servlet) { + // Create our HTTP service listener Servlet and register it with the + // Servlet host + String servletMapping = binding.getURI(); + if (!servletMapping.endsWith("/")) { + servletMapping += "/"; + } + if (!servletMapping.endsWith("*")) { + servletMapping += "*"; + } + + String mappedURI = servletHost.addServletMapping(servletMapping, servlet); + String deployedURI = mappedURI; + if (deployedURI.endsWith("*")) { + deployedURI = deployedURI.substring(0, deployedURI.length() - 1); + } + binding.setURI(deployedURI); + endpoint.setDeployedURI(deployedURI); + return mappedURI; + } + + public void stop() { + + // Remove the Servlet mappings we've added + for (String mapping: servletMappings) { + servletHost.removeServletMapping(mapping); + } + + } + + private Class<?> getTargetJavaClass(Interface targetInterface) { + // TODO: right now assume that the target is always a Java + // Implementation. Need to figure out how to generate Java + // Interface in cases where the target is not a Java Implementation + return ((JavaInterface)targetInterface).getJavaClass(); + } +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JavaToSmd.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JavaToSmd.java new file mode 100644 index 0000000000..3cbcdf735d --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JavaToSmd.java @@ -0,0 +1,131 @@ +/* + * 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.jsonrpc.provider; + +import java.lang.reflect.Method; +import java.util.Collection; + +import org.json.JSONArray; +import org.json.JSONObject; + +/** + * Utility class to create a Simple Method Description (SMD) descriptor + * from a Java class. See http://dojo.jot.com/SMD. + * + * TODO: Change to work from the Tuscany Interface instead of a Java class + * + * @version $Rev$ $Date$ + */ +public class JavaToSmd { + + public static String interfaceToSmd(Class<?> klazz, String serviceUrl) { + try { + String name = klazz.getSimpleName(); + Method[] methods = klazz.getMethods(); + + JSONObject smd = new JSONObject(); + smd.put("SMDVersion", ".1"); + smd.put("objectName", name); + smd.put("serviceType", "JSON-RPC"); + smd.put("serviceURL", serviceUrl); + + JSONArray services = new JSONArray(); + for (int i = 0; i < methods.length; i++) { + JSONObject service = new JSONObject(); + Class<?>[] params = methods[i].getParameterTypes(); + JSONArray paramArray = new JSONArray(); + for (int j = 0; j < params.length; j++) { + JSONObject param = new JSONObject(); + param.put("name", "param" + j); + param.put("type", getJSONType(params[j])); + paramArray.put(param); + } + service.put("name", methods[i].getName()); + service.put("parameters", paramArray); + services.put(service); + } + + smd.put("methods", services); + + return smd.toString(2); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + + } + + public static String interfaceToSmd20(Class<?> klazz, String serviceUrl) { + try { + String name = klazz.getSimpleName(); + Method[] methods = klazz.getMethods(); + + JSONObject smd = new JSONObject(); + smd.put("SMDVersion", "2.0"); + smd.put("transport", "POST"); + smd.put("envelope", "JSON-RPC-1.0"); + smd.put("target", serviceUrl); + smd.put("id", klazz.getName()); + smd.put("description", "JSON-RPC service provided by Tuscany: " + name); + + JSONObject services = new JSONObject(); + for (int i = 0; i < methods.length; i++) { + JSONObject service = new JSONObject(); + Class<?>[] params = methods[i].getParameterTypes(); + JSONArray paramArray = new JSONArray(); + for (int j = 0; j < params.length; j++) { + JSONObject param = new JSONObject(); + param.put("name", "param" + j); + param.put("type", getJSONType(params[j])); + paramArray.put(param); + } + service.put("parameters", paramArray); + services.put(methods[i].getName(), service); + } + + smd.put("services", services); + + return smd.toString(2); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + + } + + private static String getJSONType(Class<?> type) { + if (type == boolean.class || type == Boolean.class) { + return "boolean"; + } + if (type == String.class) { + return "string"; + } + if (byte.class == type || short.class == type + || int.class == type + || long.class == type + || float.class == type + || double.class == type + || Number.class.isAssignableFrom(type)) { + return "number"; + } + if (type.isArray() || Collection.class.isAssignableFrom(type)) { + return "array"; + } + return "object"; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcInvoker.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcInvoker.java new file mode 100644 index 0000000000..ca21599b14 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcInvoker.java @@ -0,0 +1,254 @@ +/* + * 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.jsonrpc.provider; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.List; +import java.util.UUID; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentProducer; +import org.apache.http.entity.EntityTemplate; +import org.apache.http.entity.StringEntity; +import org.apache.http.util.EntityUtils; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc10Request; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc20Request; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpcRequest; +import org.apache.tuscany.sca.databinding.json.JSONDataBinding; +import org.apache.tuscany.sca.databinding.json.jackson.JacksonHelper; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.JavaOperation; +import org.apache.tuscany.sca.invocation.DataExchangeSemantics; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.type.TypeFactory; +import org.codehaus.jackson.node.NullNode; +import org.codehaus.jackson.node.ObjectNode; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Invoker for the JSONRPC Binding + * + * @version $Rev$ $Date$ + */ +public class JsonRpcInvoker implements Invoker, DataExchangeSemantics { + private EndpointReference endpointReference; + private Operation operation; + private String uri; + private HttpClient httpClient; + + public JsonRpcInvoker(EndpointReference endpointReference, Operation operation, HttpClient httpClient) { + this.endpointReference = endpointReference; + this.operation = operation; + this.uri = endpointReference.getDeployedURI(); + this.httpClient = httpClient; + } + + public Message invoke(Message msg) { + HttpPost post = null; + HttpResponse response = null; + try { + String requestId = UUID.randomUUID().toString(); + post = new HttpPost(uri); + HttpEntity entity = null; + Object[] args = msg.getBody(); + final String db = msg.getOperation().getInputWrapper().getDataBinding(); + + if (!db.equals(JSONDataBinding.NAME)) { + Object[] params = new Object[0]; + // Extract the arguments + args = msg.getBody(); + + if (args instanceof Object[]) { + params = (Object[])args; + } + + JsonRpcRequest req = null; + if (JSONRPCBinding.VERSION_20.equals(((JSONRPCBinding)endpointReference.getBinding()).getVersion())) { + req = new JsonRpc20Request(requestId, msg.getOperation().getName(), params); + } else { + req = new JsonRpc10Request(requestId, msg.getOperation().getName(), params); + } + final JsonRpcRequest json = req; + + // Create content producer so that we can stream the json result out + ContentProducer cp = new ContentProducer() { + public void writeTo(OutputStream outstream) throws IOException { + // mapper.writeValue(outstream, req.toJSONObject().toString()); + try { + json.write(outstream); + } catch (Exception e) { + throw new IOException(e); + } + } + }; + entity = new EntityTemplate(cp); + } else { + // Single string argument + entity = new StringEntity((String)args[0], "UTF-8"); + } + + post.setEntity(entity); + + response = httpClient.execute(post); + + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + //success + + entity = response.getEntity(); + String entityResponse = EntityUtils.toString(entity); + entity.consumeContent(); + if (!db.equals(JSONDataBinding.NAME)) { + ObjectNode jsonResponse = (ObjectNode)JacksonHelper.MAPPER.readTree(entityResponse); + + if (jsonResponse.has("error") && jsonResponse.get("error") != NullNode.instance) { + processException(jsonResponse); + } + DataType<List<DataType>> outputType = operation.getOutputType(); + DataType returnType = + (outputType != null && !outputType.getLogical().isEmpty()) ? outputType.getLogical().get(0) + : null; + + if (returnType == null) { + msg.setBody(null); + return msg; + } + + //check requestId + if (!requestId.equalsIgnoreCase(jsonResponse.get("id").getTextValue())) { + throw new ServiceRuntimeException("Invalid response id:" + requestId); + } + + JsonNode rawResult = jsonResponse.get("result"); + + Class<?> returnClass = returnType.getPhysical(); + Type genericReturnType = returnType.getGenericType(); + + ObjectMapper mapper = createObjectMapper(returnClass); + String json = mapper.writeValueAsString(rawResult); + + Object body = mapper.readValue(json, TypeFactory.type(genericReturnType)); + + msg.setBody(body); + } else { + msg.setBody(entityResponse); + } + + } else { + // Consume the content so the connection can be released + response.getEntity().consumeContent(); + throw new ServiceRuntimeException("Abnormal HTTP response: " + response.getStatusLine().toString()); + } + } catch (RuntimeException e) { + throw e; + } catch (Error e) { + throw e; + } catch (Exception e) { + // e.printStackTrace(); + msg.setFaultBody(e); + } catch (Throwable e) { + throw new ServiceRuntimeException(e); + } + + return msg; + } + + public static ObjectMapper createObjectMapper(Class<?> cls) { + return JacksonHelper.createObjectMapper(cls); + } + + private String opt(ObjectNode node, String name) { + JsonNode value = node.get(name); + if (value == null) { + return null; + } else { + return value.getValueAsText(); + } + } + + /** + * Generate and throw exception based on the data in the 'responseMessage' + */ + protected void processException(ObjectNode responseMessage) throws Throwable { + // FIXME: We need to find a way to build Java exceptions out of the json-rpc error + JsonNode error = responseMessage.get("error"); + if (error != null) { + Object data = error.get("data"); + if (data instanceof ObjectNode) { + ObjectNode fault = (ObjectNode)data; + String javaClass = opt(fault, "class"); + String message = opt(fault, "message"); + String stackTrace = opt(fault, "stackTrace"); + if (javaClass != null) { + if (stackTrace != null) { + message = message + "\n" + stackTrace; + } + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + if (operation instanceof JavaOperation) { + Method method = ((JavaOperation)operation).getJavaMethod(); + classLoader = method.getDeclaringClass().getClassLoader(); + } + Class<? extends Throwable> exceptionClass = + (Class<? extends Throwable>)Class.forName(javaClass, false, classLoader); + Constructor<? extends Throwable> ctor = null; + Throwable ex = null; + try { + ctor = exceptionClass.getConstructor(String.class, Throwable.class); + ex = ctor.newInstance(message, null); + } catch (NoSuchMethodException e1) { + try { + ctor = exceptionClass.getConstructor(String.class); + ex = ctor.newInstance(message); + } catch (NoSuchMethodException e2) { + try { + ctor = exceptionClass.getConstructor(Throwable.class); + ex = ctor.newInstance(null); + } catch (NoSuchMethodException e3) { + ctor = exceptionClass.getConstructor(); + ex = ctor.newInstance(); + } + } + } + throw ex; + } + } + throw new ServiceRuntimeException(error.toString()); + } + } + + @Override + public boolean allowsPassByReference() { + return true; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcServlet.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcServlet.java new file mode 100644 index 0000000000..4261f5bffc --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcServlet.java @@ -0,0 +1,364 @@ +/* + * 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.jsonrpc.provider; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.List; + +import javax.security.auth.login.LoginException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.codec.binary.Base64; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc10Request; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc10Response; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc20BatchRequest; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc20Error; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc20Request; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpc20Response; +import org.apache.tuscany.sca.binding.jsonrpc.protocol.JsonRpcResponse; +import org.apache.tuscany.sca.databinding.json.JSONDataBinding; +import org.apache.tuscany.sca.databinding.json.jackson.JacksonHelper; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; +import org.oasisopen.sca.ServiceRuntimeException; + +public class JsonRpcServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + transient MessageFactory messageFactory; + + transient Binding binding; + transient String serviceName; + transient Object serviceInstance; + transient RuntimeEndpoint endpoint; + transient Class<?> serviceInterface; + + public JsonRpcServlet(MessageFactory messageFactory, + RuntimeEndpoint endpoint, + Class<?> serviceInterface, + Object serviceInstance) { + this.endpoint = endpoint; + this.messageFactory = messageFactory; + this.binding = endpoint.getBinding(); + this.serviceName = binding.getName(); + this.serviceInterface = serviceInterface; + this.serviceInstance = serviceInstance; + } + + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, + IOException { + + if ("smd".equals(request.getQueryString())) { + handleSMDRequest(request, response); + return; + } + try { + handleJsonRpcInvocation(request, response); + + } catch (RuntimeException re) { + if (re.getCause() instanceof javax.security.auth.login.LoginException) { + response.setHeader("WWW-Authenticate", "BASIC realm=\"" + "ldap-realm" + "\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } else { + throw re; + } + } + + } + + private void handleJsonRpcInvocation(HttpServletRequest request, HttpServletResponse response) + throws UnsupportedEncodingException, IOException, ServletException { + + // Decode using the charset in the request if it exists otherwise + // use UTF-8 as this is what all browser implementations use. + // The JSON-RPC-Java JavaScript client is ASCII clean so it + // although here we can correctly handle data from other clients + // that do not escape non ASCII data + String charset = request.getCharacterEncoding(); + if (charset == null) { + charset = "UTF-8"; + } + + JsonNode root = null; + if (request.getMethod().equals("GET")) { + // if using GET Support (see http://groups.google.com/group/json-rpc/web/json-rpc-over-http) + + //parse the GET QueryString + try { + String params = + new String(Base64.decodeBase64(URLDecoder.decode(request.getParameter("params"), charset) + .getBytes())); + StringBuilder sb = new StringBuilder(); + sb.append("{"); + sb.append("\"method\": \"" + request.getParameter("method") + "\","); + sb.append("\"params\": " + params + ","); + sb.append("\"id\":" + request.getParameter("id")); + sb.append("}"); + + root = JacksonHelper.MAPPER.readTree(sb.toString()); + } catch (Throwable e) { + JsonRpc10Response error = + new JsonRpc10Response(JsonNodeFactory.instance.textNode(request.getParameter("id")), e); + error.write(response.getWriter()); + return; + } + } else { + root = JacksonHelper.MAPPER.readTree(request.getReader()); + } + + try { + if (root.isArray()) { + ArrayNode input = (ArrayNode)root; + JsonRpc20BatchRequest batchReq = new JsonRpc20BatchRequest(input); + for (int i = 0; i < batchReq.getRequests().size(); i++) { + JsonRpcResponse result = batchReq.getBatchResponse().getResponses().get(i); + if (result == null) { + result = invoke(batchReq.getRequests().get(i)); + batchReq.getBatchResponse().getResponses().set(i, result); + } + } + ArrayNode responses = batchReq.getBatchResponse().toJSONArray(); + JacksonHelper.MAPPER.writeValue(response.getWriter(), responses); + } else { + if (root.has("jsonrpc")) { + JsonRpc20Request jsonReq = new JsonRpc20Request((ObjectNode)root); + JsonRpcResponse jsonResult = invoke(jsonReq); + if (jsonResult != null) { + jsonResult.write(response.getWriter()); + } + } else { + JsonRpc10Request jsonReq = new JsonRpc10Request((ObjectNode)root); + JsonRpc10Response jsonResult = invoke(jsonReq); + if (jsonResult != null) { + jsonResult.write(response.getWriter()); + } + } + } + } catch (Throwable e) { + throw new ServletException(e); + } + } + + private JsonRpcResponse invoke(JsonRpc20Request request) throws Exception { + if (request.isNotification()) { + return null; + } + // invoke the request + String method = request.getMethod(); + Object[] params = request.getParams(); + + Object result = null; + Operation jsonOperation = findOperation(method); + + // Invoke the get operation on the service implementation + Message requestMessage = messageFactory.createMessage(); + requestMessage.setOperation(jsonOperation); + + requestMessage.getHeaders().put("RequestMessage", request); + + if (jsonOperation.getInputWrapper().getDataBinding().equals(JSONDataBinding.NAME)) { + requestMessage.setBody(new Object[] {JacksonHelper.toString(request.getJsonNode())}); + } else { + requestMessage.setBody(params); + } + requestMessage.setBody(params); + + Message responseMessage = null; + try { + + //result = wire.invoke(jsonOperation, args); + responseMessage = endpoint.getInvocationChain(jsonOperation).getHeadInvoker().invoke(requestMessage); + } catch (RuntimeException re) { + if (re.getCause() instanceof javax.security.auth.login.LoginException) { + throw re; + } else { + JsonRpc20Error error = new JsonRpc20Error(request.getId(), re); + return error; + } + } + + if (!responseMessage.isFault()) { + if (jsonOperation.getOutputWrapper().getDataBinding().equals(JSONDataBinding.NAME)) { + result = responseMessage.getBody(); + return new JsonRpc20Response((ObjectNode)JacksonHelper.MAPPER.readTree(result.toString())); + } else { + if (jsonOperation.getOutputType().getLogical().size() == 0) { + // void operation (json-rpc notification) + try { + JsonRpc20Response response = new JsonRpc20Response(request.getId(), null); + return response; + } catch (Exception e) { + throw new ServiceRuntimeException("Unable to create JSON response", e); + } + + } else { + // regular operation returning some value + try { + result = responseMessage.getBody(); + JsonRpc20Response response = new JsonRpc20Response(request.getId(), (JsonNode)result); + //get response to send to client + return response; + } catch (Exception e) { + throw new ServiceRuntimeException("Unable to create JSON response", e); + } + } + } + + } else { + //exception thrown while executing the invocation + Throwable exception = (Throwable)responseMessage.getBody(); + + JsonRpc20Error error = new JsonRpc20Error(request.getId(), exception); + return error; + } + + } + + private JsonRpc10Response invoke(JsonRpc10Request request) throws Exception { + if (request.isNotification()) { + return null; + } + // invoke the request + String method = request.getMethod(); + Object[] params = request.getParams(); + + Object result = null; + Operation jsonOperation = findOperation(method); + + // Invoke the get operation on the service implementation + Message requestMessage = messageFactory.createMessage(); + requestMessage.setOperation(jsonOperation); + + requestMessage.getHeaders().put("RequestMessage", request); + if (jsonOperation.getInputWrapper().getDataBinding().equals(JSONDataBinding.NAME)) { + requestMessage.setBody(new Object[] {JacksonHelper.toString(request.getJsonNode())}); + } else { + requestMessage.setBody(params); + } + + Message responseMessage = null; + try { + + //result = wire.invoke(jsonOperation, args); + responseMessage = endpoint.getInvocationChain(jsonOperation).getHeadInvoker().invoke(requestMessage); + } catch (RuntimeException e) { + if (e.getCause() instanceof LoginException) { + throw e; + } else { + JsonRpc10Response error = new JsonRpc10Response(request.getId(), e); + return error; + } + } + + if (!responseMessage.isFault()) { + if (jsonOperation.getOutputWrapper().getDataBinding().equals(JSONDataBinding.NAME)) { + result = responseMessage.getBody(); + return new JsonRpc10Response((ObjectNode)JacksonHelper.MAPPER.readTree(result.toString())); + } else { + if (jsonOperation.getOutputType().getLogical().size() == 0) { + // void operation (json-rpc notification) + JsonRpc10Response response = + new JsonRpc10Response(request.getId(), JsonNodeFactory.instance.nullNode()); + return response; + + } else { + // regular operation returning some value + result = responseMessage.getBody(); + JsonRpc10Response response = new JsonRpc10Response(request.getId(), (JsonNode)result); + //get response to send to client + return response; + } + } + + } else { + //exception thrown while executing the invocation + Throwable exception = (Throwable)responseMessage.getBody(); + + JsonRpc10Response error = new JsonRpc10Response(request.getId(), exception); + return error; + } + + } + + /** + * Find the operation from the component service contract + * @param componentService + * @param method + * @return + */ + private Operation findOperation(String method) { + if (method.contains(".")) { + method = method.substring(method.lastIndexOf(".") + 1); + } + + List<Operation> operations = endpoint.getComponentServiceInterfaceContract().getInterface().getOperations(); + //endpoint.getComponentTypeServiceInterfaceContract().getInterface().getOperations(); + //componentService.getBindingProvider(binding).getBindingInterfaceContract().getInterface().getOperations(); + + Operation result = null; + for (Operation o : operations) { + if (o.isDynamic()) + return o; + if (o.getName().equalsIgnoreCase(method)) { + result = o; + break; + } + } + + return result; + } + + /** + * handles requests for the SMD descriptor for a service + */ + protected void handleSMDRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, + UnsupportedEncodingException { + String serviceUrl = request.getRequestURL().toString(); + String smd = null; + if (JSONRPCBinding.VERSION_20.equals(((JSONRPCBinding)binding).getVersion())) { + smd = JavaToSmd.interfaceToSmd20(serviceInterface, serviceUrl); + } else { + smd = JavaToSmd.interfaceToSmd(serviceInterface, serviceUrl); + } + + response.setContentType("application/json;charset=utf-8"); + OutputStream out = response.getOutputStream(); + byte[] bout = smd.getBytes("UTF-8"); + out.write(bout); + out.flush(); + out.close(); + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory new file mode 100644 index 0000000000..ceb74cffce --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory @@ -0,0 +1,20 @@ +# 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.
+
+# Implementation class for the binding extension
+org.apache.tuscany.sca.binding.jsonrpc.provider.JSONRPCBindingProviderFactory;model=org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding
+
diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.web.javascript.JavascriptProxyFactory b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.web.javascript.JavascriptProxyFactory new file mode 100644 index 0000000000..231cd4085d --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.web.javascript.JavascriptProxyFactory @@ -0,0 +1,19 @@ +# 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. + +# Implementation class for the Javascript Proxy Factory +org.apache.tuscany.sca.binding.jsonrpc.js.dojo.JSONRPCBindingJavascriptProxyFactory;qname=http://tuscany.apache.org/xmlns/sca/1.1#binding.jsonrpc,model=org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding
\ No newline at end of file diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/org/apache/tuscany/sca/binding/jsonrpc/provider/jsonrpc.js b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/org/apache/tuscany/sca/binding/jsonrpc/provider/jsonrpc.js new file mode 100644 index 0000000000..d837bab91c --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/main/resources/org/apache/tuscany/sca/binding/jsonrpc/provider/jsonrpc.js @@ -0,0 +1,493 @@ +/* + * JSON-RPC JavaScript client + * + * $Id: jsonrpc.js,v 1.36.2.3 2006/03/08 15:09:37 mclark Exp $ + * + * Copyright (c) 2003-2004 Jan-Klaas Kollhof + * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd + * + * This code is based on Jan-Klaas' JavaScript o lait library (jsolait). + * + * Licensed 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. + * + */ + +/* + * Modifications for Apache Tuscany: + * - JSONRpcClient_createMethod changed so callback is last arg + */ + +/* escape a character */ + +escapeJSONChar = +function escapeJSONChar(c) +{ + if(c == "\"" || c == "\\") return "\\" + c; + else if (c == "\b") return "\\b"; + else if (c == "\f") return "\\f"; + else if (c == "\n") return "\\n"; + else if (c == "\r") return "\\r"; + else if (c == "\t") return "\\t"; + var hex = c.charCodeAt(0).toString(16); + if(hex.length == 1) return "\\u000" + hex; + else if(hex.length == 2) return "\\u00" + hex; + else if(hex.length == 3) return "\\u0" + hex; + else return "\\u" + hex; +}; + + +/* encode a string into JSON format */ + +escapeJSONString = +function escapeJSONString(s) +{ + /* The following should suffice but Safari's regex is b0rken + (doesn't support callback substitutions) + return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, + escapeJSONChar) + "\""; + */ + + /* Rather inefficient way to do it */ + var parts = s.split(""); + for(var i=0; i < parts.length; i++) { + var c =parts[i]; + if(c == '"' || + c == '\\' || + c.charCodeAt(0) < 32 || + c.charCodeAt(0) >= 128) + parts[i] = escapeJSONChar(parts[i]); + } + return "\"" + parts.join("") + "\""; +}; + + +/* Marshall objects to JSON format */ + +toJSON = function toJSON(o) +{ + if(o == null) { + return "null"; + } else if(o.constructor == String) { + return escapeJSONString(o); + } else if(o.constructor == Number) { + return o.toString(); + } else if(o.constructor == Boolean) { + return o.toString(); + } else if(o.constructor == Date) { + return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; + } else if(o.constructor == Array) { + var v = []; + for(var i = 0; i < o.length; i++) v.push(toJSON(o[i])); + return "[" + v.join(", ") + "]"; + } else { + var v = []; + for(attr in o) { + if(o[attr] == null) v.push("\"" + attr + "\": null"); + else if(typeof o[attr] == "function"); /* skip */ + else v.push(escapeJSONString(attr) + ": " + toJSON(o[attr])); + } + return "{" + v.join(", ") + "}"; + } +}; + + +/* JSONRpcClient constructor */ + +JSONRpcClient = +function JSONRpcClient_ctor(serverURL, user, pass, objectID) +{ + this.serverURL = serverURL; + this.user = user; + this.pass = pass; + this.objectID = objectID; + + /* Add standard methods */ + if(this.objectID) { + this._addMethods(["listMethods"]); + var req = this._makeRequest("listMethods", []); + } else { + this._addMethods(["system.listMethods"]); + var req = this._makeRequest("system.listMethods", []); + } + var m = this._sendRequest(req); + this._addMethods(m); +}; + + +/* JSONRpcCLient.Exception */ + +JSONRpcClient.Exception = +function JSONRpcClient_Exception_ctor(code, message, javaStack) +{ + this.code = code; + var name; + if(javaStack) { + this.javaStack = javaStack; + var m = javaStack.match(/^([^:]*)/); + if(m) name = m[0]; + } + if(name) this.name = name; + else this.name = "JSONRpcClientException"; + this.message = message; +}; + +JSONRpcClient.Exception.CODE_REMOTE_EXCEPTION = 490; +JSONRpcClient.Exception.CODE_ERR_CLIENT = 550; +JSONRpcClient.Exception.CODE_ERR_PARSE = 590; +JSONRpcClient.Exception.CODE_ERR_NOMETHOD = 591; +JSONRpcClient.Exception.CODE_ERR_UNMARSHALL = 592; +JSONRpcClient.Exception.CODE_ERR_MARSHALL = 593; + +JSONRpcClient.Exception.prototype = new Error(); + +JSONRpcClient.Exception.prototype.toString = +function JSONRpcClient_Exception_toString(code, msg) +{ + return this.name + ": " + this.message; +}; + + +/* Default top level exception handler */ + +JSONRpcClient.default_ex_handler = +function JSONRpcClient_default_ex_handler(e) { alert(e); }; + + +/* Client settable variables */ + +JSONRpcClient.toplevel_ex_handler = JSONRpcClient.default_ex_handler; +JSONRpcClient.profile_async = false; +JSONRpcClient.max_req_active = 1; +JSONRpcClient.requestId = 1; + + +/* JSONRpcClient implementation */ + +JSONRpcClient.prototype._createMethod = +function JSONRpcClient_createMethod(methodName) +{ + var fn=function() + { + var args = []; + var callback = null; + for(var i=0;i<arguments.length;i++) args.push(arguments[i]); + +/* TUSCANY change callback to be last arg instead of first to match binding.ajax + if(typeof args[0] == "function") callback = args.shift(); +*/ + if(typeof args[arguments.length-1] == "function") callback = args.pop(); + + var req = fn.client._makeRequest.call(fn.client, fn.methodName, + args, callback); + if(callback == null) { + return fn.client._sendRequest.call(fn.client, req); + } else { + JSONRpcClient.async_requests.push(req); + JSONRpcClient.kick_async(); + return req.requestId; + } + }; + fn.client = this; + fn.methodName = methodName; + return fn; +}; + +JSONRpcClient.prototype._addMethods = +function JSONRpcClient_addMethods(methodNames) +{ + for(var i=0; i<methodNames.length; i++) { + var obj = this; + var names = methodNames[i].split("."); + for(var n=0; n<names.length-1; n++) { + var name = names[n]; + if(obj[name]) { + obj = obj[name]; + } else { + obj[name] = new Object(); + obj = obj[name]; + } + } + var name = names[names.length-1]; + if(!obj[name]) { + var method = this._createMethod(methodNames[i]); + obj[name] = method; + } + } +}; + +JSONRpcClient._getCharsetFromHeaders = +function JSONRpcClient_getCharsetFromHeaders(http) +{ + try { + var contentType = http.getResponseHeader("Content-type"); + var parts = contentType.split(/\s*;\s*/); + for(var i =0; i < parts.length; i++) { + if(parts[i].substring(0, 8) == "charset=") + return parts[i].substring(8, parts[i].length); + } + } catch (e) {} + return "UTF-8"; /* default */ +}; + +/* Async queue globals */ +JSONRpcClient.async_requests = []; +JSONRpcClient.async_inflight = {}; +JSONRpcClient.async_responses = []; +JSONRpcClient.async_timeout = null; +JSONRpcClient.num_req_active = 0; + +JSONRpcClient._async_handler = +function JSONRpcClient_async_handler() +{ + JSONRpcClient.async_timeout = null; + + while(JSONRpcClient.async_responses.length > 0) { + var res = JSONRpcClient.async_responses.shift(); + if(res.canceled) continue; + if(res.profile) res.profile.dispatch = new Date(); + try { + res.cb(res.result, res.ex, res.profile); + } catch(e) { + JSONRpcClient.toplevel_ex_handler(e); + } + } + + while(JSONRpcClient.async_requests.length > 0 && + JSONRpcClient.num_req_active < JSONRpcClient.max_req_active) { + var req = JSONRpcClient.async_requests.shift(); + if(req.canceled) continue; + req.client._sendRequest.call(req.client, req); + } +}; + +JSONRpcClient.kick_async = +function JSONRpcClient_kick_async() +{ + if(JSONRpcClient.async_timeout == null) + JSONRpcClient.async_timeout = + setTimeout(JSONRpcClient._async_handler, 0); +}; + +JSONRpcClient.cancelRequest = +function JSONRpcClient_cancelRequest(requestId) +{ + /* If it is in flight then mark it as canceled in the inflight map + and the XMLHttpRequest callback will discard the reply. */ + if(JSONRpcClient.async_inflight[requestId]) { + JSONRpcClient.async_inflight[requestId].canceled = true; + return true; + } + + /* If its not in flight yet then we can just mark it as canceled in + the the request queue and it will get discarded before being sent. */ + for(var i in JSONRpcClient.async_requests) { + if(JSONRpcClient.async_requests[i].requestId == requestId) { + JSONRpcClient.async_requests[i].canceled = true; + return true; + } + } + + /* It may have returned from the network and be waiting for its callback + to be dispatched, so mark it as canceled in the response queue + and the response will get discarded before calling the callback. */ + for(var i in JSONRpcClient.async_responses) { + if(JSONRpcClient.async_responses[i].requestId == requestId) { + JSONRpcClient.async_responses[i].canceled = true; + return true; + } + } + + return false; +}; + +JSONRpcClient.prototype._makeRequest = +function JSONRpcClient_makeRequest(methodName, args, cb) +{ + var req = {}; + req.client = this; + req.requestId = JSONRpcClient.requestId++; + + var obj = {}; + obj.id = req.requestId; + if (this.objectID) + obj.method = ".obj#" + this.objectID + "." + methodName; + else + obj.method = methodName; + obj.params = args; + + if (cb) req.cb = cb; + if (JSONRpcClient.profile_async) + req.profile = { "submit": new Date() }; + req.data = toJSON(obj); + + return req; +}; + +JSONRpcClient.prototype._sendRequest = +function JSONRpcClient_sendRequest(req) +{ + if(req.profile) req.profile.start = new Date(); + + /* Get free http object from the pool */ + var http = JSONRpcClient.poolGetHTTPRequest(); + JSONRpcClient.num_req_active++; + + /* Send the request */ + if (typeof(this.user) == "undefined") { + http.open("POST", this.serverURL, (req.cb != null)); + } else { + http.open("POST", this.serverURL, (req.cb != null), this.user, this.pass); + } + + /* setRequestHeader is missing in Opera 8 Beta */ + try { http.setRequestHeader("Content-type", "text/plain"); } catch(e) {} + + /* Construct call back if we have one */ + if(req.cb) { + var self = this; + http.onreadystatechange = function() { + if(http.readyState == 4) { + http.onreadystatechange = function () {}; + var res = { "cb": req.cb, "result": null, "ex": null}; + if (req.profile) { + res.profile = req.profile; + res.profile.end = new Date(); + } + try { res.result = self._handleResponse(http); } + catch(e) { res.ex = e; } + if(!JSONRpcClient.async_inflight[req.requestId].canceled) + JSONRpcClient.async_responses.push(res); + delete JSONRpcClient.async_inflight[req.requestId]; + JSONRpcClient.kick_async(); + } + }; + } else { + http.onreadystatechange = function() {}; + } + + JSONRpcClient.async_inflight[req.requestId] = req; + + try { + http.send(req.data); + } catch(e) { + JSONRpcClient.poolReturnHTTPRequest(http); + JSONRpcClient.num_req_active--; + throw new JSONRpcClient.Exception + (JSONRpcClient.Exception.CODE_ERR_CLIENT, "Connection failed"); + } + + if(!req.cb) return this._handleResponse(http); +}; + +JSONRpcClient.prototype._handleResponse = +function JSONRpcClient_handleResponse(http) +{ + /* Get the charset */ + if(!this.charset) { + this.charset = JSONRpcClient._getCharsetFromHeaders(http); + } + + /* Get request results */ + var status, statusText, data; + try { + status = http.status; + statusText = http.statusText; + data = http.responseText; + } catch(e) { + JSONRpcClient.poolReturnHTTPRequest(http); + JSONRpcClient.num_req_active--; + JSONRpcClient.kick_async(); + throw new JSONRpcClient.Exception + (JSONRpcClient.Exception.CODE_ERR_CLIENT, "Connection failed"); + } + + /* Return http object to the pool; */ + JSONRpcClient.poolReturnHTTPRequest(http); + JSONRpcClient.num_req_active--; + + /* Unmarshall the response */ + if(status != 200) { + throw new JSONRpcClient.Exception(status, statusText); + } + var obj; + try { + eval("obj = " + data); + } catch(e) { + throw new JSONRpcClient.Exception(550, "error parsing result"); + } + if(obj.error) + throw new JSONRpcClient.Exception(obj.error.code, obj.error.msg, + obj.error.trace); + var res = obj.result; + + /* Handle CallableProxy */ + if(res && res.objectID && res.JSONRPCType == "CallableReference") + return new JSONRpcClient(this.serverURL, this.user, + this.pass, res.objectID); + + return res; +}; + + +/* XMLHttpRequest wrapper code */ + +/* XMLHttpRequest pool globals */ +JSONRpcClient.http_spare = []; +JSONRpcClient.http_max_spare = 8; + +JSONRpcClient.poolGetHTTPRequest = +function JSONRpcClient_pool_getHTTPRequest() +{ + if(JSONRpcClient.http_spare.length > 0) { + return JSONRpcClient.http_spare.pop(); + } + return JSONRpcClient.getHTTPRequest(); +}; + +JSONRpcClient.poolReturnHTTPRequest = +function JSONRpcClient_poolReturnHTTPRequest(http) +{ + if(JSONRpcClient.http_spare.length >= JSONRpcClient.http_max_spare) + delete http; + else + JSONRpcClient.http_spare.push(http); +}; + +JSONRpcClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0", + "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP", + "Microsoft.XMLHTTP" ]; + +JSONRpcClient.getHTTPRequest = +function JSONRpcClient_getHTTPRequest() +{ + /* Mozilla XMLHttpRequest */ + try { + JSONRpcClient.httpObjectName = "XMLHttpRequest"; + return new XMLHttpRequest(); + } catch(e) {} + + /* Microsoft MSXML ActiveX */ + for (var i=0;i < JSONRpcClient.msxmlNames.length; i++) { + try { + JSONRpcClient.httpObjectName = JSONRpcClient.msxmlNames[i]; + return new ActiveXObject(JSONRpcClient.msxmlNames[i]); + } catch (e) {} + } + + /* None found */ + JSONRpcClient.httpObjectName = null; + throw new JSONRpcClient.Exception(0, "Can't create XMLHttpRequest object"); +}; + diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/bean/TestBean.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/bean/TestBean.java new file mode 100644 index 0000000000..508fc31c08 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/bean/TestBean.java @@ -0,0 +1,104 @@ +/* + * 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 bean; + +import java.util.ArrayList; +import java.util.List; + +public class TestBean { + private String testString; + // private String[] testStringArray; // Jackson cannot deserilize String[] + private List<String> testStringArray = new ArrayList<String>(); + private int testInt; + + public String getTestString() { + return testString; + } + + public void setTestString(String testString) { + this.testString = testString; + } + + public List<String> getTestStringArray() { + return testStringArray; + } + + public void setStringArray(List<String> stringArray) { + this.testStringArray = stringArray; + } + + public int getTestInt() { + return testInt; + } + + public void setTestInt(int testInt) { + this.testInt = testInt; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + testInt; + result = prime * result + ((testString == null) ? 0 : testString.hashCode()); + result = prime * result + ((testStringArray == null) ? 0 : testStringArray.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + TestBean other = (TestBean)obj; + if (testInt != other.testInt) { + return false; + } + if (testString == null) { + if (other.testString != null) { + return false; + } + } else if (!testString.equals(other.testString)) { + return false; + } + if (testStringArray == null) { + if (other.testStringArray != null) { + return false; + } + } else if (!testStringArray.equals(other.testStringArray)) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TestBean [testString=").append(testString).append(", testStringArray=").append(testStringArray) + .append(", testInt=").append(testInt).append("]"); + return builder.toString(); + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/Echo.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/Echo.java new file mode 100644 index 0000000000..bb47b9e795 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/Echo.java @@ -0,0 +1,70 @@ +/* + * 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 echo; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.oasisopen.sca.annotation.Remotable; + +import bean.TestBean; + +/** + * Interface of our sample JSONRPC service. + * + * @version $Rev$ $Date$ + */ +@Remotable +public interface Echo { + + String echo(String msg); + + void echoVoid(); + + void echoRuntimeException() throws RuntimeException; + + void echoBusinessException() throws EchoBusinessException; + + int echoInt(int param); + + double echoDouble(double param); + + boolean echoBoolean(boolean param); + + Map echoMap(HashMap map); + + TestBean echoBean(TestBean testBean); + + List echoList(ArrayList list); + + String [] echoArrayString(String[] stringArray); + + int [] echoArrayInt(int[] intArray); + + Set echoSet(HashSet set); + + void get\u03a9\u03bb\u03c0(); + + BigDecimal echoBigDecimal(BigDecimal param); +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoBusinessException.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoBusinessException.java new file mode 100644 index 0000000000..bd9d905475 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoBusinessException.java @@ -0,0 +1,29 @@ +/* + * 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 echo; + +public class EchoBusinessException extends Exception { + private static final long serialVersionUID = 7234119326657905710L; + + public EchoBusinessException(String message) + { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoClientImpl.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoClientImpl.java new file mode 100644 index 0000000000..09a4ab183a --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoClientImpl.java @@ -0,0 +1,102 @@ +/* + * 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 echo; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.oasisopen.sca.annotation.AllowsPassByReference; +import org.oasisopen.sca.annotation.Reference; + +import bean.TestBean; + +@AllowsPassByReference +public class EchoClientImpl implements Echo { + @Reference + @AllowsPassByReference + protected Echo echoReference; + + public String echo(String msg) { + return echoReference.echo(msg); + } + + public void echoVoid() { + echoReference.echoVoid(); + } + + public void echoRuntimeException() throws RuntimeException { + echoReference.echoRuntimeException(); + } + + public void echoBusinessException() throws EchoBusinessException { + echoReference.echoBusinessException(); + } + + public int echoInt(int param) { + return echoReference.echoInt(param); + } + + public double echoDouble(double param) { + return echoReference.echoDouble(param); + } + + public boolean echoBoolean(boolean param) { + return echoReference.echoBoolean(param); + } + + public Map echoMap(HashMap map) { + return echoReference.echoMap(map); + } + + public TestBean echoBean(TestBean testBean) { + return echoReference.echoBean(testBean); + } + + public List echoList(ArrayList list) { + return echoReference.echoList(list); + } + + public String[] echoArrayString(String[] stringArray) { + return echoReference.echoArrayString(stringArray); + } + + public int[] echoArrayInt(int[] intArray) { + return echoReference.echoArrayInt(intArray); + } + + public Set echoSet(HashSet set) { + return echoReference.echoSet(set); + } + + public void get\u03a9\u03bb\u03c0() { + echoReference.get\u03a9\u03bb\u03c0(); + } + + public BigDecimal echoBigDecimal(BigDecimal param) { + return echoReference.echoBigDecimal(param); + } + + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoComponentImpl.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoComponentImpl.java new file mode 100644 index 0000000000..bdfa88c65f --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/echo/EchoComponentImpl.java @@ -0,0 +1,121 @@ +/* + * 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 echo; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.oasisopen.sca.annotation.AllowsPassByReference; + +import bean.TestBean; + +/** + * A simple client component that uses a reference with an JSONRPC binding. + * + * @version $Rev$ $Date$ + */ +@AllowsPassByReference +public class EchoComponentImpl implements Echo { + + public String echo(String msg) { + System.out.println("Echo: "+ msg); + return "echo: " + msg; + } + + + public void echoVoid() { + System.out.println("Echo: VOID"); + } + + public void echoBusinessException() throws EchoBusinessException { + throw new EchoBusinessException("Business Exception"); + + } + + public void echoRuntimeException() throws RuntimeException { + throw new RuntimeException("Runtime Exception"); + } + + public int echoInt(int param) { + int value = param; + return value; + } + + public double echoDouble(double param) { + double value = param; + return param; + } + + public boolean echoBoolean(boolean param) { + boolean value = param; + return value; + } + + public Map echoMap(HashMap param) { + Map map = new HashMap(); + map = param; + return map; + } + + public TestBean echoBean(TestBean testBean1) { + TestBean testBean = new TestBean(); + testBean.setTestString(testBean1.getTestString()); + testBean.setTestInt(testBean1.getTestInt()); + testBean.setStringArray(testBean1.getTestStringArray()); + return testBean; + } + + public List echoList(ArrayList param){ + List list = new ArrayList(); + for(Iterator itr = param.iterator();itr.hasNext();) + { + list.add(itr.next()); + } + return list; + } + + public String[] echoArrayString(String[] stringArray) { + return stringArray; + } + + public int[] echoArrayInt(int[] intArray) { + return intArray; + } + + public Set echoSet(HashSet param){ + Set set = new HashSet(); + set = param; + return set; + + } + + public void get\u03a9\u03bb\u03c0() { + + } + + public BigDecimal echoBigDecimal(BigDecimal param) { + return param; + } +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCDataTypeTestCase.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCDataTypeTestCase.java new file mode 100644 index 0000000000..107866137d --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCDataTypeTestCase.java @@ -0,0 +1,219 @@ +/* + * 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.jsonrpc; + +import java.io.ByteArrayInputStream; + +import junit.framework.Assert; + +import org.apache.tuscany.sca.node.Contribution; +import org.apache.tuscany.sca.node.ContributionLocationHelper; +import org.apache.tuscany.sca.node.Node; +import org.apache.tuscany.sca.node.NodeFactory; +import org.json.JSONObject; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.meterware.httpunit.PostMethodWebRequest; +import com.meterware.httpunit.WebConversation; +import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebResponse; + +/** + * @version $Rev$ $Date$ + */ +public class JSONRPCDataTypeTestCase { + + private static final String SERVICE_PATH = "/EchoService"; + private static final String SERVICE_URL = "http://localhost:8085/SCADomain" + SERVICE_PATH; + + private static Node node; + + @BeforeClass + public static void setUp() throws Exception { + try { + String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCDataTypeTestCase.class); + node = NodeFactory.newInstance().createNode("JSONRPCBinding.composite", new Contribution("test", contribution)); + node.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void tearDown() throws Exception { + node.stop(); + } + + @Test + public void testInt() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{ \"method\": \"echoInt\", \"params\": [12345], \"id\": 4}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals(12345, jsonResp.getInt("result")); + } + + @Test + public void testBoolean() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{ \"method\": \"echoBoolean\", \"params\": [true], \"id\": 5}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals(true, jsonResp.getBoolean("result")); + } + + @Test + public void testMap() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{ \"method\": \"echoMap\", \"params\": [ {\"javaClass\": \"java.util.HashMap\", \"map\": { \"Binding\": \"JSON-RPC\"}}], \"id\": 6}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals("JSON-RPC", jsonResp.getJSONObject("result").getJSONObject("map").getString("Binding")); + } + + @Test + public void testBean() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{ \"method\": \"echoBean\", \"params\": [ {\"javaClass\": \"bean.TestBean\", \"testString\": \"JSON-RPC\", \"testInt\":1234}], \"id\": 7}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals("JSON-RPC", jsonResp.getJSONObject("result").getString("testString")); + } + + @Test + public void testList() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{ \"method\": \"echoList\", \"params\": [[0,1,2,3,4]], \"id\": 8}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals(0, jsonResp.getJSONArray("result").get(0)); + } + + @Test + public void testArrayString() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{\"params\":[[\"1\",\"2\"]],\"method\":\"echoArrayString\",\"id\":9}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals(1, jsonResp.getJSONArray("result").getInt(0)); + } + + + @Test + public void testArrayInt() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{\"params\":[[1,2]],\"method\":\"echoArrayInt\",\"id\":10}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals(1, jsonResp.getJSONArray("result").getInt(0)); + } + + + @Test + public void testSet() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{ \"method\": \"echoSet\", \"params\": [[\"red\", \"blue\"]],\"id\": 11}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals("red", jsonResp.getJSONArray("result").get(0)); + } + + @Test + public void testBigDecimal() throws Exception { + JSONObject jsonRequest = new JSONObject( + "{ \"method\": \"echoBigDecimal\", \"params\": [\"12345.67\"], \"id\": 4}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest(SERVICE_URL, + new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")), "application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + + Assert.assertEquals(12345.67, jsonResp.get("result")); + } +}
\ No newline at end of file diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCExceptionTestCase.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCExceptionTestCase.java new file mode 100644 index 0000000000..037c6f3ad0 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCExceptionTestCase.java @@ -0,0 +1,95 @@ +/* + * 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.jsonrpc; + +import java.io.ByteArrayInputStream; + +import junit.framework.Assert; + +import org.apache.tuscany.sca.node.Contribution; +import org.apache.tuscany.sca.node.ContributionLocationHelper; +import org.apache.tuscany.sca.node.Node; +import org.apache.tuscany.sca.node.NodeFactory; +import org.json.JSONObject; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.meterware.httpunit.PostMethodWebRequest; +import com.meterware.httpunit.WebConversation; +import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebResponse; + +/** + * @version $Rev$ $Date$ + */ +public class JSONRPCExceptionTestCase{ + + private static final String SERVICE_PATH = "/EchoService"; + + private static final String SERVICE_URL = "http://localhost:8085/SCADomain" + SERVICE_PATH; + + private static Node node; + + @BeforeClass + public static void setUp() throws Exception { + try { + String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCExceptionTestCase.class); + node = NodeFactory.newInstance().createNode("JSONRPCBinding.composite", new Contribution("test", contribution)); + node.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void tearDown() throws Exception { + node.stop(); + } + + @Test + public void testRuntimeException() throws Exception{ + JSONObject jsonRequest = new JSONObject("{ \"method\": \"echoRuntimeException\", \"params\": [], \"id\": 2}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest( SERVICE_URL, new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")),"application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonErr = new JSONObject(response.getText()).getJSONObject("error"); + + Assert.assertEquals("Runtime Exception", jsonErr.getString("message")); + } + + @Test + public void testBusinessException() throws Exception{ + JSONObject jsonRequest = new JSONObject("{ \"method\": \"echoBusinessException\", \"params\": [], \"id\": 3}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest( SERVICE_URL, new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")),"application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonErr = new JSONObject(response.getText()).getJSONObject("error"); + + Assert.assertEquals("Business Exception", jsonErr.getString("message")); + } +}
\ No newline at end of file diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCReferenceTargetTestCase.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCReferenceTargetTestCase.java new file mode 100644 index 0000000000..383a862945 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCReferenceTargetTestCase.java @@ -0,0 +1,117 @@ +/* + * 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.jsonrpc; + +import java.util.Arrays; + +import junit.framework.Assert; + +import org.apache.tuscany.sca.node.Contribution; +import org.apache.tuscany.sca.node.ContributionLocationHelper; +import org.apache.tuscany.sca.node.Node; +import org.apache.tuscany.sca.node.NodeFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import bean.TestBean; +import echo.Echo; + +public class JSONRPCReferenceTargetTestCase { + private static final String ECHO_COMPONENT_WITH_REFERENCE = "EchoComponentWithReferenceTarget"; + private static Node node; + + @BeforeClass + public static void setUp() throws Exception { + try { + String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCReferenceTargetTestCase.class); + node = + NodeFactory.newInstance().createNode(new Contribution("testClient", contribution)); + node.start(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void tearDown() throws Exception { + node.stop(); + } + + @Test + public void testInvokeReference() throws Exception { + Echo echoComponent = node.getService(Echo.class, ECHO_COMPONENT_WITH_REFERENCE); + String result = echoComponent.echo("ABC"); + Assert.assertEquals("echo: ABC", result); + } + + @Test + public void testInvokeBeanReference() throws Exception { + Echo echoComponent = node.getService(Echo.class, ECHO_COMPONENT_WITH_REFERENCE); + TestBean bean = new TestBean(); + bean.setTestInt(1); + bean.setTestString("123"); + bean.setStringArray(Arrays.asList("A", "B")); + TestBean result = echoComponent.echoBean(bean); + Assert.assertEquals(bean, result); + } + + @Test + public void testInvokeReferenceVoidOperation() throws Exception { + Echo echoComponent = node.getService(Echo.class, ECHO_COMPONENT_WITH_REFERENCE); + echoComponent.echoVoid(); + } + + @Test(expected = Exception.class) + public void testInvokeReferenceException() throws Exception { + Echo echoComponent = node.getService(Echo.class, ECHO_COMPONENT_WITH_REFERENCE); + try { + echoComponent.echoBusinessException(); + } catch (Exception e) { + System.err.println(e); + throw e; + } + } + + @Test + public void testInvokeReference20() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference20"); + String result = echoComponent.echo("ABC"); + Assert.assertEquals("echo: ABC", result); + } + + @Test + public void testInvokeReferenceVoidOperation20() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference20"); + echoComponent.echoVoid(); + } + + @Test(expected = Exception.class) + public void testInvokeReferenceException20() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference20"); + try { + echoComponent.echoBusinessException(); + } catch (Exception e) { + System.err.println(e); + throw e; + } + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCReferenceTestCase.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCReferenceTestCase.java new file mode 100644 index 0000000000..3950d3c134 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCReferenceTestCase.java @@ -0,0 +1,123 @@ +/* + * 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.jsonrpc; + +import java.util.Arrays; + +import junit.framework.Assert; + +import org.apache.tuscany.sca.node.Contribution; +import org.apache.tuscany.sca.node.ContributionLocationHelper; +import org.apache.tuscany.sca.node.Node; +import org.apache.tuscany.sca.node.NodeFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import bean.TestBean; +import echo.Echo; + +public class JSONRPCReferenceTestCase { + private static Node nodeServer; + private static Node node; + + @BeforeClass + public static void setUp() throws Exception { + try { + String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCReferenceTestCase.class); + nodeServer = + NodeFactory.newInstance().createNode("JSONRPCBinding.composite", new Contribution("testServer", contribution)); + nodeServer.start(); + + contribution = ContributionLocationHelper.getContributionLocation(JSONRPCReferenceTestCase.class); + node = + NodeFactory.newInstance().createNode("JSONRPCReference.composite", new Contribution("testClient", contribution)); + node.start(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void tearDown() throws Exception { + nodeServer.stop(); + node.stop(); + } + + @Test + public void testInvokeReference() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference"); + String result = echoComponent.echo("ABC"); + Assert.assertEquals("echo: ABC", result); + } + + @Test + public void testInvokeBeanReference() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference"); + TestBean bean = new TestBean(); + bean.setTestInt(1); + bean.setTestString("123"); + bean.setStringArray(Arrays.asList("A", "B")); + TestBean result = echoComponent.echoBean(bean); + Assert.assertEquals(bean, result); + } + + @Test + public void testInvokeReferenceVoidOperation() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference"); + echoComponent.echoVoid(); + } + + @Test(expected = Exception.class) + public void testInvokeReferenceException() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference"); + try { + echoComponent.echoBusinessException(); + } catch (Exception e) { + System.err.println(e); + throw e; + } + } + + @Test + public void testInvokeReference20() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference20"); + String result = echoComponent.echo("ABC"); + Assert.assertEquals("echo: ABC", result); + } + + @Test + public void testInvokeReferenceVoidOperation20() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference20"); + echoComponent.echoVoid(); + } + + @Test(expected = Exception.class) + public void testInvokeReferenceException20() throws Exception { + Echo echoComponent = node.getService(Echo.class, "EchoComponentWithReference20"); + try { + echoComponent.echoBusinessException(); + } catch (Exception e) { + System.err.println(e); + throw e; + } + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCServiceTestCase.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCServiceTestCase.java new file mode 100644 index 0000000000..bbf8d4cee7 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCServiceTestCase.java @@ -0,0 +1,147 @@ +/* + * 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.jsonrpc; + +import java.io.ByteArrayInputStream; +import java.net.URLEncoder; + +import junit.framework.Assert; + +import org.apache.axiom.om.util.Base64; +import org.apache.tuscany.sca.node.Contribution; +import org.apache.tuscany.sca.node.ContributionLocationHelper; +import org.apache.tuscany.sca.node.Node; +import org.apache.tuscany.sca.node.NodeFactory; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.meterware.httpunit.GetMethodWebRequest; +import com.meterware.httpunit.PostMethodWebRequest; +import com.meterware.httpunit.WebConversation; +import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebResponse; + +/** + * @version $Rev$ $Date$ + */ +public class JSONRPCServiceTestCase { + + private static String SERVICE_URL; + private static String SERVICE20_URL; + + private static Node node; + + @BeforeClass + public static void setUp() throws Exception { + try { + String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCServiceTestCase.class); + node = NodeFactory.newInstance().createNode("JSONRPCBinding.composite", new Contribution("test", contribution)); + node.start(); + SERVICE_URL = node.getEndpointAddress("EchoComponent/Echo/Echo"); + SERVICE20_URL = node.getEndpointAddress("EchoComponent/Echo/jsonrpc20"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void tearDown() throws Exception { + node.stop(); + } + + @Test + public void testEchoWithJSONRPCBinding() throws Exception { + JSONObject jsonRequest = new JSONObject("{ \"method\": \"echo\", \"params\": [\"Hello JSON-RPC\"], \"id\": 1}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest( SERVICE_URL, new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")),"application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + Assert.assertEquals("echo: Hello JSON-RPC", jsonResp.getString("result")); + } + + @Test + public void testEchoWithJSONRPC20Binding() throws Exception { + JSONObject jsonRequest = new JSONObject("{ \"jsonrpc\": \"2.0\", \"method\": \"echo\", \"params\": [\"Hello JSON-RPC\"], \"id\": 1}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest( SERVICE20_URL, new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")),"application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + Assert.assertEquals("echo: Hello JSON-RPC", jsonResp.getString("result")); + } + + + @Test + public void testEchoWithJSONRPC20BindingBatch() throws Exception { + JSONObject jsonRequest1 = new JSONObject("{ \"jsonrpc\": \"2.0\", \"method\": \"echo\", \"params\": [\"Hello JSON-RPC\"], \"id\": 1}"); + JSONObject jsonRequest2 = new JSONObject("{ \"jsonrpc\": \"2.0\", \"method\": \"echo\", \"params\": [\"Hello JSON-RPC 2.0\"], \"id\": 2}"); + JSONArray batchReq = new JSONArray(); + batchReq.put(jsonRequest1); + batchReq.put(jsonRequest2); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest( SERVICE20_URL, new ByteArrayInputStream(batchReq.toString().getBytes("UTF-8")),"application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONArray jsonResp = new JSONArray(response.getText()); + Assert.assertEquals("echo: Hello JSON-RPC", ((JSONObject) jsonResp.get(0)).getString("result")); + Assert.assertEquals("echo: Hello JSON-RPC 2.0", ((JSONObject) jsonResp.get(1)).getString("result")); + } + + @Test + public void testJSONRPCBindingGET() throws Exception { + String params = Base64.encode("[\"Hello JSON-RPC\"]".getBytes()); + String queryString = "?method=echo¶ms=" + URLEncoder.encode(params,"UTF-8") + "&id=1"; + + WebConversation wc = new WebConversation(); + WebRequest request = new GetMethodWebRequest(SERVICE_URL + queryString); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + Assert.assertEquals("echo: Hello JSON-RPC", jsonResp.getString("result")); + } + + @Test + public void testEchoVoidWithJSONRPCBinding() throws Exception { + JSONObject jsonRequest = new JSONObject("{ \"method\": \"echoVoid\", \"params\": [], \"id\": 1}"); + + WebConversation wc = new WebConversation(); + WebRequest request = new PostMethodWebRequest( SERVICE_URL, new ByteArrayInputStream(jsonRequest.toString().getBytes("UTF-8")),"application/json"); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + + JSONObject jsonResp = new JSONObject(response.getText()); + Assert.assertTrue(jsonResp.isNull("result")); + } +}
\ No newline at end of file diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCSmdTestCase.java b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCSmdTestCase.java new file mode 100644 index 0000000000..0ee1643243 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/java/org/apache/tuscany/sca/binding/jsonrpc/JSONRPCSmdTestCase.java @@ -0,0 +1,86 @@ +/* + * 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.jsonrpc; + +import junit.framework.Assert; + +import org.apache.tuscany.sca.node.Contribution; +import org.apache.tuscany.sca.node.ContributionLocationHelper; +import org.apache.tuscany.sca.node.Node; +import org.apache.tuscany.sca.node.NodeFactory; +import org.json.JSONObject; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.meterware.httpunit.GetMethodWebRequest; +import com.meterware.httpunit.WebConversation; +import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebResponse; + +import echo.Echo; + +/** + * @version $Rev$ $Date$ + */ +public class JSONRPCSmdTestCase { + + private static final String SERVICE_PATH = "/EchoService"; + + private static final String SERVICE_URL = "http://localhost:8085/SCADomain" + SERVICE_PATH; + + private static final String SMD_URL = SERVICE_URL + "?smd"; + + private static Node node; + + @BeforeClass + public static void setUp() throws Exception { + try { + String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCSmdTestCase.class); + node = + NodeFactory.newInstance() + .createNode("JSONRPCBinding.composite", new Contribution("test", contribution)); + node.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void tearDown() throws Exception { + node.stop(); + } + + @Test + /** + * This test make sure the JSON-RPC Binding can handle special characters when generating SMD + */ + public void testJSONRPCSmdSpecialCharacters() throws Exception { + WebConversation wc = new WebConversation(); + WebRequest request = new GetMethodWebRequest(SMD_URL); + WebResponse response = wc.getResource(request); + + Assert.assertEquals(200, response.getResponseCode()); + JSONObject smd = new JSONObject(response.getText()); + Assert.assertEquals(Echo.class.getMethods().length, smd.getJSONArray("methods").length()); + + // System.out.println(">>>SMD:\n" + response.getText()); + } +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/resources/JSONRPCBinding.composite b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/resources/JSONRPCBinding.composite new file mode 100644 index 0000000000..44de429713 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/resources/JSONRPCBinding.composite @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://jsonrpc"
+ xmlns:jsonrpc="http://jsonrpc"
+ name="JSONRPCBinding">
+
+ <!--service name="EchoService" promote="EchoComponent">
+ <interface.java interface="echo.Echo"/>
+ <tuscany:binding.jsonrpc uri="http://localhost:8085/SCADomain/EchoService"/>
+ </service -->
+
+ <component name="EchoComponent">
+ <implementation.java class="echo.EchoComponentImpl"/>
+ <service name="Echo">
+ <tuscany:binding.jsonrpc uri="http://localhost:8085/SCADomain/EchoService"/>
+ <tuscany:binding.jsonrpc version="2.0" name="jsonrpc20" uri="http://localhost:8085/SCADomain/EchoService20"/>
+ </service>
+ </component>
+
+ <component name="EchoComponent1">
+ <implementation.java class="echo.EchoComponentImpl"/>
+ <service name="Echo">
+ <tuscany:binding.jsonrpc name="jsonrpc" uri="/services/EchoService"/>
+ <tuscany:binding.jsonrpc version="2.0" name="jsonrpc20" uri="/services/EchoService20"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/resources/JSONRPCReference.composite b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/resources/JSONRPCReference.composite new file mode 100644 index 0000000000..3679e259a4 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-jsonrpc-runtime/src/test/resources/JSONRPCReference.composite @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1" + targetNamespace="http://jsonrpc" + xmlns:jsonrpc="http://jsonrpc" + name="JSONRPCReference"> + + <component name="EchoComponentWithReference"> + <implementation.java class="echo.EchoClientImpl" /> + <reference name="echoReference"> + <tuscany:binding.jsonrpc uri="http://localhost:8085/SCADomain/EchoService" /> + </reference> + </component> + + <component name="EchoComponentWithReference20"> + <implementation.java class="echo.EchoClientImpl" /> + + <reference name="echoReference"> + <tuscany:binding.jsonrpc version="2.0" uri="http://localhost:8085/SCADomain/EchoService20" /> + </reference> + </component> + + <component name="EchoComponentWithReferenceTarget"> + <implementation.java class="echo.EchoClientImpl" /> + <reference name="echoReference" target="EchoComponent1/Echo/jsonrpc"> + </reference> + </component> + + +</composite> |