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

org.json.other.server.Base64JsonRpcExecutor Maven / Gradle / Ivy

There is a newer version: 1.04
Show newest version
/*
 * Copyright (C) 2011 ritwik.net
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.json.other.server;

import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.openyelp.cache.RpcCache;
import com.openyelp.commons.AllowAllTypeChecker;
import com.openyelp.commons.JsonRpcErrorCodes;
import com.openyelp.commons.JsonRpcException;
import com.openyelp.commons.JsonRpcRemoteException;
import com.openyelp.commons.RpcIntroSpection;
import com.openyelp.commons.TypeChecker;
import com.openyelp.server.HandleEntry;
import com.openyelp.server.JsonRpcServerTransport;


public final class Base64JsonRpcExecutor implements RpcIntroSpection {


    private static final Pattern METHOD_PATTERN = Pattern
            .compile("([_a-zA-Z][_a-zA-Z0-9]*)\\.([_a-zA-Z][_a-zA-Z0-9]*)");

    private final Map> handlers;

    private final TypeChecker typeChecker;
    private volatile boolean locked;

    public Base64JsonRpcExecutor() {
        this(new AllowAllTypeChecker());
    }

    @SuppressWarnings("unchecked")
    public Base64JsonRpcExecutor(TypeChecker typeChecker) {
        this.typeChecker = typeChecker;
        this.handlers = new HashMap>();
        addHandler("system", this, RpcIntroSpection.class);
    }

    public boolean isLocked() {
        return locked;
    }

    public  void addHandler(String name, T handler, Class... classes) {
        if (locked) {
            throw new JsonRpcException("executor has been locked, can't add more handlers");
        }

        synchronized (handlers) {
            HandleEntry handleEntry = new HandleEntry(typeChecker, handler, classes);
            if (this.handlers.containsKey(name)) {
                throw new IllegalArgumentException("handler already exists");
            }
            this.handlers.put(name, handleEntry);
        }
    }

    public void execute(JsonRpcServerTransport transport) {
        if (!locked) {
            synchronized (handlers) {
                locked = true;
            }
        }

        String methodName = null;
        JsonArray params = null;

        JsonObject resp = new JsonObject();
        resp.addProperty("jsonrpc", "2.0");

        String errorMessage = null;
        Integer errorCode = null;
        String errorData = null;

        JsonObject req = null;
        try {
            String requestData = transport.readRequest();
            JsonParser parser = new JsonParser();
            req = (JsonObject) parser.parse(new StringReader(requestData));
        } catch (Throwable t) {
            errorCode = JsonRpcErrorCodes.PARSE_ERROR_CODE;
            errorMessage = "unable to parse json-rpc request";
            errorData = getStackTrace(t);


            sendError(transport, resp, errorCode, errorMessage, errorData);
            return;
        }


        try {
            assert req != null;
            resp.add("id", req.get("id"));

            methodName = req.getAsJsonPrimitive("method").getAsString();
            params = (JsonArray) req.get("params");
            if (params == null) {
                params = new JsonArray();
            }
        } catch (Throwable t) {
            errorCode = JsonRpcErrorCodes.INVALID_REQUEST_ERROR_CODE;
            errorMessage = "unable to read request";
            errorData = getStackTrace(t);


            sendError(transport, resp, errorCode, errorMessage, errorData);
            return;
        }

        try {
            JsonElement result = executeMethod(methodName, params);
            resp.add("result", result);
        } catch (Throwable t) {
            if (t instanceof JsonRpcRemoteException) {
                sendError(transport, resp, (JsonRpcRemoteException) t);
                return;
            }
            errorCode = JsonRpcErrorCodes.getServerError(1);
            errorMessage = t.getMessage();
            errorData = getStackTrace(t);
            sendError(transport, resp, errorCode, errorMessage, errorData);
            return;
        }

        try {
            String responseData = resp.toString();
            transport.writeResponse(responseData);
        } catch (Exception e) {
        }
    }

    private void sendError(JsonRpcServerTransport transport, JsonObject resp, JsonRpcRemoteException e) {
        sendError(transport, resp, e.getCode(), e.getMessage(), e.getData());
    }

    private void sendError(JsonRpcServerTransport transport, JsonObject resp, Integer code, String message, String data) {
        JsonObject error = new JsonObject();
        if (code != null) {
            error.addProperty("code", code);
        }

        if (message != null) {
            error.addProperty("message", message);
        }

        if (data != null) {
            error.addProperty("data", data);
        }

        resp.add("error", error);
        resp.remove("result");
        String responseData = resp.toString();

        try {
            transport.writeResponse(responseData);
        } catch (Exception e) {
        	e.printStackTrace();
        }
    }

    private String getStackTrace(Throwable t) {
        StringWriter str = new StringWriter();
        PrintWriter w = new PrintWriter(str);
        t.printStackTrace(w);
        w.close();
        return str.toString();
    }

    private JsonElement executeMethod(String methodName, JsonArray params) throws Throwable {
        try {
            Matcher mat = METHOD_PATTERN.matcher(methodName);
            if (!mat.find()) {
                throw new JsonRpcRemoteException(JsonRpcErrorCodes.INVALID_REQUEST_ERROR_CODE, "invalid method name", null);
            }

            String handleName = mat.group(1);
            methodName = mat.group(2);

            HandleEntry handleEntry = handlers.get(handleName);
            if (handleEntry == null) {
                throw new JsonRpcRemoteException(JsonRpcErrorCodes.METHOD_NOT_FOUND_ERROR_CODE, "no such method exists", null);
            }

            Method executableMethod = null;
            for (Method m : handleEntry.getMethods()) {
                if (!m.getName().equals(methodName)) {
                    continue;
                }

                if (canExecute(m, params)) {
                    executableMethod = m;
                    break;
                }
            }

            if (executableMethod == null) {
                throw new JsonRpcRemoteException(JsonRpcErrorCodes.METHOD_NOT_FOUND_ERROR_CODE, "no such method exists", null);
            }

            Object result = executableMethod.invoke(
                    handleEntry.getHandler(), getParameters(executableMethod, params));

            return new Gson().toJsonTree(result);
        } catch (Throwable t) {
            if (t instanceof InvocationTargetException) {
                t = ((InvocationTargetException) t).getTargetException();
            }
            if (t instanceof JsonRpcRemoteException) {
                throw (JsonRpcRemoteException) t;
            }
            throw new JsonRpcRemoteException(JsonRpcErrorCodes.getServerError(0), t.getMessage(), getStackTrace(t));
        }
    }

    public boolean canExecute(Method method, JsonArray params) {
        if (method.getParameterTypes().length != params.size()) {
            return false;
        }

        return true;
    }

    public Object[] getParameters(Method method, JsonArray params) {
        List list = new ArrayList();
        Gson gson = new Gson();
        Class[] types = method.getParameterTypes();
        for (int i = 0; i < types.length; i++) {
            JsonElement p = params.get(i);
            Object o = gson.fromJson(p.toString(), types[i]);
            list.add(o);
        }
        return list.toArray();
    }

    public String[] listMethods() {
        Set methods = new TreeSet();
        for (String name : this.handlers.keySet()) {
            HandleEntry handleEntry = this.handlers.get(name);
            for (String method : handleEntry.getSignatures().keySet()) {
                methods.add(name + "." + method);
            }
        }
        String[] arr = new String[methods.size()];
        return methods.toArray(arr);
    }

    public String[] methodSignature(String method) {
        if (method == null) {
            throw new NullPointerException("method");
        }

        Matcher mat = METHOD_PATTERN.matcher(method);
        if (!mat.find()) {
            throw new IllegalArgumentException("invalid method name");
        }

        String handleName = mat.group(1);
        String methodName = mat.group(2);

        Set signatures = new TreeSet();

        HandleEntry handleEntry = handlers.get(handleName);
        if (handleEntry == null) {
            throw new IllegalArgumentException("no such method exists");
        }

        for (Method m : handleEntry.getMethods()) {
            if (!m.getName().equals(methodName)) {
                continue;
            }

            String[] sign = handleEntry.getSignatures().get(m.getName());

            StringBuffer buff = new StringBuffer(sign[0]);
            for (int i = 1; i < sign.length; i++) {
                buff.append(",").append(sign[i]);
            }

            signatures.add(buff.toString());
        }

        if (signatures.size() == 0) {
            throw new IllegalArgumentException("no such method exists");
        }

        String[] arr = new String[signatures.size()];
        return signatures.toArray(arr);
    }

	@Override
	public RpcCache getRpcCache() {
		return null;
	}

	@Override
	public void setRpcCache(RpcCache rpcCache) {
		// TODO Auto-generated method stub
		
	}


}