/** * Handles the given {@link ObjectNode} and writes the responses to the given {@link * OutputStream}. * * @param node the {@link JsonNode} * @param ops the {@link OutputStream} * @throws IOException on error */ protected void handleObject(ObjectNode node, OutputStreamWrapper opsw) throws IOException { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Request: " + node.toString()); } // validate request if (!backwardsComaptible && !node.has("jsonrpc") || !node.has("method")) { writeAndFlushResponse( opsw, createErrorResponse("jsonrpc", "null", StandardJsonError.INVALID_REQUEST, null)); return; } // get nodes JsonNode jsonPrcNode = node.get("jsonrpc"); JsonNode methodNode = node.get("method"); JsonNode idNode = node.get("id"); JsonNode paramsNode = node.get("params"); // get node values String jsonRpc = (jsonPrcNode != null && !jsonPrcNode.isNull()) ? jsonPrcNode.asText() : "2.0"; String methodName = (methodNode != null && !methodNode.isNull()) ? methodNode.asText() : null; Object id = parseId(idNode); // find methods Set<Method> methods = new HashSet<Method>(); methods.addAll(ReflectionUtil.findMethods(getHandlerClass(), methodName)); if (methods.isEmpty()) { writeAndFlushResponse( opsw, createErrorResponse(jsonRpc, id, StandardJsonError.METHOD_NOT_FOUND, null)); return; } // choose a method MethodAndArgs methodArgs = findBestMethodByParamsNode(methods, paramsNode); if (methodArgs == null) { writeAndFlushResponse( opsw, createErrorResponse(jsonRpc, id, StandardJsonError.INVALID_PARAMS, null)); return; } // invoke the method JsonNode result = null; Throwable thrown = null; try { result = invoke(methodArgs.method, methodArgs.arguments); } catch (Throwable e) { thrown = e; } // respond if it's not a notification request if (id != null) { // attempt to resolve the error JsonError error = null; if (thrown != null) { // get cause of exception Throwable e = thrown; if (InvocationTargetException.class.isInstance(e)) { e = InvocationTargetException.class.cast(e).getTargetException(); } // resolve error if (errorResolver != null) { error = errorResolver.resolveError(e, methodArgs.method, methodArgs.arguments); } else { error = DEFAULT_ERRROR_RESOLVER.resolveError(e, methodArgs.method, methodArgs.arguments); } // make sure we have a JsonError if (error == null) { error = new com.googlecode.jsonrpc4j.ErrorResolver.BasicJsonError( 0, e.getMessage(), e.getClass().getName()); } } // the resoponse object JsonRpcServerResponse response = null; // build error if (error != null) { response = createErrorResponse( jsonRpc, id, error.getCode(), 500, error.getMessage(), error.getData()); // build success } else { response = createSuccessResponse(jsonRpc, id, result); } // write it writeAndFlushResponse(opsw, response); } // log and potentially re-throw errors if (thrown != null) { if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.log(Level.SEVERE, "Error in JSON-RPC Service", thrown); } if (rethrowExceptions) { throw new RuntimeException(thrown); } } }
/** * Handles the given {@link ObjectNode} and writes the responses to the given {@link * OutputStream}. * * @param node the {@link JsonNode} * @param ops the {@link OutputStream} * @throws JsonGenerationException * @throws JsonMappingException * @throws IOException */ private void handleObject(ObjectNode node, OutputStream ops) throws JsonGenerationException, JsonMappingException, IOException { // validate request if (!node.has("jsonrpc") || !node.has("method")) { mapper.writeValue( ops, createErrorResponse("jsonrpc", "null", -32600, "Invalid Request", null)); return; } // parse request String jsonRpc = node.get("jsonrpc").getValueAsText(); String methodName = node.get("method").getValueAsText(); String id = node.get("id").getValueAsText(); JsonNode params = node.get("params"); int paramCount = (params != null) ? params.size() : 0; // find methods Set<Method> methods = new HashSet<Method>(); methods.addAll(ReflectionUtil.findMethods(getHandlerClass(), methodName)); // method not found if (methods.isEmpty()) { mapper.writeValue(ops, createErrorResponse(jsonRpc, id, -32601, "Method not found", null)); return; } // iterate through the methods and remove // the one's who's parameter count's don't // match the request Iterator<Method> itr = methods.iterator(); while (itr.hasNext()) { Method method = itr.next(); if (method.getParameterTypes().length != paramCount) { itr.remove(); } } // choose a method Method method = null; List<JsonNode> paramNodes = new ArrayList<JsonNode>(); // handle param arrays, no params, and single methods if (paramCount == 0 || params.isArray() || (methods.size() == 1)) { method = methods.iterator().next(); for (int i = 0; i < paramCount; i++) { paramNodes.add(params.get(i)); } // handle named params } else if (params.isObject()) { // loop through each method for (Method m : methods) { // get method annotations Annotation[][] annotations = m.getParameterAnnotations(); boolean found = true; List<JsonNode> namedParams = new ArrayList<JsonNode>(); for (int i = 0; i < annotations.length; i++) { // look for param name annotations String paramName = null; for (int j = 0; j < annotations[i].length; j++) { if (!JsonRpcParamName.class.isInstance(annotations[i][j])) { continue; } else { paramName = JsonRpcParamName.class.cast(annotations[i][j]).value(); continue; } } // bail if param name wasn't found if (paramName == null) { found = false; break; // found it by name } else if (params.has(paramName)) { namedParams.add(params.get(paramName)); } } // did we find it? if (found) { method = m; paramNodes.addAll(namedParams); break; } } } // invalid parameters if (method == null) { mapper.writeValue( ops, createErrorResponse(jsonRpc, id, -32602, "Invalid method parameters.", null)); return; } // invoke the method JsonNode result = null; ObjectNode error = null; Throwable thrown = null; try { result = invoke(method, paramNodes); } catch (Throwable e) { thrown = e; if (InvocationTargetException.class.isInstance(e)) { e = InvocationTargetException.class.cast(e).getTargetException(); } error = mapper.createObjectNode(); error.put("code", 0); error.put("message", e.getMessage()); error.put("data", e.getClass().getName()); } // bail if notification request if (id == null) { return; } // create response ObjectNode response = mapper.createObjectNode(); response.put("jsonrpc", jsonRpc); response.put("id", id); if (error == null) { response.put("result", result); } else if (error != null) { response.put("error", error); } // write it mapper.writeValue(ops, response); // re-throw errors if (thrown != null) { throw new RuntimeException(thrown); } }