diff --git a/src/main/java/com/loafle/commons/rpc/annotation/RPCMethod.java b/src/main/java/com/loafle/commons/rpc/annotation/RPCMethod.java new file mode 100644 index 0000000..cdb3f6e --- /dev/null +++ b/src/main/java/com/loafle/commons/rpc/annotation/RPCMethod.java @@ -0,0 +1,12 @@ +package com.loafle.commons.rpc.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RPCMethod { + String value() default ""; +} diff --git a/src/main/java/com/loafle/commons/rpc/registry/RPCInvoker.java b/src/main/java/com/loafle/commons/rpc/registry/RPCInvoker.java index b719ffb..21f65ea 100644 --- a/src/main/java/com/loafle/commons/rpc/registry/RPCInvoker.java +++ b/src/main/java/com/loafle/commons/rpc/registry/RPCInvoker.java @@ -8,5 +8,5 @@ import com.loafle.commons.rpc.protocol.RPCRegistryCodec; */ public interface RPCInvoker { boolean hasMethod(String method); - Object invoke(RPCRegistryCodec codec, Object... leadingParams) throws RPCException; + Object invoke(RPCRegistryCodec codec) throws RPCException; } diff --git a/src/main/java/com/loafle/commons/rpc/registry/RPCRegistry.java b/src/main/java/com/loafle/commons/rpc/registry/RPCRegistry.java index d555d37..d08ff23 100644 --- a/src/main/java/com/loafle/commons/rpc/registry/RPCRegistry.java +++ b/src/main/java/com/loafle/commons/rpc/registry/RPCRegistry.java @@ -8,8 +8,8 @@ import com.loafle.commons.rpc.RPCException; * RPCRegistry */ public interface RPCRegistry extends RPCInvoker { - Object getService(String name); + void registerService(Object receiver) throws RPCException; void registerService(Object receiver, String name) throws RPCException; - void registerServices(Object... receivers) throws RPCException; - void registerServices(Map receivers) throws RPCException; + void registerService(Object receiver, Class receiverClass) throws RPCException; + void registerService(Object receiver, Class receiverClass, String name) throws RPCException; } diff --git a/src/main/java/com/loafle/commons/rpc/registry/pojo/POJORPCRegistry.java b/src/main/java/com/loafle/commons/rpc/registry/pojo/POJORPCRegistry.java new file mode 100644 index 0000000..f06d5bf --- /dev/null +++ b/src/main/java/com/loafle/commons/rpc/registry/pojo/POJORPCRegistry.java @@ -0,0 +1,68 @@ +package com.loafle.commons.rpc.registry.pojo; + +import java.lang.reflect.Type; + +import com.loafle.commons.rpc.RPCException; +import com.loafle.commons.rpc.protocol.RPCRegistryCodec; +import com.loafle.commons.rpc.registry.RPCRegistry; +import com.loafle.commons.rpc.util.RPCServiceRegistry; + +/** + * POJORPCRegistry + */ +public class POJORPCRegistry implements RPCRegistry { + private RPCServiceRegistry serviceRegistry; + + public POJORPCRegistry() { + this.serviceRegistry = new RPCServiceRegistry(); + } + + @Override + public void registerService(Object receiver) throws RPCException { + if (null == receiver) { + throw new RPCException("receiver is null"); + } + this.registerService(receiver, receiver.getClass()); + } + + @Override + public void registerService(Object receiver, String name) throws RPCException { + if (null == receiver) { + throw new RPCException("receiver is null"); + } + this.registerService(receiver, receiver.getClass(), name); + } + + @Override + public void registerService(Object receiver, Class receiverClass) throws RPCException { + if (null == receiver) { + throw new RPCException("receiver is null"); + } + this.registerService(receiver, receiverClass, receiverClass.getName()); + } + + @Override + public void registerService(Object receiver, Class receiverClass, String name) throws RPCException { + this.serviceRegistry.register(receiver, receiverClass, name); + } + + @Override + public boolean hasMethod(String method) { + return this.serviceRegistry.hasMethod(method); + } + + @Override + public Object invoke(RPCRegistryCodec codec) throws RPCException { + String method = codec.method(); + if (!this.serviceRegistry.hasMethod(method)) { + throw new RPCException(String.format("method[%s] is not exist", method)); + } + Type[] parameterTypes = this.serviceRegistry.getParameterTypes(method); + Object[] params = codec.params(parameterTypes); + + Object result = this.serviceRegistry.invoke(method, params); + + return result; + } + +} \ No newline at end of file diff --git a/src/main/java/com/loafle/commons/rpc/util/RPCServiceRegistry.java b/src/main/java/com/loafle/commons/rpc/util/RPCServiceRegistry.java new file mode 100644 index 0000000..0867fab --- /dev/null +++ b/src/main/java/com/loafle/commons/rpc/util/RPCServiceRegistry.java @@ -0,0 +1,150 @@ +package com.loafle.commons.rpc.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +import com.loafle.commons.rpc.RPCException; +import com.loafle.commons.rpc.annotation.RPCMethod; + +/** + * RPCServiceRegistry + */ +public class RPCServiceRegistry { + private Map services; + + public RPCServiceRegistry() { + this.services = new HashMap<>(); + } + + public void register(Object receiver, Class receiverClass, String name) throws RPCException { + if (null == receiver) { + throw new RPCException("receiver is null"); + } + + String sName = name; + if ("" == sName.trim()) { + sName = receiverClass.getName(); + } + + RPCServiceMeta serviceMeta = new RPCServiceMeta(); + serviceMeta.instance = receiver; + + Method[] methods = receiverClass.getMethods(); + + for (Method method : methods) { + RPCMethod a = method.getAnnotation(RPCMethod.class); + if (null == a) { + continue; + } + + RPCServiceMethodMeta methodMeta = new RPCServiceMethodMeta(); + methodMeta.method = method; + methodMeta.returnType = method.getReturnType(); + methodMeta.parameterTypes = method.getGenericParameterTypes(); + + String n = "" == a.value() ? method.getName() : a.value(); + serviceMeta.methods.put(n, methodMeta); + } + + if (0 < serviceMeta.methods.size()) { + this.services.put(sName, serviceMeta); + } + } + + public boolean hasMethod(String method) { + String[] sm = method.split("."); + + if (null == sm || 2 != sm.length) { + return false; + } + RPCServiceMeta serviceMeta = this.services.get(sm[0]); + if (null == serviceMeta) { + return false; + } + RPCServiceMethodMeta methodMeta = serviceMeta.getMethodMeta(sm[1]); + if (null == methodMeta) { + return false; + } + return true; + } + + public Type[] getParameterTypes(String method) throws RPCException { + String[] sm = method.split("."); + + if (null == sm || 2 != sm.length) { + throw new RPCException(String.format("method[%s] is not valid", method)); + } + RPCServiceMeta serviceMeta = this.services.get(sm[0]); + if (null == serviceMeta) { + throw new RPCException(String.format("service[%s] is not exist", sm[0])); + } + RPCServiceMethodMeta methodMeta = serviceMeta.getMethodMeta(sm[1]); + if (null == methodMeta) { + throw new RPCException(String.format("method[%s] of service[%s] is not exist", sm[1], sm[0])); + } + return methodMeta.parameterTypes; + } + + public Object invoke(String method, Object... params) throws RPCException { + String[] sm = method.split("."); + + if (null == sm || 2 != sm.length) { + throw new RPCException(String.format("method[%s] is not valid", method)); + } + RPCServiceMeta serviceMeta = this.services.get(sm[0]); + if (null == serviceMeta) { + throw new RPCException(String.format("service[%s] is not exist", sm[0])); + } + RPCServiceMethodMeta methodMeta = serviceMeta.getMethodMeta(sm[1]); + if (null == methodMeta) { + throw new RPCException(String.format("method[%s] of service[%s] is not exist", sm[1], sm[0])); + } + + try { + return methodMeta.method.invoke(serviceMeta.instance, params); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RPCException(String.format("Cannot invoke method[%s] with params[%s]", method, params), e); + } + } + + public static class RPCServiceMeta { + private Object instance; + private Map methods; + + RPCServiceMeta() { + this.methods = new HashMap<>(); + } + + public Object getInstance() { + return this.instance; + } + + public RPCServiceMethodMeta getMethodMeta(String name) { + return this.methods.get(name); + } + } + + public static class RPCServiceMethodMeta { + private Method method; + private Class returnType; + private Type[] parameterTypes; + + RPCServiceMethodMeta() { + } + + public Method getMethod() { + return this.method; + } + + public Class getReturnType() { + return this.returnType; + } + + public Type[] getParameterTypes() { + return this.parameterTypes; + } + } +} \ No newline at end of file