From a3ce9fab07af3011619d15c234cefda4b203e233 Mon Sep 17 00:00:00 2001 From: crylearner Date: Sun, 8 Jul 2018 23:51:15 +0800 Subject: [PATCH] new extense --- src/rpc/framework/server/Event.java | 29 +++ src/rpc/framework/server/EventCenter.java | 146 +++++++++++++++ .../server/EventListenerInterface.java | 5 + .../server/EventSourceInterface.java | 7 + src/rpc/framework/server/RpcServer.java | 38 +++- .../framework/server/RpcServiceAdapter.java | 52 ++++-- .../framework/server/RpcServiceInterface.java | 5 +- src/rpc/framework/server/RpcSubscriber.java | 176 ++++++++++++++++++ ...viceRegister.java => ServiceRegistry.java} | 13 +- .../server/annotation/RpcAttachEvent.java | 13 ++ .../server/annotation/RpcDetachEvent.java | 12 ++ .../framework/server/annotation/RpcEvent.java | 15 ++ .../server/annotation/RpcMethod.java | 25 +++ .../annotation/{Rpc.java => RpcService.java} | 7 +- src/server/json/Hello.java | 41 +++- src/server/json/HelloRpcWrapper.java | 44 +++++ src/server/json/HelloService.java | 48 +++-- src/server/json/Main.java | 14 +- .../json/android/ContentProviderService.java | 44 +++++ src/server/json/android/ContextService.java | 64 +++++++ src/server/json/android/CursorService.java | 26 +++ src/server/json/android/Main.java | 28 +++ .../server/RpcServiceAdapterTest.java | 6 +- .../framework/server/ServiceRegisterTest.java | 8 +- 24 files changed, 798 insertions(+), 68 deletions(-) create mode 100644 src/rpc/framework/server/Event.java create mode 100644 src/rpc/framework/server/EventCenter.java create mode 100644 src/rpc/framework/server/EventListenerInterface.java create mode 100644 src/rpc/framework/server/EventSourceInterface.java create mode 100644 src/rpc/framework/server/RpcSubscriber.java rename src/rpc/framework/server/{ServiceRegister.java => ServiceRegistry.java} (88%) create mode 100644 src/rpc/framework/server/annotation/RpcAttachEvent.java create mode 100644 src/rpc/framework/server/annotation/RpcDetachEvent.java create mode 100644 src/rpc/framework/server/annotation/RpcEvent.java create mode 100644 src/rpc/framework/server/annotation/RpcMethod.java rename src/rpc/framework/server/annotation/{Rpc.java => RpcService.java} (66%) create mode 100644 src/server/json/HelloRpcWrapper.java create mode 100644 src/server/json/android/ContentProviderService.java create mode 100644 src/server/json/android/ContextService.java create mode 100644 src/server/json/android/CursorService.java create mode 100644 src/server/json/android/Main.java diff --git a/src/rpc/framework/server/Event.java b/src/rpc/framework/server/Event.java new file mode 100644 index 0000000..1dd2bae --- /dev/null +++ b/src/rpc/framework/server/Event.java @@ -0,0 +1,29 @@ +//package rpc.framework.server; +// +//public class Event { +// public String ID; +// +// public Event(String iD) { +// super(); +// ID = iD; +// } +// +// @Override +// public int hashCode() { +// return ID.hashCode(); // FIXME:: same content string but not the same object? +// } +// +// @Override +// public boolean equals(Object obj) { +// if (obj instanceof Event) { +// return this.ID == ((Event) obj).ID; +// } else { +// return super.equals(obj); +// } +// } +// +// @Override +// public String toString() { +// return ID; +// } +//} diff --git a/src/rpc/framework/server/EventCenter.java b/src/rpc/framework/server/EventCenter.java new file mode 100644 index 0000000..f134628 --- /dev/null +++ b/src/rpc/framework/server/EventCenter.java @@ -0,0 +1,146 @@ +//package rpc.framework.server; +// +//import java.util.ArrayList; +//import java.util.HashSet; +//import java.util.LinkedList; +//import java.util.concurrent.ConcurrentHashMap; +// +//import org.json.JSONObject; +// +//import rpc.framework.RpcInvoker; +//import rpc.framework.RpcServerInvokerHandler; +//import rpc.json.message.RpcNotification; +//import rpc.util.IDGenerator; +//import rpc.util.RpcLog; +// +///** +// * @author sunshyran +// * +// */ +//public class EventCenter implements EventListenerInterface { +// private static final String TAG="EventCenter"; +// private RpcServerInvokerHandler mHandler = null; +// private IDGenerator mSIDGen = new IDGenerator(); // TODO:: reuse id generator temporally +// public static final long INVALID_SID = -1; +// private HashSet mSources = new HashSet(); +// +// private class EventListener implements EventListenerInterface { +// private long mSID = -1; +// private EventListenerInterface mListener = null; +// public EventListener(long SID, EventListenerInterface listener) { +// mSID = SID; +// mListener = listener; +// } +// @Override +// public void onNotify(Event event, Object data) { +// mListener.onNotify(event, data); +// } +// +// } +// private ConcurrentHashMap> mListeners = new ConcurrentHashMap>(); +// +// /**add event source into event center +// * @param source +// */ +// public void addEventSource(EventSourceInterface source) { +// synchronized (mSources) { +// if (mSources.contains(source)) { +// RpcLog.w(TAG, "source " + source + " is already added into event center!"); +// } else { +// RpcLog.i(TAG, "add source " + source + " into event center"); +// mSources.add(source); +// } +// } +// } +// +// /**remove source from event center +// * @param source +// */ +// public void removeEventSource(EventSourceInterface source) { +// synchronized (mSources) { +// if (!mSources.contains(source)) { +// RpcLog.w(TAG, "source " + source + " is not in event center!"); +// } else { +// RpcLog.i(TAG, "remove source " + source + " from event center"); +// mSources.remove(source); +// } +// } +// } +// +// public long addEventListener(Event event, EventListener listener) { +// boolean isAcceptable = false; +// synchronized (mSources) { +// for (EventSourceInterface source:mSources) { +// if (source.acceptEvent(event)) { +// if (source.subscribe(event, this)) { +// isAcceptable = true; +// } else { +// RpcLog.e(TAG, "subscribe event of source failed: " + event + ", " + source); +// } +// } +// } +// } +// +// if (!isAcceptable) { +// RpcLog.e(TAG, "no source accept event " + event); +// return INVALID_SID; +// } +// +// long sid = aquireSID(); +// LinkedList listeners = mListeners.getOrDefault(event, new LinkedList()); +// synchronized (listeners) { // FIXME:: thread safe is enough? +// listeners.add(new EventListener(sid, listener)); +// mListeners.put(event, listeners); +// } +// return sid; +// } +// +// public void removeEventListener(Event event, EventListener listener) { +// boolean isAcceptable = false; +// synchronized (mSources) { +// for (EventSourceInterface source:mSources) { +// if (source.acceptEvent(event)) { +// source.unsubscribe(event, this); +// } +// } +// } +// +// +// } +// +// +// +// private long aquireSID() { +// return mSIDGen.getRequestId(); +// } +// +// +// @Override +// public void onNotify(Event event, Object data) { +// System.out.println("onNotify"); +// HashSet listeners = mListeners.get(event); +// if (listeners == null) { return; } +// ArrayList listeners = new ArrayList(listeners.); +// +// RpcNotification notification = new RpcNotification(); +// notification.setMethod(event.method); +// JSONObject params = new JSONObject(); +// params.put("SID", sid); +// params.put("data", data); +// notification.setParams(params); +// try { +// notify(notification); +// } catch (InterruptedException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } +// +// private long getRemoteEventListener(Event event) { +// returen 0 +// } +// +// private void notify(RpcNotification notification) throws InterruptedException { +// mHandler.invoke(new RpcInvoker(notification, null, null)); +// } +//} diff --git a/src/rpc/framework/server/EventListenerInterface.java b/src/rpc/framework/server/EventListenerInterface.java new file mode 100644 index 0000000..a406631 --- /dev/null +++ b/src/rpc/framework/server/EventListenerInterface.java @@ -0,0 +1,5 @@ +//package rpc.framework.server; +// +//public interface EventListenerInterface { +// void onNotify(Event event, Object data); +//} diff --git a/src/rpc/framework/server/EventSourceInterface.java b/src/rpc/framework/server/EventSourceInterface.java new file mode 100644 index 0000000..04248cd --- /dev/null +++ b/src/rpc/framework/server/EventSourceInterface.java @@ -0,0 +1,7 @@ +//package rpc.framework.server; +// +//public interface EventSourceInterface { +// public boolean subscribe(Event event, EventListenerInterface observer); +// public boolean unsubscribe(Event event, EventListenerInterface observer); +// public boolean acceptEvent(Event event); +//} diff --git a/src/rpc/framework/server/RpcServer.java b/src/rpc/framework/server/RpcServer.java index f565614..6e4bd82 100644 --- a/src/rpc/framework/server/RpcServer.java +++ b/src/rpc/framework/server/RpcServer.java @@ -9,6 +9,7 @@ import rpc.exception.RpcException; import rpc.exception.RpcInternalError; import rpc.exception.RpcInvalidRquest; +import rpc.framework.INotificationListener; import rpc.framework.RpcInvoker; import rpc.framework.RpcServerInvokerHandler; import rpc.framework.connection.IRpcChannel; @@ -19,11 +20,11 @@ import rpc.json.message.RpcResponse; import rpc.util.RpcLog; -public class RpcServer { +public class RpcServer implements INotificationListener{ private static final String TAG = "RpcServer"; private boolean mIsRunning = false; private RpcServerInvokerHandler mHandler = null; - ServiceRegister mServiceRegister = new ServiceRegister(); + ServiceRegistry mServiceRegister = new ServiceRegistry(); ExecutorService mThreadPool = Executors.newCachedThreadPool(); class RequestProcessor implements Callable { @@ -43,7 +44,7 @@ public RpcResponse call() throws Exception { RpcLog.d(TAG, "RequestProcessor is callings"); try { if (mRequest.getMethod() == null || mRequest.getMethod().isEmpty()) { - throw new RpcInvalidRquest("method is empty in request of " + mRequest.toString()); + throw new RpcInvalidRquest("method is empty in request of " + mRequest.toString()); } return mService.execute(mRequest); @@ -59,7 +60,10 @@ public RpcResponse call() throws Exception { */ public void registerService(RpcServiceInterface service) { mServiceRegister.addService(service); - + } + + public void registerSubject(String servicename, Object subject) { + RpcSubscriber.BaseRpcSubscriber.registerSubject(servicename, subject); } @@ -68,7 +72,7 @@ public void registerService(RpcServiceInterface service) { * @param port */ public void serve(String ip, int port) { - RpcLog.i(TAG, mServiceRegister.listServices()); + while(true) { IRpcChannel channel = RpcConnector.acceptChannel(ip, port); if (channel == null) { @@ -78,19 +82,35 @@ public void serve(String ip, int port) { mIsRunning = true; mHandler = new RpcServerInvokerHandler(); mHandler.bindChannel(channel); + // TODO:: 做一些与回调相关的处理 + RpcSubscriber s = null; + try { + s = (RpcSubscriber)RpcSubscriber.BaseRpcSubscriber.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return; + } + s.onConnect(this); + mServiceRegister.removeService(s.list()); + mServiceRegister.addService(s); + RpcLog.i(TAG, mServiceRegister.listServices()); run(); + s.onDisconnect(); } } - public void onNotify(RpcNotification message) { - while (mIsRunning) { - if (message == null) { continue; } + public boolean onNotify(RpcNotification message) { + if (mIsRunning) { + if (message == null) { return false; } try { + RpcLog.i(TAG, "notify message"); mHandler.invoke(new RpcInvoker(message, null, null)); + return true; } catch (InterruptedException e) { RpcLog.e(RpcServer.TAG, "server is stopped because of exception:" + e); } } + return false; } @@ -101,7 +121,7 @@ public void run() { RpcInvoker invoker = mHandler.retrieve(); RpcRequest request = (RpcRequest)invoker.getRequest(); RpcServiceInterface service = (RpcServiceInterface)mServiceRegister.getService(request.getMethod()); - RpcLog.d(TAG, "ask request: " + request.toString()); + // RpcLog.d(TAG, "ask request: " + request.toString()); RpcResponse response = null; if (service == null) { RpcLog.e(TAG, "NO service can handle this method:" + request.getMethod()); diff --git a/src/rpc/framework/server/RpcServiceAdapter.java b/src/rpc/framework/server/RpcServiceAdapter.java index d582cde..53f2591 100644 --- a/src/rpc/framework/server/RpcServiceAdapter.java +++ b/src/rpc/framework/server/RpcServiceAdapter.java @@ -1,5 +1,6 @@ package rpc.framework.server; +import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; @@ -7,6 +8,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import javax.management.NotificationListener; + import org.json.JSONArray; import org.json.JSONObject; @@ -15,7 +18,9 @@ import rpc.exception.RpcInvalidParameters; import rpc.exception.RpcMethodNotFound; import rpc.exception.RpcPermissionDenied; -import rpc.framework.server.annotation.Rpc; +import rpc.framework.server.annotation.RpcAttachEvent; +import rpc.framework.server.annotation.RpcMethod; +import rpc.framework.server.annotation.RpcService; import rpc.json.message.RpcRequest; import rpc.json.message.RpcResponse; import rpc.util.RpcLog; @@ -27,7 +32,10 @@ public final class RpcServiceAdapter implements RpcServiceInterface { private final static String TAG = "RpcServiceAdapter"; private ConcurrentHashMap mMethodsMap = new ConcurrentHashMap(); + private ConcurrentHashMap mEventsMap = new ConcurrentHashMap(); private Object mObject; // all method share the same object + private NotificationListener mListener = null; + /**adapt target method as RpcServiceInterface like * @param object @@ -77,12 +85,20 @@ public static RpcServiceAdapter adapt(Object object, String[] methods) { public static RpcServiceAdapter adapt(Object object) { ArrayList methodsArray = new ArrayList(); for (Method m : object.getClass().getMethods()) { - if (m.getAnnotation(Rpc.class) != null) { - if (m.getAnnotation(Rpc.class).params().length != m.getParameterTypes().length) { + RpcMethod an = m.getAnnotation(RpcMethod.class); + if (an != null) { + if (an.params().length > 0 && an.params().length != m.getParameterTypes().length) { RpcLog.e(TAG, "method has an inconsistent Rpc annotation: " + m.getName()); continue; } - methodsArray.add(m); + if (!an.subject()) { + methodsArray.add(m); + } else { + RpcSubscriber.BaseRpcSubscriber.registerSubject(getMainServiceName(object) + '.' + m.getName(), object); + } + } else if (m.getAnnotation(RpcAttachEvent.class) != null) { + m.getAnnotation(RpcAttachEvent.class); + //TODO } } @@ -106,10 +122,19 @@ private static String getClassLastName(Object object) { return className; } + private static String getMainServiceName(Object object) { + RpcService an = object.getClass().getAnnotation(RpcService.class); + if (an != null && !an.name().isEmpty()) { + return an.name(); + } else { + // FIXME:: internal class name is properly? + return getClassLastName(object); + } + } + private void addService(Object serviceObject, Method method) { mObject = serviceObject; - // FIXME:: internal class name is properly? - mMethodsMap.put(getClassLastName(serviceObject) + '.' + method.getName(), method); + mMethodsMap.put(getMainServiceName(serviceObject) + '.' + method.getName(), method); } @@ -121,9 +146,10 @@ public String[] list() { @Override public RpcResponse execute(RpcRequest request) throws RpcException { - Method m = mMethodsMap.get(request.getMethod()); + String methodname = request.getMethod(); + Method m = mMethodsMap.get(methodname); if (m == null) { - throw new RpcMethodNotFound(request.getMethod()); + throw new RpcMethodNotFound(methodname); } Object[] args = null; @@ -153,7 +179,7 @@ private Object[] fillArgs(Method mMethod, JSONObject params) throws RpcException } // params是按照函数参数的 key-value键值对,由于java1.8以下,不能直接读取形参名,所以只能使用annotation - Rpc rpc = mMethod.getAnnotation(Rpc.class); + RpcMethod rpc = mMethod.getAnnotation(RpcMethod.class); if (rpc == null) { RpcLog.e(TAG, "Rpc annotation is not found for method: " + mMethod.getName()); throw new RpcInternalError("method " + mMethod.getName() + " annotate error"); @@ -168,6 +194,9 @@ private Object[] fillArgs(Method mMethod, JSONObject params) throws RpcException for (int i=0; i mServicesMap = new ConcurrentHashMap(); + private ConcurrentHashMap mListenerMap = new ConcurrentHashMap(); + + + public static RpcSubscriber BaseRpcSubscriber = new RpcSubscriber(); + + @Override + public Object clone() throws CloneNotSupportedException { + RpcSubscriber obj = (RpcSubscriber) super.clone(); + // enough, every thing except mListener canbe share. 而mListener后面总是会被重新设置 + return obj; + } + + + @Override + public String[] list() { + Set set = mServicesMap.keySet(); + return set.toArray(new String[]{}); + } + + @Override + public RpcResponse execute(RpcRequest request) throws RpcException { + String method = request.getMethod(); + if ("HelloService.listenGrowUp".equals(method)) { + return listenGrowUp(request); + } else if ("HelloService.unlistenGrowUp".equals(method)) { + return unlistenGrowUp(request); + } else if ("Hello.observeAge".equals(method)) { + return observeAge(request); + } else { + RpcLog.e(TAG, "unsupport method: " + method); + return null; + } + } + + /**注册订阅接口 + * @param subject 服务类对象 + * @param sericename 服务名,e.g. helloservice.observeAge + */ + public void registerSubject(String servicename, Object subject) { + RpcLog.d(TAG, "register " + servicename); + mServicesMap.put(servicename, subject); + } + + public String listServices() { + StringBuffer buffer = new StringBuffer(); + for (Entry entry : mServicesMap.entrySet()) { + buffer.append(entry.getValue() + " : " + entry.getKey() + "\n"); + } + return buffer.toString(); + } + + void onConnect(INotificationListener listener) { + mListener = listener; + } + + void onDisconnect() { + mListener = null; + } + + private void safeNotify(RpcNotification noti) { + if (mListener != null) { + mListener.onNotify(noti); + } + } + + RpcResponse listenGrowUp(RpcRequest request) throws RpcException { + String methodname = request.getMethod(); + + HelloService service = (HelloService) mServicesMap.get(methodname); + if (service == null) { + throw new RpcMethodNotFound(methodname); + } + + int sid = mSIDGen.getRequestId(); + Hello.AgeListener listener = new Hello.AgeListener() { + public void onChanged(int age) { + RpcNotification noti = new RpcNotification(); + JSONObject agejson = new JSONObject(); + agejson.put("age", age); + agejson.put("SID", sid); + noti.setMethod("agechanged"); + noti.setParams(agejson); + safeNotify(noti); + } + }; + JSONObject args = (JSONObject)request.getParams(); + String type = args.getString("Type"); + service.listenGrowUp(type, listener); + + mListenerMap.put(sid, listener); + + JSONObject result = new JSONObject(); + result.put("SID", sid); + return new RpcResponse(request.getId(), result, true); + } + + + RpcResponse unlistenGrowUp(RpcRequest request) throws RpcException { + String methodname = request.getMethod(); + HelloService service = (HelloService) mServicesMap.get(methodname); + if (service == null) { + throw new RpcMethodNotFound(methodname); + } + + int sid = ((JSONObject) request.getParams()).getInt("SID"); + Object listener = mListenerMap.get(sid); + JSONObject args = (JSONObject)request.getParams(); + String type = args.getString("Type"); + service.unlistenGrowUp(type, (Hello.AgeListener)listener); + return new RpcResponse(request.getId(), null, true); + } + + RpcResponse observeAge(RpcRequest request) throws RpcException { + String methodname = request.getMethod(); + + HelloRpcWrapper service = (HelloRpcWrapper) mServicesMap.get(methodname); + if (service == null) { + throw new RpcMethodNotFound(methodname); + } + + int sid = mSIDGen.getRequestId(); + Hello.AgeListener listener = new Hello.AgeListener() { + public void onChanged(int age) { + RpcNotification noti = new RpcNotification(); + JSONObject agejson = new JSONObject(); + agejson.put("age", age); + agejson.put("SID", sid); + noti.setMethod("agechanged"); + noti.setParams(agejson); + safeNotify(noti); + } + }; + JSONObject args = (JSONObject)request.getParams(); + String type = args.getString("Type"); + service.observeAge(type, listener); + + mListenerMap.put(sid, listener); + + JSONObject result = new JSONObject(); + result.put("SID", sid); + return new RpcResponse(request.getId(), result, true); + } +} diff --git a/src/rpc/framework/server/ServiceRegister.java b/src/rpc/framework/server/ServiceRegistry.java similarity index 88% rename from src/rpc/framework/server/ServiceRegister.java rename to src/rpc/framework/server/ServiceRegistry.java index 7ecf9fa..3187b24 100644 --- a/src/rpc/framework/server/ServiceRegister.java +++ b/src/rpc/framework/server/ServiceRegistry.java @@ -19,8 +19,8 @@ * @author 23683 * */ -public class ServiceRegister { - private static final String TAG="ServiceRegister"; +public class ServiceRegistry { + private static final String TAG="ServiceRegistry"; private ConcurrentHashMap mServiceMap = new ConcurrentHashMap(); @@ -53,7 +53,7 @@ public String listServices() { public void addService(String serviceName, RpcServiceInterface service) { mServiceMap.put(serviceName, service); } - + /**register all rpc method in the methods * @param service * @param methods e.g. {"add", "minus", "divide"} @@ -75,6 +75,7 @@ public void addService(RpcServiceInterface service) { } } + /**删除与服务方法method对应的rpc服务 * @param method 服务方法名 e.g. MyService.myMethod */ @@ -82,6 +83,12 @@ public void removeService(String method) { mServiceMap.remove(method); } + public void removeService(String[] methods) { + for (String m:methods) { + removeService(m); + } + } + /** * 删除所有服务 */ diff --git a/src/rpc/framework/server/annotation/RpcAttachEvent.java b/src/rpc/framework/server/annotation/RpcAttachEvent.java new file mode 100644 index 0000000..c7e078b --- /dev/null +++ b/src/rpc/framework/server/annotation/RpcAttachEvent.java @@ -0,0 +1,13 @@ +package rpc.framework.server.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 RpcAttachEvent { + String[] events() default {}; // 监听的事件类型 + Class listener(); // 回调函数 +} diff --git a/src/rpc/framework/server/annotation/RpcDetachEvent.java b/src/rpc/framework/server/annotation/RpcDetachEvent.java new file mode 100644 index 0000000..e601fdd --- /dev/null +++ b/src/rpc/framework/server/annotation/RpcDetachEvent.java @@ -0,0 +1,12 @@ +package rpc.framework.server.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 RpcDetachEvent { + String[] events() default {}; // 回调函数 +} diff --git a/src/rpc/framework/server/annotation/RpcEvent.java b/src/rpc/framework/server/annotation/RpcEvent.java new file mode 100644 index 0000000..ab1b2d0 --- /dev/null +++ b/src/rpc/framework/server/annotation/RpcEvent.java @@ -0,0 +1,15 @@ +package rpc.framework.server.annotation; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(ElementType.METHOD) +public @interface RpcEvent { + public static enum ActionType {SUBSCRIBE, UNSUBSCRIBE}; + String method() default ""; // rpc方法名,不填表示与修饰的方法同名 + String[] params() default {}; // rpc方法参数名列表 +} diff --git a/src/rpc/framework/server/annotation/RpcMethod.java b/src/rpc/framework/server/annotation/RpcMethod.java new file mode 100644 index 0000000..b7533bf --- /dev/null +++ b/src/rpc/framework/server/annotation/RpcMethod.java @@ -0,0 +1,25 @@ +/** + * + */ +package rpc.framework.server.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author sunshyran + * usage: @Rpc(method="call_abc", params=["arg1","arg2"]) + * method 服务名。 可省略,默认同定义的函数名 + * params 形参名。 不可省略。 + * subject 是否是订阅, 默认false + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RpcMethod { + public static final String[] NO_PARAMS = new String[]{}; + String method() default ""; // rpc方法名,不填表示与修饰的方法同名 + String[] params() default {}; // 成员方法的形参名 + boolean subject() default false; +} \ No newline at end of file diff --git a/src/rpc/framework/server/annotation/Rpc.java b/src/rpc/framework/server/annotation/RpcService.java similarity index 66% rename from src/rpc/framework/server/annotation/Rpc.java rename to src/rpc/framework/server/annotation/RpcService.java index 140299b..b3a9d05 100644 --- a/src/rpc/framework/server/annotation/Rpc.java +++ b/src/rpc/framework/server/annotation/RpcService.java @@ -13,9 +13,8 @@ * usage: @Rpc(params=["arg1","arg2"]) * */ -@Target({ElementType.METHOD}) +@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) -public @interface Rpc { - public static final String[] NO_PARAMS = new String[]{}; - String[] params() default {}; +public @interface RpcService { + String name() default ""; // rpc主服务名,不填表示与修饰的方法同名 } \ No newline at end of file diff --git a/src/server/json/Hello.java b/src/server/json/Hello.java index d0742aa..3ede82a 100644 --- a/src/server/json/Hello.java +++ b/src/server/json/Hello.java @@ -1,25 +1,48 @@ package server.json; -import rpc.framework.server.annotation.Rpc; +import rpc.util.RpcLog; public class Hello { - String mName = "no one"; - public Hello() { - + public interface AgeListener { + void onChanged(int age); } - @Rpc + private AgeListener mAgeListener; + String mName = "no one"; + int mAge = 0; + public String sayName() { return mName; } - @Rpc(params={"a","b"}) public int add(int a, int b) { - return a +b; + return a+b; } - @Rpc(params={"name"}) public void giveName(String name) { mName = name; } - } + + public int growUp() { + ++mAge; + if (mAgeListener!=null) { + RpcLog.i("Hello", "age is changed"); + mAgeListener.onChanged(mAge); + } + return mAge; + } + + public void observeAge(String type, AgeListener listener) { + //if (type == "growup") { + RpcLog.i("Hello", "observeAge"); + mAgeListener = listener; + //} + } + + public void unobserveAge(String type, AgeListener listener) { + //if (type == "growup") { + mAgeListener = null; + //} + } + +} diff --git a/src/server/json/HelloRpcWrapper.java b/src/server/json/HelloRpcWrapper.java new file mode 100644 index 0000000..2ccb143 --- /dev/null +++ b/src/server/json/HelloRpcWrapper.java @@ -0,0 +1,44 @@ +package server.json; + +import rpc.framework.server.annotation.RpcMethod; +import rpc.framework.server.annotation.RpcService; + +@RpcService(name="Hello") +public class HelloRpcWrapper { + private Hello mHello = null; + + public HelloRpcWrapper() { + mHello = new Hello(); + } + + @RpcMethod + public String sayName() { + return mHello.sayName(); + } + + @RpcMethod(params={"a","b"}) + public int add(int a, int b) { + return mHello.add(a, b); + } + + @RpcMethod(params={"name"}) + public void giveName(String name) { + mHello.giveName(name); + } + + @RpcMethod + public int growUp() { + return mHello.growUp(); + } + + @RpcMethod(params= {"type", "listener"}, subject=true) + public void observeAge(String type, Hello.AgeListener listener) { + mHello.observeAge(type, listener); + } + + @RpcMethod(params= {"type", "listener"}, subject=true) + public void unobserveAge(String type, Hello.AgeListener listener) { + mHello.unobserveAge(type, listener); + } + + } diff --git a/src/server/json/HelloService.java b/src/server/json/HelloService.java index 183ecae..775a0bd 100644 --- a/src/server/json/HelloService.java +++ b/src/server/json/HelloService.java @@ -10,8 +10,10 @@ public class HelloService implements RpcServiceInterface { private static final String TAG = "HelloService"; - String mName = "no one"; + private Hello mHello = null; + public HelloService() { + mHello = new Hello(); } @Override @@ -19,7 +21,10 @@ public String[] list() { return new String[] { "HelloService.add", "HelloService.sayName", - "HelloService.giveName" + "HelloService.giveName", + "HelloService.growUp", + "HelloService.listenGrowUp", + "HelloService.unlistenGrowUp" }; } @@ -34,41 +39,48 @@ public RpcResponse execute(RpcRequest request) throws RpcException { } else if ("HelloService.giveName".equals(method)) { return giveName(request); - + + } else if ("HelloService.growUp".equals(method)) { + return growUp(request); + } else { RpcLog.e(TAG, "unsupport method: " + method); return null; } } + - public String sayName() { - return mName; - } - - public int add(int a, int b) { - return a +b; - } - public void giveName(String name) { - mName = name; - } private RpcResponse sayName(RpcRequest request) { - return new RpcResponse(request.getId(), sayName(), true); + return new RpcResponse(request.getId(), mHello.sayName(), true); } private RpcResponse add(RpcRequest request) { JSONObject args = (JSONObject)request.getParams(); int a = args.getInt("a"); int b = args.getInt("b"); - return new RpcResponse(request.getId(), add(a,b), true); + return new RpcResponse(request.getId(), mHello.add(a,b), true); } private RpcResponse giveName(RpcRequest request) { JSONObject args = (JSONObject)request.getParams(); - giveName(args.getString("name")); + mHello.giveName(args.getString("name")); return new RpcResponse(request.getId(), null, true); } -} - + + private RpcResponse growUp(RpcRequest request) { + int age = mHello.growUp(); + return new RpcResponse(request.getId(), age, true); + } + + public void listenGrowUp(String type, Hello.AgeListener listener) { + mHello.observeAge(type, listener); + } + + public void unlistenGrowUp(String type, Hello.AgeListener listener) { + mHello.unobserveAge(type, listener); + } + +} \ No newline at end of file diff --git a/src/server/json/Main.java b/src/server/json/Main.java index 844ab24..d604751 100644 --- a/src/server/json/Main.java +++ b/src/server/json/Main.java @@ -2,7 +2,6 @@ import rpc.framework.server.RpcServer; import rpc.framework.server.RpcServiceAdapter; -import rpc.framework.server.RpcServiceInterface; public class Main { @@ -13,14 +12,17 @@ public Main() { public static void main(String[] args) { RpcServer server = new RpcServer(); // 继承自RpcServiceInterface的服务 - HelloService helloservice = new HelloService(); - server.registerService(helloservice); +// HelloService helloservice = new HelloService(); +// server.registerService(helloservice); +// server.registerSubject("HelloService.listenGrowUp", helloservice); +// server.registerSubject("HelloService.unlistenGrowUp", helloservice); // 普通类,没有继承自RpcServiceInterface。 使用 - Hello hello = new Hello(); + HelloRpcWrapper hello = new HelloRpcWrapper(); server.registerService(RpcServiceAdapter.adapt(hello)); - - server.serve(null, 12345); + //server.registerSubject("Hello.observeAge", hello); + //server.registerSubject("Hello.unobserveAge", hello); + server.serve(null, 12346); } } diff --git a/src/server/json/android/ContentProviderService.java b/src/server/json/android/ContentProviderService.java new file mode 100644 index 0000000..14f615e --- /dev/null +++ b/src/server/json/android/ContentProviderService.java @@ -0,0 +1,44 @@ +package server.json.android; + +import org.json.JSONArray; +import org.json.JSONObject; + +import rpc.framework.server.annotation.RpcMethod; +import rpc.framework.server.annotation.RpcService; + +@RpcService(name="ContentProvider") +public class ContentProviderService { + + @RpcMethod(params={"uri", "projection", "selection", "selectionArgs", "sortOrder"}) + public JSONObject query(String uri, JSONArray projection, + String selection, JSONArray selectionArgs, String sortOrder) { + // convert uri to Uri() + // call + JSONObject result = new JSONObject("{'token':1}"); + return result; + } + + @RpcMethod(params= {"uri", "values"}) + public String insert(String uri, JSONObject values) { + // jsonobject ot contenttypes + + return uri; + } + + @RpcMethod(params= {"uri", "selection", "selectionArgs"}) + public int delete(String uri, String selection, JSONArray selectionArgs) { + return 0; + } + + @RpcMethod(params= {"uri", "values", "selection", "selectionArgs"}) + public int update(String uri, JSONObject values, String selection, + JSONArray selectionArgs) { + + return 0; + } + + @RpcMethod(params= {"method", "arg", "extras"}) + public JSONObject call(String method, String arg, JSONObject extras) { + return null; + } +} diff --git a/src/server/json/android/ContextService.java b/src/server/json/android/ContextService.java new file mode 100644 index 0000000..bd8cde4 --- /dev/null +++ b/src/server/json/android/ContextService.java @@ -0,0 +1,64 @@ +package server.json.android; + +import org.json.JSONObject; + +import rpc.framework.server.annotation.RpcMethod; +import rpc.framework.server.annotation.RpcService; + +// 最终应该使用android中的BroadcastReceiver代替 +interface BroadcastReceiver { + public void onReceive(JSONObject intent); +} + +@RpcService(name="Context") +public class ContextService { + + @RpcMethod(params= {"intent"}) + public void startActivity(JSONObject intent) { + + } + + @RpcMethod(params= {"intent", "permission"}) + public void sendBroadcast(JSONObject intent, String permission) { + + + } + + @RpcMethod(params= {"intent", "permission"}) + public void sendOrderedBroadcast(JSONObject intent, String permission) { + + + } + + @RpcMethod(params= {"intent"}) + public void sendStickyBroadcast(JSONObject intent) { + + } + + @RpcMethod(params= {"intent"}) + public void removeStickyBroadcast(JSONObject intent) { + + } + + @RpcMethod(params= {"receiver", "filter", "permission"}, subject=true) + public JSONObject registerReceiver(BroadcastReceiver receiver, + JSONObject filter, String permission) { + return null; + } + + @RpcMethod(params= {"receiver"}, subject=true) + public void unregisterReceiver(BroadcastReceiver receiver) { + + } + + @RpcMethod(params= {"intent"}) + public JSONObject startService(JSONObject intent) { + return null; + } + + @RpcMethod(params= {"intent"}) + public boolean stopService(JSONObject intent) { + return false; + } + +} diff --git a/src/server/json/android/CursorService.java b/src/server/json/android/CursorService.java new file mode 100644 index 0000000..fe79f0f --- /dev/null +++ b/src/server/json/android/CursorService.java @@ -0,0 +1,26 @@ +package server.json.android; + +import org.json.JSONArray; + +import rpc.framework.server.annotation.RpcMethod; +import rpc.framework.server.annotation.RpcService; + +@RpcService(name="Cursor") +public class CursorService { + + @RpcMethod(params= {"size"}) + public JSONArray fetch(int size) { + return null; + } + + @RpcMethod + public void close() { + + } + + @RpcMethod + public int getCount() { + return 0; + } + +} diff --git a/src/server/json/android/Main.java b/src/server/json/android/Main.java new file mode 100644 index 0000000..29222d4 --- /dev/null +++ b/src/server/json/android/Main.java @@ -0,0 +1,28 @@ +package server.json.android; + +import org.json.JSONObject; + +import rpc.framework.server.RpcServer; +import rpc.framework.server.RpcServiceAdapter; +import rpc.util.RpcLog; + +public class Main { + + public Main() { + // TODO Auto-generated constructor stub + } + + public static void main(String[] args) { + RpcServer server = new RpcServer(); + // 普通类,没有继承自RpcServiceInterface。 使用 + ContentProviderService provider = new ContentProviderService(); + CursorService cursor = new CursorService(); + ContextService context = new ContextService(); + + server.registerService(RpcServiceAdapter.adapt(provider)); + server.registerService(RpcServiceAdapter.adapt(cursor)); + server.registerService(RpcServiceAdapter.adapt(context)); + server.serve(null, 12346); + } + +} diff --git a/test/rpc/framework/server/RpcServiceAdapterTest.java b/test/rpc/framework/server/RpcServiceAdapterTest.java index cf3b635..4875e66 100644 --- a/test/rpc/framework/server/RpcServiceAdapterTest.java +++ b/test/rpc/framework/server/RpcServiceAdapterTest.java @@ -12,18 +12,18 @@ import org.junit.Test; import rpc.exception.RpcException; -import rpc.framework.server.annotation.Rpc; +import rpc.framework.server.annotation.RpcMethod; import rpc.json.message.RpcRequest; import rpc.json.message.RpcResponse; class RpcServiceAdapterTestHelper { - @Rpc(params={"x"}) + @RpcMethod(params={"x"}) public int s1(int x) { return x; } - @Rpc + @RpcMethod public int s2() { return 0; } diff --git a/test/rpc/framework/server/ServiceRegisterTest.java b/test/rpc/framework/server/ServiceRegisterTest.java index 29b1201..00f6ac6 100644 --- a/test/rpc/framework/server/ServiceRegisterTest.java +++ b/test/rpc/framework/server/ServiceRegisterTest.java @@ -54,14 +54,14 @@ public void tearDown() throws Exception { @Test public final void testAddServiceStringRpcServiceInterface() { - ServiceRegister mSR = new ServiceRegister(); + ServiceRegistry mSR = new ServiceRegistry(); mSR.addService("ServiceTest.s1", new ServiceTest()); assertTrue(mSR.getService("ServiceTest.s1") != null); } @Test public final void testAddServiceRpcServiceInterfaceStringArray() { - ServiceRegister mSR = new ServiceRegister(); + ServiceRegistry mSR = new ServiceRegistry(); mSR.addService(new ServiceTest(), new String[] {"s1", "s2"}); System.out.println(mSR.listServices()); assertTrue(mSR.getService("ServiceTest.s1") != null); @@ -70,7 +70,7 @@ public final void testAddServiceRpcServiceInterfaceStringArray() { @Test public final void testAddServiceRpcServiceInterface() { - ServiceRegister mSR = new ServiceRegister(); + ServiceRegistry mSR = new ServiceRegistry(); mSR.addService(new ServiceTest()); System.out.println(mSR.listServices()); assertTrue(mSR.getService("ServiceTest.s1") != null); @@ -79,7 +79,7 @@ public final void testAddServiceRpcServiceInterface() { @Test public final void testRemoveService() { - ServiceRegister mSR = new ServiceRegister(); + ServiceRegistry mSR = new ServiceRegistry(); mSR.addService(new ServiceTest()); System.out.println(mSR.listServices()); assertTrue(mSR.getService("ServiceTest.s1") != null);