Improved the SMD and error handling

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1171688 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
rfeng 2011-09-16 17:34:05 +00:00
commit 5103397852
5 changed files with 163 additions and 87 deletions

View file

@ -130,59 +130,53 @@ public class JSONRPCBindingInvoker implements Invoker, DataExchangeSemantics {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//success
try {
entity = response.getEntity();
String entityResponse = EntityUtils.toString(entity);
entity.consumeContent();
if (!db.equals(JSONDataBinding.NAME)) {
JSONObject jsonResponse = new JSONObject(entityResponse);
if (!jsonResponse.has("result")) {
processException(jsonResponse);
}
DataType<List<DataType>> outputType = operation.getOutputType();
DataType returnType =
(outputType != null && !outputType.getLogical().isEmpty()) ? outputType.getLogical().get(0)
: null;
entity = response.getEntity();
String entityResponse = EntityUtils.toString(entity);
entity.consumeContent();
if (!db.equals(JSONDataBinding.NAME)) {
JSONObject jsonResponse = new JSONObject(entityResponse);
if (returnType == null) {
msg.setBody(null);
return msg;
}
if (!jsonResponse.has("result")) {
processException(jsonResponse);
}
DataType<List<DataType>> outputType = operation.getOutputType();
DataType returnType =
(outputType != null && !outputType.getLogical().isEmpty()) ? outputType.getLogical().get(0)
: null;
//check requestId
if (!requestId.equalsIgnoreCase(jsonResponse.optString("id"))) {
throw new ServiceRuntimeException("Invalid response id:" + requestId);
}
Object rawResult = jsonResponse.get("result");
if (rawResult == null) {
processException(jsonResponse);
}
Class<?> returnClass = returnType.getPhysical();
Type genericReturnType = returnType.getGenericType();
ObjectMapper mapper = createObjectMapper(returnClass);
String json = rawResult.toString();
// Jackson requires the quoted String so that readValue can work
if (returnClass == String.class) {
json = "\"" + json + "\"";
}
Object body = mapper.readValue(json, TypeFactory.type(genericReturnType));
msg.setBody(body);
} else {
msg.setBody(entityResponse);
if (returnType == null) {
msg.setBody(null);
return msg;
}
} catch (Exception e) {
//FIXME Exceptions are not handled correctly here
// They should be reported to the client JavaScript as proper
// JavaScript exceptions.
throw new ServiceRuntimeException("Unable to parse response", e);
//check requestId
if (!requestId.equalsIgnoreCase(jsonResponse.optString("id"))) {
throw new ServiceRuntimeException("Invalid response id:" + requestId);
}
Object rawResult = jsonResponse.get("result");
if (rawResult == null) {
processException(jsonResponse);
}
Class<?> returnClass = returnType.getPhysical();
Type genericReturnType = returnType.getGenericType();
ObjectMapper mapper = createObjectMapper(returnClass);
String json = rawResult.toString();
// Jackson requires the quoted String so that readValue can work
if (returnClass == String.class) {
json = "\"" + json + "\"";
}
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();
@ -241,6 +235,7 @@ public class JSONRPCBindingInvoker implements Invoker, DataExchangeSemantics {
* Generate and throw exception based on the data in the 'responseMessage'
*/
protected void processException(JSONObject responseMessage) throws JSONException {
// FIXME: We need to find a way to build Java exceptions out of the json-rpc error
JSONObject error = (JSONObject)responseMessage.get("error");
if (error != null) {
throw new ServiceRuntimeException(error.toString());

View file

@ -16,9 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tuscany.sca.binding.jsonrpc.provider;
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
@ -29,28 +33,99 @@ import java.lang.reflect.Method;
* @version $Rev$ $Date$
*/
class JavaToSmd {
static String interfaceToSmd(Class<?> klazz, String serviceUrl) {
String name = klazz.getSimpleName();
Method[] methods = klazz.getMethods();
StringBuffer smdSb = new StringBuffer();
smdSb.append("{\"SMDVersion\":\".1\",\"objectName\":\"" + name + "\",\"serviceType\":\"JSON-RPC\",\"serviceURL\":\""+ serviceUrl + "\",\"methods\":[");
for (int i = 0; i < methods.length; i++) {
if (i != 0) smdSb.append(",");
Class<?>[] params = methods[i].getParameterTypes();
smdSb.append("{\"name\":\""+methods[i].getName() + "\",\"parameters\":[");
for (int j = 0; j < params.length; j++) {
if (j != 0) smdSb.append(",");
// right now Dojo doesn't look at the type value, so we'll default it to STRING
// also, since we can't introspect the method parameter names we'll just create an incrementing parameter name
smdSb.append("{\"name\":\"param" + j + "\",\"type\":\"STRING\"}");
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);
}
smdSb.append("]}");
smd.put("methods", services);
return smd.toString(2);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
smdSb.append("]}");
return smdSb.toString();
}
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";
}
}

View file

@ -60,7 +60,7 @@ public class EchoClientImpl implements Echo {
}
public void echoBusinessException() throws EchoBusinessException {
throw new UnsupportedOperationException("UNsupported !");
echoReference.echoBusinessException();
}
public int echoInt(int param) {
@ -80,7 +80,7 @@ public class EchoClientImpl implements Echo {
}
public void echoRuntimeException() throws RuntimeException {
throw new UnsupportedOperationException("UNsupported !");
echoReference.echoRuntimeException();
}
public Set echoSet(HashSet set) {

View file

@ -35,6 +35,7 @@ public class JSONRPCReferenceTestCase {
private static final String SERVICE_URL = "http://localhost:8085/SCADomain" + SERVICE_PATH;
private static Node nodeServer;
private static Node node;
@BeforeClass
public static void setUp() throws Exception {
@ -42,6 +43,11 @@ public class JSONRPCReferenceTestCase {
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();
}
@ -50,37 +56,31 @@ public class JSONRPCReferenceTestCase {
@AfterClass
public static void tearDown() throws Exception {
nodeServer.stop();
node.stop();
}
@Test
public void testInvokeReference() throws Exception {
Node node = null;
String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCReferenceTestCase.class);
node = NodeFactory.newInstance().createNode("JSONRPCReference.composite", new Contribution("testClient", contribution));
node.start();
Echo echoComponent = node.getService(Echo.class,"EchoComponentWithReference");
String result = echoComponent.echo("ABC");
Assert.assertEquals("echo: ABC", result);
if (node != null) {
node.stop();
}
}
@Test
public void testInvokeReferenceVoidOperation() throws Exception {
Node node = null;
String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCReferenceTestCase.class);
node = NodeFactory.newInstance().createNode("JSONRPCReference.composite", new Contribution("testClient", contribution));
node.start();
Echo echoComponent = node.getService(Echo.class,"EchoComponentWithReference");
echoComponent.echoVoid();
if (node != null) {
node.stop();
}
@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;
}
}
}

View file

@ -25,6 +25,7 @@ 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;
@ -34,6 +35,8 @@ import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import echo.Echo;
/**
* @version $Rev$ $Date$
*/
@ -51,7 +54,9 @@ public class JSONRPCSmdTestCase {
public static void setUp() throws Exception {
try {
String contribution = ContributionLocationHelper.getContributionLocation(JSONRPCSmdTestCase.class);
node = NodeFactory.newInstance().createNode("JSONRPCBinding.composite", new Contribution("test", contribution));
node =
NodeFactory.newInstance()
.createNode("JSONRPCBinding.composite", new Contribution("test", contribution));
node.start();
} catch (Exception e) {
e.printStackTrace();
@ -69,12 +74,13 @@ public class JSONRPCSmdTestCase {
*/
public void testJSONRPCSmdSpecialCharacters() throws Exception {
WebConversation wc = new WebConversation();
WebRequest request = new GetMethodWebRequest(SMD_URL);
WebRequest request = new GetMethodWebRequest(SMD_URL);
WebResponse response = wc.getResource(request);
Assert.assertEquals(200, response.getResponseCode());
Assert.assertNotNull(response.getText());
JSONObject smd = new JSONObject(response.getText());
Assert.assertEquals(Echo.class.getMethods().length, smd.getJSONArray("methods").length());
//System.out.println(">>>SMD:" + response.getText());
// System.out.println(">>>SMD:\n" + response.getText());
}
}