Java tutorial
/* * 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<String, HandleEntry<?>> 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<String, HandleEntry<?>>(); addHandler("system", this, RpcIntroSpection.class); } public boolean isLocked() { return locked; } public <T> void addHandler(String name, T handler, Class<T>... classes) { if (locked) { throw new JsonRpcException("executor has been locked, can't add more handlers"); } synchronized (handlers) { HandleEntry<T> handleEntry = new HandleEntry<T>(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<Object> list = new ArrayList<Object>(); 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<String> methods = new TreeSet<String>(); 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<String> signatures = new TreeSet<String>(); 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 } }