Skip to content

Commit

Permalink
Introduce JsonRpcMapper abstract
Browse files Browse the repository at this point in the history
WIP

References #378

(cherry picked from commit 0a3bed1)
  • Loading branch information
acogoluegnes committed Aug 16, 2018
1 parent 82c18e9 commit 119a957
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 57 deletions.
2 changes: 0 additions & 2 deletions src/main/java/com/rabbitmq/tools/json/JSONUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ public static Object fill(Object target, Map<String, Object> source, boolean use
String name = prop.getName();
Method setter = prop.getWriteMethod();
if (setter != null && !Modifier.isStatic(setter.getModifiers())) {
//System.out.println(target + " " + name + " <- " + source.get(name));
setter.invoke(target, source.get(name));
}
}
Expand All @@ -74,7 +73,6 @@ public static Object fill(Object target, Map<String, Object> source, boolean use
if (Modifier.isPublic(fieldMod) && !(Modifier.isFinal(fieldMod) ||
Modifier.isStatic(fieldMod)))
{
//System.out.println(target + " " + field.getName() + " := " + source.get(field.getName()));
try {
field.set(target, source.get(field.getName()));
} catch (IllegalArgumentException iae) {
Expand Down
72 changes: 72 additions & 0 deletions src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.rabbitmq.tools.jsonrpc;

import com.rabbitmq.tools.json.JSONReader;
import com.rabbitmq.tools.json.JSONWriter;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
*
*/
public class DefaultJsonRpcMapper implements JsonRpcMapper {

@Override
public JsonRpcRequest parse(String requestBody, ServiceDescription description) {
Map<String, Object> request = (Map<String,Object>) new JSONReader().read(requestBody);

return new JsonRpcRequest(
request.get("id"), request.get("version").toString(), request.get("method").toString(),
((List<?>) request.get("params")).toArray()
);
}

@Override
public JsonRpcResponse parse(String responseBody) {
Map<String, Object> map = (Map<String, Object>) (new JSONReader().read(responseBody));
Map<String, Object> error;
JsonRpcException exception = null;
if (map.containsKey("error")) {
error = (Map<String, Object>) map.get("error");
exception = new JsonRpcException(
new JSONWriter().write(error),
(String) error.get("name"),
error.get("code") == null ? 0 : (Integer) error.get("code"),
(String) error.get("message"),
error
);
}
return new JsonRpcResponse(map, map.get("result"), map.get("error"), exception);
}

@Override
public Object[] parameters(JsonRpcRequest request, Method method) {
Object[] parameters = request.getParameters();
Object[] convertedParameters = new Object[parameters.length];
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
convertedParameters[i] = convert(parameters[i], parameterTypes[i]);
}
return convertedParameters;
}

@Override
public String write(Object input) {
return new JSONWriter().write(input);
}

protected Object convert(Object input, Class<?> expectedClass) {
return input;
// if (input == null || input.getClass().equals(expectedClass)) {
// return input;
// }
// System.err.println(input.getClass() + " " + expectedClass);
// if (Long.class.equals(expectedClass) && input instanceof Integer) {
// return Long.valueOf(((Integer) input).longValue());
// } else if (long.class.equals(expectedClass) && input instanceof Integer) {
// return
// }
// return input;
}
}
25 changes: 12 additions & 13 deletions src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public class JsonRpcClient extends RpcClient implements InvocationHandler {
/** Holds the JSON-RPC service description for this client. */
private ServiceDescription serviceDescription;

private final JsonRpcMapper mapper;

/**
* Construct a new JsonRpcClient, passing the parameters through
* to RpcClient's constructor. The service description record is
Expand All @@ -72,6 +74,7 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey, int ti
throws IOException, JsonRpcException, TimeoutException
{
super(channel, exchange, routingKey, timeout);
this.mapper = new DefaultJsonRpcMapper();
retrieveServiceDescription();
}

Expand All @@ -86,18 +89,14 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey)
* @return the result contained within the reply, if no exception is found
* Throws JsonRpcException if the reply object contained an exception
*/
public static Object checkReply(Map<String, Object> reply)
private Object checkReply(JsonRpcMapper.JsonRpcResponse reply)
throws JsonRpcException
{
if (reply.containsKey("error")) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) reply.get("error");
// actually a Map<String, Object>
throw new JsonRpcException(map);
}
if (reply.getError() != null) {
throw reply.getException();
}

Object result = reply.get("result");
return result;
return reply.getResult();
}

/**
Expand All @@ -114,16 +113,16 @@ public Object call(String method, Object[] params) throws IOException, JsonRpcEx
request.put("method", method);
request.put("version", ServiceDescription.JSON_RPC_VERSION);
request.put("params", (params == null) ? new Object[0] : params);
String requestStr = new JSONWriter().write(request);
String requestStr = mapper.write(request);
try {
String replyStr = this.stringCall(requestStr);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Reply string: {}", replyStr);
}
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) (new JSONReader().read(replyStr));

return checkReply(map);
JsonRpcMapper.JsonRpcResponse reply = mapper.parse(replyStr);

return checkReply(reply);
} catch(ShutdownSignalException ex) {
throw new IOException(ex.getMessage()); // wrap, re-throw
}
Expand Down
35 changes: 19 additions & 16 deletions src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,43 @@
// If you have any questions regarding licensing, please contact us at
// info@rabbitmq.com.


package com.rabbitmq.tools.jsonrpc;

import java.util.Map;

import com.rabbitmq.tools.json.JSONWriter;

/**
* Thrown when a JSON-RPC service indicates an error occurred during a call.
*/
public class JsonRpcException extends Exception {

/**
* Default serialized version ID
*/
private static final long serialVersionUID = 1L;
/** Usually the constant string, "JSONRPCError" */
/**
* Usually the constant string, "JSONRPCError"
*/
public String name;
/** Error code */
/**
* Error code
*/
public int code;
/** Error message */
/**
* Error message
*/
public String message;
/** Error detail object - may not always be present or meaningful */
/**
* Error detail object - may not always be present or meaningful
*/
public Object error;

public JsonRpcException() {
// no work needed in default no-arg constructor
}

public JsonRpcException(Map<String, Object> errorMap) {
super(new JSONWriter().write(errorMap));
name = (String) errorMap.get("name");
code = 0;
if (errorMap.get("code") != null) { code = ((Integer) errorMap.get("code")); }
message = (String) errorMap.get("message");
error = errorMap.get("error");
public JsonRpcException(String detailMessage, String name, int code, String message, Object error) {
super(detailMessage);
this.name = name;
this.code = code;
this.message = message;
this.error = error;
}
}
89 changes: 89 additions & 0 deletions src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.rabbitmq.tools.jsonrpc;

import java.lang.reflect.Method;

/**
*
*/
public interface JsonRpcMapper {

JsonRpcRequest parse(String requestBody, ServiceDescription description);

JsonRpcResponse parse(String responseBody);

Object[] parameters(JsonRpcRequest request, Method method);

String write(Object input);

class JsonRpcRequest {

private final Object id;
private final String version;
private final String method;
private final Object[] parameters;

public JsonRpcRequest(Object id, String version, String method, Object[] parameters) {
this.id = id;
this.version = version;
this.method = method;
this.parameters = parameters;
}

public Object getId() {
return id;
}

public String getVersion() {
return version;
}

public String getMethod() {
return method;
}

public Object[] getParameters() {
return parameters;
}

public boolean isSystem() {
return method.startsWith("system.");
}

public boolean isSystemDescribe() {
return "system.describe".equals(method);
}

}

class JsonRpcResponse {

private final Object reply;
private final Object result;
private final Object error;
private final JsonRpcException exception;

public JsonRpcResponse(Object reply, Object result, Object error, JsonRpcException exception) {
this.reply = reply;
this.result = result;
this.error = error;
this.exception = exception;
}

public Object getReply() {
return reply;
}

public Object getError() {
return error;
}

public Object getResult() {
return result;
}

public JsonRpcException getException() {
return exception;
}
}

}
30 changes: 16 additions & 14 deletions src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public class JsonRpcServer extends StringRpcServer {
/** The instance backing this server. */
public Object interfaceInstance;

private final JsonRpcMapper mapper;

/**
* Construct a server that talks to the outside world using the
* given channel, and constructs a fresh temporary
Expand All @@ -70,6 +72,7 @@ public JsonRpcServer(Channel channel,
throws IOException
{
super(channel);
this.mapper = new DefaultJsonRpcMapper();
init(interfaceClass, interfaceInstance);
}

Expand Down Expand Up @@ -98,6 +101,7 @@ public JsonRpcServer(Channel channel,
throws IOException
{
super(channel, queueName);
this.mapper = new DefaultJsonRpcMapper();
init(interfaceClass, interfaceInstance);
}

Expand Down Expand Up @@ -126,25 +130,24 @@ public String doCall(String requestBody)
LOGGER.debug("Request: {}", requestBody);
}
try {
@SuppressWarnings("unchecked")
Map<String, Object> request = (Map<String,Object>) new JSONReader().read(requestBody);
JsonRpcMapper.JsonRpcRequest request = mapper.parse(requestBody, serviceDescription);
if (request == null) {
response = errorResponse(null, 400, "Bad Request", null);
} else if (!ServiceDescription.JSON_RPC_VERSION.equals(request.get("version"))) {
} else if (!ServiceDescription.JSON_RPC_VERSION.equals(request.getVersion())) {
response = errorResponse(null, 505, "JSONRPC version not supported", null);
} else {
id = request.get("id");
method = (String) request.get("method");
List<?> parmList = (List<?>) request.get("params");
params = parmList.toArray();
if (method.equals("system.describe")) {
id = request.getId();
method = request.getMethod();
params = request.getParameters();
if (request.isSystemDescribe()) {
response = resultResponse(id, serviceDescription);
} else if (method.startsWith("system.")) {
} else if (request.isSystem()) {
response = errorResponse(id, 403, "System methods forbidden", null);
} else {
Object result;
try {
Method matchingMethod = matchingMethod(method, params);
params = mapper.parameters(request, matchingMethod);
if (LOGGER.isDebugEnabled()) {
Collection<String> parametersValuesAndTypes = new ArrayList<String>();
if (params != null) {
Expand Down Expand Up @@ -197,7 +200,7 @@ public Method matchingMethod(String methodName, Object[] params)
* ID given, using the code, message, and possible
* (JSON-encodable) argument passed in.
*/
public static String errorResponse(Object id, int code, String message, Object errorArg) {
private String errorResponse(Object id, int code, String message, Object errorArg) {
Map<String, Object> err = new HashMap<String, Object>();
err.put("name", "JSONRPCError");
err.put("code", code);
Expand All @@ -210,22 +213,21 @@ public static String errorResponse(Object id, int code, String message, Object e
* Construct and encode a JSON-RPC success response for the
* request ID given, using the result value passed in.
*/
public static String resultResponse(Object id, Object result) {
private String resultResponse(Object id, Object result) {
return response(id, "result", result);
}

/**
* Private API - used by errorResponse and resultResponse.
*/
public static String response(Object id, String label, Object value) {
private String response(Object id, String label, Object value) {
Map<String, Object> resp = new HashMap<String, Object>();
resp.put("version", ServiceDescription.JSON_RPC_VERSION);
if (id != null) {
resp.put("id", id);
}
resp.put(label, value);
String respStr = new JSONWriter().write(resp);
//System.err.println(respStr);
String respStr = mapper.write(resp);
return respStr;
}

Expand Down
Loading

0 comments on commit 119a957

Please sign in to comment.