1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting.jsonrpc;
18 
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Method;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Map;
24 
25 import com.googlecode.android_scripting.facade.FacadeManager;
26 import com.googlecode.android_scripting.Log;
27 import com.googlecode.android_scripting.rpc.MethodDescriptor;
28 
29 public abstract class RpcReceiverManager {
30 
31     private final Map<Class<? extends RpcReceiver>, RpcReceiver> mReceivers;
32 
33     /**
34      * A map of strings to known RPCs.
35      */
36     private final Map<String, MethodDescriptor> mKnownRpcs = new HashMap<String, MethodDescriptor>();
37 
RpcReceiverManager(Collection<Class<? extends RpcReceiver>> classList)38     public RpcReceiverManager(Collection<Class<? extends RpcReceiver>> classList) {
39         mReceivers = new HashMap<Class<? extends RpcReceiver>, RpcReceiver>();
40         for (Class<? extends RpcReceiver> receiverClass : classList) {
41             mReceivers.put(receiverClass, null);
42             Collection<MethodDescriptor> methodList = MethodDescriptor.collectFrom(receiverClass);
43             for (MethodDescriptor m : methodList) {
44                 if (mKnownRpcs.containsKey(m.getName())) {
45                     // We already know an RPC of the same name. We don't catch this anywhere because
46                     // this is a programming error.
47                     throw new RuntimeException("An RPC with the name " + m.getName()
48                             + " is already known.");
49                 }
50                 mKnownRpcs.put(m.getName(), m);
51             }
52         }
53     }
54 
getRpcReceiverClasses()55     public Collection<Class<? extends RpcReceiver>> getRpcReceiverClasses() {
56         return mReceivers.keySet();
57     }
58 
get(Class<? extends RpcReceiver> clazz)59     private RpcReceiver get(Class<? extends RpcReceiver> clazz) {
60         RpcReceiver object = mReceivers.get(clazz);
61         if (object != null) {
62             return object;
63         }
64 
65         Constructor<? extends RpcReceiver> constructor;
66         try {
67             constructor = clazz.getConstructor(FacadeManager.class);
68             object = constructor.newInstance(this);
69             mReceivers.put(clazz, object);
70         } catch (Exception e) {
71             Log.e(e);
72         }
73 
74         return object;
75     }
76 
getReceiver(Class<T> clazz)77     public <T extends RpcReceiver> T getReceiver(Class<T> clazz) {
78         RpcReceiver receiver = get(clazz);
79         return clazz.cast(receiver);
80     }
81 
getMethodDescriptor(String methodName)82     public MethodDescriptor getMethodDescriptor(String methodName) {
83         return mKnownRpcs.get(methodName);
84     }
85 
invoke(Class<? extends RpcReceiver> clazz, Method method, Object[] args)86     public Object invoke(Class<? extends RpcReceiver> clazz, Method method, Object[] args)
87             throws Exception {
88         RpcReceiver object = get(clazz);
89         return method.invoke(object, args);
90     }
91 
shutdown()92     public void shutdown() {
93         for (RpcReceiver receiver : mReceivers.values()) {
94             try {
95                 if (receiver != null) {
96                     receiver.shutdown();
97                 }
98             } catch (Exception e) {
99                 Log.e("Failed to shut down an RpcReceiver", e);
100             }
101         }
102     }
103 }
104