Introduced MethodHandle based invokers for Notification and RPCs
[mdsal.git] / yang / yang-binding / src / main / java / org / opendaylight / yangtools / yang / binding / util / RpcServiceInvoker.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.binding.util;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.cache.CacheBuilder;
12 import com.google.common.cache.CacheLoader;
13 import com.google.common.cache.LoadingCache;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.ImmutableMap.Builder;
16 import java.lang.reflect.Method;
17 import java.util.Map;
18 import java.util.concurrent.Future;
19 import javax.annotation.Nonnull;
20 import javax.annotation.Nullable;
21 import org.opendaylight.yangtools.yang.binding.BindingMapping;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.RpcService;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.common.RpcResult;
26
27 /**
28  * Provides single method invocation of RPCs on supplied instance.
29  *
30  * Rpc Service invoker provides common invocation interface for any subtype of {@link RpcService}.
31  * via {@link #invokeRpc(RpcService, QName, DataObject)} method.
32  *
33  *
34  *
35  */
36 public final class RpcServiceInvoker {
37
38     private static final LoadingCache<Class<? extends RpcService>, RpcServiceInvoker> INVOKERS = CacheBuilder.newBuilder()
39             .weakKeys()
40             .build(new CacheLoader<Class<? extends RpcService>, RpcServiceInvoker>() {
41
42                 @Override
43                 public RpcServiceInvoker load(Class<? extends RpcService> key) throws Exception {
44                     return createInvoker(key);
45                 }
46
47             });
48
49     private final Map<String, RpcMethodInvoker> methodInvokers;
50
51     private RpcServiceInvoker(Map<String, RpcMethodInvoker> methodInvokers) {
52         this.methodInvokers  = Preconditions.checkNotNull(methodInvokers);
53     }
54
55     /**
56      *
57      * Creates RPCServiceInvoker for specified RpcService type
58      *
59      * @param type RpcService interface, which was generated from model.
60      * @return Cached instance of {@link RpcServiceInvoker} for supplied RPC type.
61      *
62      */
63     public static RpcServiceInvoker from(Class<? extends RpcService> type) {
64         Preconditions.checkArgument(type.isInterface());
65         Preconditions.checkArgument(BindingReflections.isBindingClass(type));
66         return INVOKERS.getUnchecked(type);
67     }
68
69     /**
70      * Invokes supplied RPC on provided implementation of RPC Service.
71      *
72      * @param impl Imlementation on which RPC should be invoked.
73      * @param rpcName Name of RPC to be invoked.
74      * @param input Input data for RPC.
75      * @return Future which will complete once rpc procesing is finished.
76      */
77     public Future<RpcResult<?>> invokeRpc(@Nonnull RpcService impl, @Nonnull QName rpcName,@Nullable DataObject input ) {
78         Preconditions.checkNotNull(impl, "implemetation must be supplied");
79         return invoke(impl,BindingMapping.getMethodName(rpcName),input);
80     }
81
82     private static RpcServiceInvoker createInvoker(Class<? extends RpcService> key) {
83         return new RpcServiceInvoker(createInvokerMap(key));
84     }
85
86     private static Map<String, RpcMethodInvoker> createInvokerMap(Class<? extends RpcService> key) {
87         Builder<String, RpcMethodInvoker> ret = ImmutableMap.<String, RpcMethodInvoker>builder();
88         for(Method method : key.getMethods()) {
89             if(BindingReflections.isRpcMethod(method)) {
90                 ret.put(method.getName(), RpcMethodInvoker.from(method));
91             }
92
93         }
94         return ret.build();
95     }
96
97     private Future<RpcResult<?>> invoke(RpcService impl, String methodName, DataObject input) {
98         RpcMethodInvoker invoker = methodInvokers.get(methodName);
99         Preconditions.checkArgument(invoker != null,"Supplied rpc is not valid for implementation %s",impl);
100         return invoker.invokeOn(impl, input);
101     }
102 }