Merge "Fixed testool performance bottleneck due to testtool using NetconfMonitoring...
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / impl / BindingDOMRpcServiceAdapter.java
1 /*
2  * Copyright (c) 2015 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.controller.md.sal.binding.impl;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Preconditions;
12 import com.google.common.cache.CacheBuilder;
13 import com.google.common.cache.CacheLoader;
14 import com.google.common.cache.LoadingCache;
15 import com.google.common.collect.ClassToInstanceMap;
16 import com.google.common.collect.ImmutableMap;
17 import com.google.common.collect.ImmutableSet;
18 import com.google.common.util.concurrent.CheckedFuture;
19 import com.google.common.util.concurrent.Futures;
20 import com.google.common.util.concurrent.ListenableFuture;
21 import java.lang.reflect.Method;
22 import java.util.Set;
23 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMAdapterBuilder.Factory;
24 import org.opendaylight.controller.md.sal.binding.impl.RpcServiceAdapter.InvocationDelegate;
25 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
26 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
27 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
28 import org.opendaylight.controller.md.sal.dom.api.DOMService;
29 import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
30 import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
31 import org.opendaylight.yangtools.yang.binding.DataObject;
32 import org.opendaylight.yangtools.yang.binding.RpcService;
33 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
34 import org.opendaylight.yangtools.yang.common.QName;
35 import org.opendaylight.yangtools.yang.common.RpcResult;
36 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
37 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
39 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
40
41 public class BindingDOMRpcServiceAdapter implements RpcConsumerRegistry, InvocationDelegate {
42
43     protected static final Factory<RpcConsumerRegistry> BUILDER_FACTORY = new Factory<RpcConsumerRegistry>() {
44
45         @Override
46         public BindingDOMAdapterBuilder<RpcConsumerRegistry> newBuilder() {
47             return new Builder();
48         }
49
50     };
51
52     private final LoadingCache<Class<? extends RpcService>, RpcServiceAdapter> proxies = CacheBuilder.newBuilder()
53             .weakKeys()
54             .build(new CacheLoader<Class<? extends RpcService>, RpcServiceAdapter>() {
55
56                 @Override
57                 public RpcServiceAdapter load(final Class<? extends RpcService> key) throws Exception {
58                     return createProxy(key);
59                 }
60
61             });
62
63     private final DOMRpcService domService;
64     private final BindingToNormalizedNodeCodec codec;
65
66     public BindingDOMRpcServiceAdapter(final DOMRpcService domService, final BindingToNormalizedNodeCodec codec) {
67         super();
68         this.domService = domService;
69         this.codec = codec;
70     }
71
72     @Override
73     public <T extends RpcService> T getRpcService(final Class<T> rpcService) {
74         Preconditions.checkArgument(rpcService != null, "Rpc Service needs to be specied.");
75         @SuppressWarnings("unchecked")
76         final
77         T proxy = (T) proxies.getUnchecked(rpcService).getProxy();
78         return proxy;
79     }
80
81     @Override
82     public ListenableFuture<RpcResult<?>> invoke(final SchemaPath rpc, final DataObject input) {
83         final CheckedFuture<DOMRpcResult, DOMRpcException> domFuture = domService.invokeRpc(rpc, serialize(rpc,input));
84         return transformFuture(rpc,domFuture,codec.getCodecFactory());
85     }
86
87     private RpcServiceAdapter createProxy(final Class<? extends RpcService> key) {
88         Preconditions.checkArgument(BindingReflections.isBindingClass(key));
89         Preconditions.checkArgument(key.isInterface(), "Supplied RPC service type must be interface.");
90         final ImmutableMap<Method, SchemaPath> rpcNames = codec.getRpcMethodToSchemaPath(key);
91         return new RpcServiceAdapter(key, rpcNames, this);
92     }
93
94     private NormalizedNode<?, ?> serialize(final SchemaPath rpc,final DataObject input) {
95         if(input == null) {
96             return null;
97         }
98         final QName rpcInputIdentifier = QName.create(rpc.getLastComponent(),"input");
99         return new LazySerializedContainerNode(rpcInputIdentifier, input, codec.getCodecFactory());
100     }
101
102     private static ListenableFuture<RpcResult<?>> transformFuture(final SchemaPath rpc,final ListenableFuture<DOMRpcResult> domFuture, final BindingNormalizedNodeCodecRegistry codec) {
103         return Futures.transform(domFuture, new Function<DOMRpcResult, RpcResult<?>>() {
104             @Override
105             public RpcResult<?> apply(final DOMRpcResult input) {
106                 if(input instanceof LazySerializedDOMRpcResult) {
107                     return ((LazySerializedDOMRpcResult) input).bidningRpcResult();
108                 }
109                 final NormalizedNode<?, ?> domData = input.getResult();
110                 final DataObject bindingResult;
111                 if(domData != null) {
112                     final SchemaPath rpcOutput = rpc.createChild(QName.create(rpc.getLastComponent(),"output"));
113                     bindingResult = codec.fromNormalizedNodeRpcData(rpcOutput, (ContainerNode) domData);
114                 } else {
115                     bindingResult = null;
116                 }
117                 return RpcResult.class.cast(RpcResultBuilder.success(bindingResult).build());
118             }
119         });
120     }
121
122     private static final class Builder extends BindingDOMAdapterBuilder<RpcConsumerRegistry> {
123
124         @Override
125         protected RpcConsumerRegistry createInstance(final BindingToNormalizedNodeCodec codec,
126                 final ClassToInstanceMap<DOMService> delegates) {
127             final DOMRpcService domRpc  = delegates.getInstance(DOMRpcService.class);
128             return new BindingDOMRpcServiceAdapter(domRpc  , codec);
129         }
130
131         @Override
132         public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
133             return ImmutableSet.of(DOMRpcService.class);
134         }
135
136     }
137
138 }