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