19f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/* 2f04335f899f2cce69f843692a3cb9cec229683c2tturney * Copyright (C) 2017 The Android Open Source Project 39f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * 4f04335f899f2cce69f843692a3cb9cec229683c2tturney * Licensed under the Apache License, Version 2.0 (the "License"); 5f04335f899f2cce69f843692a3cb9cec229683c2tturney * you may not use this file except in compliance with the License. 6f04335f899f2cce69f843692a3cb9cec229683c2tturney * You may obtain a copy of the License at 79f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * 8f04335f899f2cce69f843692a3cb9cec229683c2tturney * http://www.apache.org/licenses/LICENSE-2.0 99f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * 109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Unless required by applicable law or agreed to in writing, software 11f04335f899f2cce69f843692a3cb9cec229683c2tturney * distributed under the License is distributed on an "AS IS" BASIS, 12f04335f899f2cce69f843692a3cb9cec229683c2tturney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f04335f899f2cce69f843692a3cb9cec229683c2tturney * See the License for the specific language governing permissions and 14f04335f899f2cce69f843692a3cb9cec229683c2tturney * limitations under the License. 159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */ 169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipackage com.googlecode.android_scripting.jsonrpc; 189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.lang.reflect.Constructor; 209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.lang.reflect.Method; 219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Collection; 229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.HashMap; 239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Map; 249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.facade.FacadeManager; 269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.Log; 279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.rpc.MethodDescriptor; 289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipublic abstract class RpcReceiverManager { 309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li private final Map<Class<? extends RpcReceiver>, RpcReceiver> mReceivers; 329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li /** 349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * A map of strings to known RPCs. 359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */ 369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li private final Map<String, MethodDescriptor> mKnownRpcs = new HashMap<String, MethodDescriptor>(); 379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li public RpcReceiverManager(Collection<Class<? extends RpcReceiver>> classList) { 399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li mReceivers = new HashMap<Class<? extends RpcReceiver>, RpcReceiver>(); 409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li for (Class<? extends RpcReceiver> receiverClass : classList) { 419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li mReceivers.put(receiverClass, null); 429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li Collection<MethodDescriptor> methodList = MethodDescriptor.collectFrom(receiverClass); 439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li for (MethodDescriptor m : methodList) { 449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li if (mKnownRpcs.containsKey(m.getName())) { 459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li // We already know an RPC of the same name. We don't catch this anywhere because 469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li // this is a programming error. 479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li throw new RuntimeException("An RPC with the name " + m.getName() 489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li + " is already known."); 499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li mKnownRpcs.put(m.getName(), m); 519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li public Collection<Class<? extends RpcReceiver>> getRpcReceiverClasses() { 569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li return mReceivers.keySet(); 579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li private RpcReceiver get(Class<? extends RpcReceiver> clazz) { 609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li RpcReceiver object = mReceivers.get(clazz); 619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li if (object != null) { 629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li return object; 639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li Constructor<? extends RpcReceiver> constructor; 669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li try { 679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li constructor = clazz.getConstructor(FacadeManager.class); 689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li object = constructor.newInstance(this); 699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li mReceivers.put(clazz, object); 709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } catch (Exception e) { 719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li Log.e(e); 729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li return object; 759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li public <T extends RpcReceiver> T getReceiver(Class<T> clazz) { 789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li RpcReceiver receiver = get(clazz); 799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li return clazz.cast(receiver); 809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li public MethodDescriptor getMethodDescriptor(String methodName) { 839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li return mKnownRpcs.get(methodName); 849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li public Object invoke(Class<? extends RpcReceiver> clazz, Method method, Object[] args) 879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li throws Exception { 889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li RpcReceiver object = get(clazz); 899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li return method.invoke(object, args); 909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li 929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li public void shutdown() { 939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li for (RpcReceiver receiver : mReceivers.values()) { 949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li try { 959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li if (receiver != null) { 969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li receiver.shutdown(); 979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } catch (Exception e) { 999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li Log.e("Failed to shut down an RpcReceiver", e); 1009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 1019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 1029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li } 1039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li} 104