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

io.zbus.rpc.RpcProcessor Maven / Gradle / Ivy

There is a newer version: 1.0.0-b1
Show newest version
package io.zbus.rpc;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.zbus.kit.FileKit;
import io.zbus.kit.StrKit;
import io.zbus.kit.logging.Logger;
import io.zbus.kit.logging.LoggerFactory;
import io.zbus.transport.http.Message; 


public class RpcProcessor {
	private static final Logger log = LoggerFactory.getLogger(RpcProcessor.class);  
	
	private RpcCodec codec = new JsonRpcCodec();
	private Map methods = new HashMap(); 
	private Map> object2Methods = new HashMap>();	
	
	private String docUrlContext = "/";
	 
	public void addModule(Object... services){
		for(Object obj : services){
			if(obj == null) continue;
			for(Class intf : getAllInterfaces(obj.getClass())){
				addModule(intf.getSimpleName(), obj);
				addModule(intf.getName(), obj);
			} 
			addModule(obj.getClass().getSimpleName(), obj);
			addModule(obj.getClass().getName(), obj);
		} 
	}
	
	public void addModule(String module, Object... services){
		for(Object service: services){
			this.initCommandTable(module, service);
		}
	} 
	
	public void addModule(Class... clazz){
		Object[] services = new Object[clazz.length];
		for(int i=0;i c = clazz[i];
			try {
				services[i] = c.newInstance();
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			} 
		} 
		addModule(services);
	}
	
	public void addModule(String module, Class... clazz){
		Object[] services = new Object[clazz.length];
		for(int i=0;i c = clazz[i];
			try {
				services[i] = c.newInstance();
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			} 
		} 
		addModule(module, services);
	} 
	
	public void removeModule(Object... services){
		for(Object obj : services){
			for(Class intf : getAllInterfaces(obj.getClass())){
				removeModule(intf.getSimpleName(), obj);
				removeModule(intf.getCanonicalName(), obj);
			} 
			removeModule(obj.getClass().getSimpleName(), obj);
			removeModule(obj.getClass().getName(), obj);
		}
	}
	
	public void removeModule(String module, Object... services){
		for(Object service: services){
			this.removeCommandTable(module, service);
		}
	}
	
	private static List> getAllInterfaces(Class clazz){
		List> res = new ArrayList>();
		while(clazz != null){ 
			res.addAll(Arrays.asList(clazz.getInterfaces()));
			clazz = clazz.getSuperclass();
		}
		return res;
	}  
	
	private void addModuleInfo(String module, Object service){
		List rpcMethods = null;
		String serviceKey = service.getClass().getCanonicalName();
		if(object2Methods.containsKey(serviceKey)){
			rpcMethods = object2Methods.get(serviceKey); 
		} else {
			rpcMethods = new ArrayList();
			object2Methods.put(serviceKey,rpcMethods);
		}
		  
		
		Method [] methods = service.getClass().getMethods();  
		for (Method m : methods) { 
			if(m.getDeclaringClass() == Object.class) continue;
			String method = m.getName();
			Remote cmd = m.getAnnotation(Remote.class);
			if(cmd != null){ 
				method = cmd.id();
				if(cmd.exclude()) continue;
				if("".equals(method)){
					method = m.getName();
				}  
			}
			RpcMethod rpcm = null;
			for(RpcMethod rm : rpcMethods) {
				if(rm.getName().equals(method)) {
					rpcm = rm;
					break;
				}
			}
			if(rpcm != null) {
				if(!rpcm.modules.contains(module)) {
					rpcm.modules.add(module);
				}
			} else {
				List modules = new ArrayList(); 
				modules.add(module);
				rpcm = new RpcMethod();
				rpcm.setModules(modules);
				rpcm.setName(method);
				rpcm.setReturnType(m.getReturnType().getCanonicalName());
				List paramTypes = new ArrayList();
				for(Class t : m.getParameterTypes()){
					paramTypes.add(t.getCanonicalName());
				}
				rpcm.setParamTypes(paramTypes);
				rpcMethods.add(rpcm);
			} 
		} 
	}
	
	private void removeModuleInfo(Object service){
		String serviceKey = service.getClass().getName();
		object2Methods.remove(serviceKey);
	} 
	
	private void initCommandTable(String module, Object service){
		addModuleInfo(module, service);
		
		try {  
			Method [] methods = service.getClass().getMethods(); 
			for (Method m : methods) { 
				if(m.getDeclaringClass() == Object.class) continue;
				
				String method = m.getName();
				Remote cmd = m.getAnnotation(Remote.class);
				if(cmd != null){ 
					method = cmd.id();
					if(cmd.exclude()) continue;
					if("".equals(method)){
						method = m.getName();
					}  
				} 
				
				m.setAccessible(true);
				MethodInstance mi = new MethodInstance(m, service);
				
				String[] keys = paramSignature(module, m);
				for(String key : keys){
					if(this.methods.containsKey(key)){
						log.debug(key + " overrided"); 
					}  
					this.methods.put(key, mi); 
				} 
			}  
		} catch (SecurityException e) {
			log.error(e.getMessage(), e);
		}   
	}
	
	private void removeCommandTable(String module, Object service){
		removeModuleInfo(service);
		
		try {  
			Method [] methods = service.getClass().getMethods(); 
			for (Method m : methods) { 
				String method = m.getName();
				Remote cmd = m.getAnnotation(Remote.class);
				if(cmd != null){ 
					method = cmd.id();
					if(cmd.exclude()) continue;
					if("".equals(method)){
						method = m.getName();
					}  
				} 
				String[] keys = paramSignature(module, m);
				for(String key : keys){ 
					this.methods.remove(key);
				}  
			}  
		} catch (SecurityException e) {
			log.error(e.getMessage(), e);
		}   
	}  
	
	
	static class MethodMatchResult{
		MethodInstance method;
		boolean fullMatched;
	}
	
	private MethodMatchResult matchMethod(Request req){ 
		StringBuilder sb = new StringBuilder();
		if(req.getParamTypes() != null){
			for(String type : req.getParamTypes()){
				sb.append(type+",");
			}
		}
		String module = req.getModule(); 
		String method = req.getMethod();
		String key = module+":"+method+":"+sb.toString();  
		String key2 = module+":"+method;
		
		MethodMatchResult result = new MethodMatchResult();
		if(this.methods.containsKey(key)){
			result.method = this.methods.get(key); 
			result.fullMatched = true;
			return result;
		} else { 
			if(this.methods.containsKey(key2)){
				result.method = this.methods.get(key2); 
				result.fullMatched = false; 
				return result;
			}
			String errorMsg = String.format("%s:%s not found, missing moudle settings?", module, method);
			throw new IllegalArgumentException(errorMsg); 
		}
	}
	
	private String[] paramSignature(String module, Method m){
		Class[] paramTypes = m.getParameterTypes();
		StringBuilder sb = new StringBuilder();
		StringBuilder sb2 = new StringBuilder();
		for(int i=0;i[] targetParamTypes = target.method.getParameterTypes();
		int requiredLength = 0;
		for(Class clazz : targetParamTypes){
			if(Message.class.isAssignableFrom(clazz)) continue; //ignore Message parameter
			requiredLength++;
		}
		if(requiredLength !=  req.getParams().length){
			String requiredParamTypeString = "";
			for(int i=0;i paramType = targetParamTypes[i]; 
				requiredParamTypeString += paramType.getName();
				if(i" +  
				"%s" +  
				"%s(%s)" + 
				"	
    %s
" + "
%s
" + "" + "" + "
    %s
" + ""; String methodLink = docUrlContext + m.modules.get(0) + "/" + m.name; String method = m.name; String paramList = ""; for(String type : m.paramTypes) { paramList += type + ", "; } if(paramList.length() > 0) { paramList = paramList.substring(0, paramList.length()-2); } String paramDesc = ""; String methodDesc = ""; String modules = ""; for(String module : m.modules) { modules += "
  • "+module+"
  • "; } return String.format(fmt, color, m.returnType, methodLink, method, paramList, paramDesc, methodDesc, modules); } private Message renderDoc() throws IOException { Message result = new Message(); String doc = "
    "; int rowIdx = 0; for(List objectMethods : object2Methods.values()) { for(RpcMethod m : objectMethods) { doc += rowDoc(m, rowIdx++); } } doc += "
    "; Map model = new HashMap(); model.put("content", doc); String body = FileKit.loadFile("rpc.htm", model); result.setBody(body); return result; } public Message process(Message msg){ String encoding = msg.getEncoding(); Object result = null; int status = RpcCodec.STATUS_OK; //assumed to be successful try { Request req = codec.decodeRequest(msg); if(req == null || StrKit.isEmpty(req.getMethod())){ return renderDoc(); } else { MethodMatchResult matchResult = matchMethod(req); MethodInstance target = matchResult.method; if(matchResult.fullMatched){ checkParamTypes(target, req); } Class[] targetParamTypes = target.method.getParameterTypes(); Object[] invokeParams = new Object[targetParamTypes.length]; Object[] reqParams = req.getParams(); int j = 0; for(int i=0; i modules = new ArrayList(); private String name; private List paramTypes = new ArrayList(); private String returnType; public List getModules() { return modules; } public void setModules(List modules) { this.modules = modules; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getParamTypes() { return paramTypes; } public void setParamTypes(List paramTypes) { this.paramTypes = paramTypes; } public String getReturnType() { return returnType; } public void setReturnType(String returnType) { this.returnType = returnType; } } }




    © 2015 - 2025 Weber Informatics LLC | Privacy Policy