com.almende.eve.protocol.jsonrpc.formats.JSONRequest.java Source code

Java tutorial

Introduction

Here is the source code for com.almende.eve.protocol.jsonrpc.formats.JSONRequest.java

Source

/*
 * Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
 * License: The Apache Software License, Version 2.0
 */
package com.almende.eve.protocol.jsonrpc.formats;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.almende.eve.protocol.jsonrpc.annotation.Name;
import com.almende.eve.protocol.jsonrpc.annotation.Optional;
import com.almende.util.AnnotationUtil;
import com.almende.util.AnnotationUtil.AnnotatedMethod;
import com.almende.util.AnnotationUtil.AnnotatedParam;
import com.almende.util.callback.AsyncCallback;
import com.almende.util.jackson.JOM;
import com.almende.util.uuid.UUID;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * The Class JSONRequest.
 */
public final class JSONRequest extends JSONMessage {
    private static final Logger LOG = Logger.getLogger(JSONRequest.class.getCanonicalName());
    private static final long serialVersionUID = 1970046457233622444L;
    transient private AsyncCallback<?> callback = null;

    private JsonNode id = null;
    private String method = null;
    private ObjectNode params = null;

    /**
     * Instantiates a new jSON request.
     */
    public JSONRequest() {
        init(null, null, null, null);
    }

    /**
     * Instantiates a new JSON request.
     * 
     * @param json
     *            the json
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public JSONRequest(final String json) throws IOException {
        final ObjectMapper mapper = JOM.getInstance();
        init(mapper.readTree(json));
    }

    /**
     * Instantiates a new JSON request.
     * 
     * @param request
     *            the request
     */
    public JSONRequest(final JsonNode request) {
        init(request);
    }

    /**
     * Instantiates a new JSON request.
     *
     * @param method
     *            the method
     * @param params
     *            the params
     * @param callback
     *            the callback
     */
    public <T> JSONRequest(final String method, final ObjectNode params, final AsyncCallback<T> callback) {
        init(null, method, params, callback);
    }

    /**
     * Instantiates a new JSON request.
     *
     * @param method
     *            the method
     * @param params
     *            the params
     */
    public JSONRequest(final String method, final ObjectNode params) {
        init(null, method, params, null);
    }

    /**
     * Instantiates a new jSON request.
     *
     * @param id
     *            the id
     * @param method
     *            the method
     * @param params
     *            the params
     * @param callback
     *            the callback
     */
    public <T> JSONRequest(final JsonNode id, final String method, final ObjectNode params,
            final AsyncCallback<T> callback) {
        init(id, method, params, callback);
    }

    /**
     * Create a JSONRequest from a java method and arguments.
     *
     * @param method
     *            the method
     * @param args
     *            the args
     * @param callback
     *            the callback
     */
    public <T> JSONRequest(final Method method, final Object[] args, final AsyncCallback<T> callback) {
        AnnotatedMethod annotatedMethod = null;
        try {
            annotatedMethod = new AnnotationUtil.AnnotatedMethod(method);
        } catch (final Exception e) {
            LOG.log(Level.WARNING, "Method can't be used as annotated method", e);
            throw new IllegalArgumentException(
                    "Method '" + method.getName() + "' can't be used as annotated method.", e);
        }
        final List<AnnotatedParam> annotatedParams = annotatedMethod.getParams();

        final ObjectNode params = JOM.createObjectNode();

        for (int i = 0; i < annotatedParams.size(); i++) {
            final AnnotatedParam annotatedParam = annotatedParams.get(i);
            if (i < args.length && args[i] != null) {
                final Name nameAnnotation = annotatedParam.getAnnotation(Name.class);
                if (nameAnnotation != null && nameAnnotation.value() != null) {
                    final String name = nameAnnotation.value();
                    final JsonNode paramValue = JOM.getInstance().valueToTree(args[i]);
                    params.set(name, paramValue);
                } else {
                    throw new IllegalArgumentException("Parameter " + i + " in method '" + method.getName()
                            + "' is missing the @Name annotation.");
                }
            } else if (isRequired(annotatedParam)) {
                throw new IllegalArgumentException(
                        "Required parameter " + i + " in method '" + method.getName() + "' is null.");
            }
        }
        JsonNode id = null;
        try {
            id = JOM.getInstance().valueToTree(new UUID().toString());
        } catch (final Exception e) {
            LOG.log(Level.SEVERE, "Failed to generate UUID for request", e);
        }
        init(id, method.getName(), params, callback);
    }

    /**
     * Test if a parameter is required Reads the parameter annotation @Required.
     * Returns True if the annotation is not provided.
     * 
     * @param param
     *            the param
     * @return required
     */
    @SuppressWarnings("deprecation")
    static boolean isRequired(final AnnotatedParam param) {
        boolean required = true;
        final com.almende.eve.protocol.jsonrpc.annotation.Required requiredAnnotation = param
                .getAnnotation(com.almende.eve.protocol.jsonrpc.annotation.Required.class);
        if (requiredAnnotation != null) {
            required = requiredAnnotation.value();
        }
        if (param.getAnnotation(Optional.class) != null) {
            required = false;
        }
        return required;
    }

    /**
     * Inits the.
     * 
     * @param request
     *            the request
     */
    public void init(final JsonNode request) {
        if (request == null || request.isNull()) {
            throw new JSONRPCException(JSONRPCException.CODE.INVALID_REQUEST, "Request is null");
        }
        if (request.has(JSONRPC) && request.get(JSONRPC).isTextual()
                && !request.get(JSONRPC).asText().equals(VERSION)) {
            throw new JSONRPCException(JSONRPCException.CODE.INVALID_REQUEST,
                    "Value of member 'jsonrpc' is not equal to '2.0'");
        }
        if (!request.has(METHOD)) {
            throw new JSONRPCException(JSONRPCException.CODE.INVALID_REQUEST, "Member 'method' missing in request");
        }
        if (!(request.get(METHOD).isTextual())) {
            throw new JSONRPCException(JSONRPCException.CODE.INVALID_REQUEST, "Member 'method' is no String");
        }
        if (request.has(PARAMS) && !(request.get(PARAMS).isObject())) {
            throw new JSONRPCException(JSONRPCException.CODE.INVALID_REQUEST, "Member 'params' is no ObjectNode");
        }

        init(request.get(ID), request.get(METHOD).asText(), (ObjectNode) request.get(PARAMS), null);
    }

    /**
     * Inits the.
     * 
     * @param id
     *            the id
     * @param method
     *            the method
     * @param params
     *            the params
     */
    private <T> void init(final JsonNode id, final String method, final ObjectNode params,
            final AsyncCallback<T> callback) {
        this.setRequest(true);
        if (callback != null && (id == null || id.isNull())) {
            setId(JOM.getInstance().valueToTree(new UUID().toString()));
        } else {
            setId(id);
        }
        setMethod(method);
        setParams(params);
        setCallback(callback);
    }

    /**
     * Sets the id.
     * 
     * @param id
     *            the new id
     */
    public void setId(final JsonNode id) {
        this.id = id;
    }

    @Override
    public JsonNode getId() {
        return this.id;
    }

    /**
     * Sets the method.
     * 
     * @param method
     *            the new method
     */
    public void setMethod(final String method) {
        this.method = method;
    }

    /**
     * Gets the method.
     * 
     * @return the method
     */
    public String getMethod() {
        return this.method;
    }

    /**
     * Sets the params.
     * 
     * @param params
     *            the new params
     */
    public void setParams(final ObjectNode params) {
        this.params = params;
    }

    /**
     * Gets the params.
     * 
     * @return the params
     */
    public ObjectNode getParams() {
        return this.params;
    }

    /**
     * Put param.
     * 
     * @param name
     *            the name
     * @param value
     *            the value
     */
    public void putParam(final String name, final Object value) {
        this.params.set(name, JOM.getInstance().convertValue(value, JsonNode.class));
    }

    /**
     * Gets the param.
     * 
     * @param name
     *            the name
     * @return the param
     */
    public Object getParam(final String name) {
        final ObjectMapper mapper = JOM.getInstance();
        if (params.has(name)) {
            return mapper.convertValue(params.get(name), Object.class);
        }
        return null;
    }

    /**
     * Checks for param.
     * 
     * @param name
     *            the name
     * @return the object
     */
    public Object hasParam(final String name) {
        return this.params.has(name);
    }

    /**
     * Gets the jsonrpc version.
     *
     * @return the jsonrpc version
     */
    public String getJsonrpc() {
        return VERSION;
    }

    /**
     * Gets the callback.
     *
     * @return the callback
     */
    @JsonIgnore
    public AsyncCallback<?> getCallback() {
        return callback;
    }

    /**
     * Sets the callback.
     *
     * @param callback
     *            the new callback
     */
    @JsonIgnore
    public <T> void setCallback(AsyncCallback<T> callback) {
        this.callback = callback;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        final ObjectMapper mapper = JOM.getInstance();
        try {
            return mapper.writeValueAsString(this);
        } catch (final Exception e) {
            LOG.log(Level.WARNING, "", e);
        }
        return null;
    }
}