final List<JsonRpcRequest> requests = new ArrayList<JsonRpcRequest>();
final List<ExecutionCommand> commands = new ArrayList<ExecutionCommand>();
final List<JsonRpcResponse> responses = new ArrayList<JsonRpcResponse>();
JsonNode root;
ByteCountingInputStream iStream = null;
try {
iStream = createByteCountingInputStream(http.getRequest().getInputStream());
try {
EnumUtils.setHardFailureForThisThread(hardFailEnumDeserialisation);
root = mapper.readTree(iStream);
final long bytesRead = iStream.getCount();
final boolean isBatch = root.isArray();
if (isBatch) {
requests.addAll((List<JsonRpcRequest>)mapper.convertValue(root, BATCH_REQUEST_TYPE));
} else {
JsonRpcRequest rpc = mapper.convertValue(root, SINGLE_REQUEST_TYPE);
requests.add(rpc);
}
if (requests.isEmpty()) {
writeErrorResponse(http, context, new CougarValidationException(ServerFaultCode.NoRequestsFound, "No Requests found in rpc call"));
} else {
final TimeConstraints realTimeConstraints = DefaultTimeConstraints.rebaseFromNewStartTime(context.getRequestTime(), readRawTimeConstraints(http.getRequest()));
for (final JsonRpcRequest rpc : requests) {
final JsonRpcOperationBinding binding = bindings.get(stripMinorVersionFromUri(rpc.getMethod().toLowerCase()));
if (binding!=null) {
try {
JsonRpcParam [] paramDefs = binding.getJsonRpcParams();
final Object [] args = new Object[paramDefs.length];
for (int i=0;i<paramDefs.length;i++) {
JsonNode paramValue = rpc.getParams().isArray() ? rpc.getParams().get(i) : rpc.getParams().get(paramDefs[i].getName());
JavaType javaType = paramDefs[i].getJavaType();
args[i] = mapper.convertValue(paramValue, javaType);
// complex types are handled by the mapper, but for some reason, direct enums are not
if (javaType.isEnumType() && args[i] != null && ((Enum)args[i]).name().equals("UNRECOGNIZED_VALUE")) {
throw new IllegalArgumentException(new Exception(new EnumDerialisationException("UNRECOGNIZED_VALUE is not allowed as an input")));
}
}
commands.add(new ExecutionCommand() {//2nd: index 0, 3rd: index 1, 4th: index 2
@Override
public void onResult(ExecutionResult executionResult) {
JsonRpcResponse response = buildExecutionResultResponse(rpc, executionResult);
synchronized(responses) {
responses.add(response);
writeResponseIfComplete(http, context, isBatch, requests, responses, bytesRead);
}
}
@Override
public OperationKey getOperationKey() {
return binding.getOperationDefinition().getOperationKey();
}
@Override
public Object[] getArgs() {
return args;
}
@Override
public TimeConstraints getTimeConstraints() {
return realTimeConstraints;
}
});
} catch (Exception e) {
if (e instanceof IllegalArgumentException && e.getCause()!=null && e.getCause().getCause()!=null && e.getCause().getCause() instanceof EnumDerialisationException) {
responses.add(JsonRpcErrorResponse.buildErrorResponse(rpc, new JsonRpcError(INVALID_PARAMS, ServerFaultCode.ServerDeserialisationFailure.getDetail(), null)));
}
else {
responses.add(JsonRpcErrorResponse.buildErrorResponse(rpc, new JsonRpcError(INVALID_PARAMS, ServerFaultCode.MandatoryNotDefined.getDetail(), null)));
}
writeResponseIfComplete(http, context, isBatch, requests, responses, bytesRead);
}
} else {
responses.add(JsonRpcErrorResponse.buildErrorResponse(rpc, new JsonRpcError(METHOD_NOT_FOUND, ServerFaultCode.NoSuchOperation.getDetail(), null)));
writeResponseIfComplete(http, context, isBatch, requests, responses, bytesRead);
}
}
}
} catch (Exception ex) {
//This happens when there was a problem reading
//deal with case where every request was bad
writeErrorResponse(http, context, CougarMarshallingException.unmarshallingException("json",ex,false));
commands.clear();
}
//return command resolver irrespective of whether it is empty so the top level processor doesn't error
return new CommandResolver<HttpCommand>() {
@Override
public ExecutionContextWithTokens resolveExecutionContext() {
return context;
}
@Override
public Iterable<ExecutionCommand> resolveExecutionCommands() {
return commands;
}
};
} catch (Exception e) {
throw CougarMarshallingException.unmarshallingException("json", "Unable to resolve requests for json-rpc", e, false);
} finally {
try {
if (iStream != null) {
iStream.close();
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}