Esempio n. 1
0
  /**
   * 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);
      }
    }
  }
Esempio n. 2
0
  /**
   * 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);
    }
  }