All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.cenotelie.commons.jsonrpc.JsonRpcServerBase Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2017 Association Cénotélie (cenotelie.fr)
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this program.
 * If not, see .
 ******************************************************************************/

package fr.cenotelie.commons.jsonrpc;

import fr.cenotelie.hime.redist.ASTNode;
import fr.cenotelie.commons.utils.TextUtils;
import fr.cenotelie.commons.utils.json.Json;
import fr.cenotelie.commons.utils.json.JsonDeserializer;
import fr.cenotelie.commons.utils.json.JsonLexer;
import fr.cenotelie.commons.utils.json.JsonParser;
import fr.cenotelie.commons.utils.logging.BufferedLogger;

import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * A base implementation of a Json-Rpc server
 *
 * @author Laurent Wouters
 */
public abstract class JsonRpcServerBase implements JsonRpcServer {
    /**
     * The de-serializer to use
     */
    protected final JsonDeserializer deserializer;

    /**
     * Initializes this server
     */
    public JsonRpcServerBase() {
        this(JsonDeserializer.DEFAULT);
    }

    /**
     * Initializes this server
     *
     * @param deserializer The de-serializer to use for requests
     */
    public JsonRpcServerBase(JsonDeserializer deserializer) {
        this.deserializer = deserializer;
    }

    @Override
    public String handle(String input) {
        return handle(new StringReader(input));
    }

    @Override
    public String handle(Reader input) {
        BufferedLogger logger = new BufferedLogger();
        ASTNode definition = Json.parse(logger, input);
        if (definition == null || !logger.getErrorMessages().isEmpty())
            return JsonRpcResponseError.newParseError(null).serializedJSON();
        return handle(definition);
    }

    /**
     * Handles the specified input
     *
     * @param definition the definition of the request
     * @return The response
     */
    protected String handle(ASTNode definition) {
        Object object = deserializeRequests(definition);
        if (object == null)
            return JsonRpcResponseError.newInvalidRequest(null).serializedJSON();
        if (object instanceof JsonRpcRequest) {
            JsonRpcResponse response = handle((JsonRpcRequest) object);
            if (response == null)
                return null;
            return response.serializedJSON();
        } else {
            List requests = ((List) object);
            if (requests.isEmpty())
                return JsonRpcResponseError.newInvalidRequest(null).serializedJSON();
            List responses = handle(requests);
            if (responses.isEmpty())
                return null;
            return Json.serialize(responses);
        }
    }

    @Override
    public abstract JsonRpcResponse handle(JsonRpcRequest request);

    @Override
    public List handle(List requests) {
        List responses = new ArrayList<>(requests.size());
        for (JsonRpcRequest request : requests) {
            if (request == null)
                responses.add(JsonRpcResponseError.newInvalidRequest(null));
            else {
                JsonRpcResponse response = handle(request);
                if (response != null)
                    responses.add(response);
            }
        }
        return responses;
    }

    /**
     * De-serializes the requests objects
     *
     * @param definition The serialized definition
     * @return The request(s)
     */
    protected Object deserializeRequests(ASTNode definition) {
        if (definition.getSymbol().getID() == JsonParser.ID.object)
            return deserializeRequest(definition);
        if (definition.getSymbol().getID() != JsonParser.ID.array)
            return null;
        List requests = new ArrayList<>();
        for (ASTNode child : definition.getChildren()) {
            JsonRpcRequest request = deserializeRequest(child);
            requests.add(request);
        }
        return requests;
    }

    /**
     * De-serializes the request object
     *
     * @param definition The serialized definition
     * @return The request
     */
    protected JsonRpcRequest deserializeRequest(ASTNode definition) {
        if (definition.getSymbol().getID() != JsonParser.ID.object)
            return null;

        String jsonRpc = null;
        String identifier = null;
        String method = null;
        ASTNode params = null;

        for (ASTNode child : definition.getChildren()) {
            ASTNode nodeMemberName = child.getChildren().get(0);
            String name = TextUtils.unescape(nodeMemberName.getValue());
            name = name.substring(1, name.length() - 1);
            ASTNode nodeValue = child.getChildren().get(1);
            switch (name) {
                case "jsonrpc": {
                    if (nodeValue.getSymbol().getID() != JsonLexer.ID.LITERAL_STRING)
                        return null;
                    jsonRpc = TextUtils.unescape(nodeValue.getValue());
                    jsonRpc = jsonRpc.substring(1, jsonRpc.length() - 1);
                    break;
                }
                case "id": {
                    switch (nodeValue.getSymbol().getID()) {
                        case JsonLexer.ID.LITERAL_NULL:
                            identifier = null;
                            break;
                        case JsonLexer.ID.LITERAL_FALSE:
                            return null;
                        case JsonLexer.ID.LITERAL_TRUE:
                            return null;
                        case JsonLexer.ID.LITERAL_INTEGER:
                            identifier = nodeValue.getValue();
                            break;
                        case JsonLexer.ID.LITERAL_DECIMAL:
                            identifier = nodeValue.getValue();
                            break;
                        case JsonLexer.ID.LITERAL_DOUBLE:
                            identifier = nodeValue.getValue();
                            break;
                        case JsonLexer.ID.LITERAL_STRING:
                            identifier = TextUtils.unescape(nodeValue.getValue());
                            identifier = identifier.substring(1, identifier.length() - 1);
                            break;
                        default:
                            return null;
                    }
                    break;
                }
                case "method": {
                    if (nodeValue.getSymbol().getID() != JsonLexer.ID.LITERAL_STRING)
                        return null;
                    method = TextUtils.unescape(nodeValue.getValue());
                    method = method.substring(1, method.length() - 1);
                    break;
                }
                case "params": {
                    params = nodeValue;
                    break;
                }
            }
        }

        if (!Objects.equals(jsonRpc, "2.0"))
            return null;
        if (method == null)
            return null;
        Object params2 = params != null ? deserializer.deserialize(params, method) : null;
        return new JsonRpcRequest(identifier, method, params2);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy