BUG-1092: adjust to YangInstanceIdentifier
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / impl / connect / dom / DomToBindingRpcForwarder.java
1 package org.opendaylight.controller.sal.binding.impl.connect.dom;
2
3 import static com.google.common.base.Preconditions.checkArgument;
4 import static com.google.common.base.Preconditions.checkState;
5
6 import java.lang.ref.WeakReference;
7 import java.lang.reflect.InvocationHandler;
8 import java.lang.reflect.Method;
9 import java.lang.reflect.Proxy;
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.Set;
13 import java.util.WeakHashMap;
14 import java.util.concurrent.Callable;
15
16 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
17 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
18 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
19 import org.opendaylight.controller.sal.core.api.Broker;
20 import org.opendaylight.controller.sal.core.api.RpcImplementation;
21 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
22 import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
23 import org.opendaylight.yangtools.concepts.ObjectRegistration;
24 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
25 import org.opendaylight.yangtools.yang.binding.BindingMapping;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
28 import org.opendaylight.yangtools.yang.binding.RpcService;
29 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
30 import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
31 import org.opendaylight.yangtools.yang.common.QName;
32 import org.opendaylight.yangtools.yang.common.RpcResult;
33 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
34 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.google.common.base.Function;
39 import com.google.common.collect.FluentIterable;
40 import com.google.common.collect.ImmutableSet;
41 import com.google.common.util.concurrent.Futures;
42 import com.google.common.util.concurrent.ListenableFuture;
43
44 class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
45
46     private final Logger LOG = LoggerFactory.getLogger(DomToBindingRpcForwarder.class);
47
48     private final Set<QName> supportedRpcs;
49     private final WeakReference<Class<? extends RpcService>> rpcServiceType;
50     private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
51     private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
52     private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
53     private final RpcService proxy;
54     private ObjectRegistration<?> forwarderRegistration;
55     private boolean registrationInProgress = false;
56
57     private final RpcProvisionRegistry biRpcRegistry;
58     private final RpcProviderRegistry baRpcRegistry;
59     private final RpcProviderRegistryImpl baRpcRegistryImpl;
60
61     private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toDOMInstanceIdentifier;
62
63     private final static Method EQUALS_METHOD;
64
65     static {
66         try {
67             EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
68         } catch (Exception e) {
69             throw new RuntimeException(e);
70         }
71     }
72
73     public DomToBindingRpcForwarder(final Class<? extends RpcService> service, final BindingIndependentMappingService mappingService,
74         final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry, final RpcProviderRegistryImpl registryImpl) {
75         this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
76         this.supportedRpcs = mappingService.getRpcQNamesFor(service);
77
78         toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier>() {
79
80             @Override
81             public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier apply(final InstanceIdentifier<?> input) {
82                 return mappingService.toDataDom(input);
83             }
84         };
85
86         this.biRpcRegistry = biRpcRegistry;
87         this.baRpcRegistry = baRpcRegistry;
88         this.baRpcRegistryImpl = registryImpl;
89
90         Class<?> cls = rpcServiceType.get();
91         ClassLoader clsLoader = cls.getClassLoader();
92         proxy =(RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
93         createStrategies(mappingService);
94     }
95
96     /**
97      * Constructor for Routed RPC Forwareder.
98      *
99      * @param service
100      * @param context
101      * @param registryImpl
102      */
103     public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
104         final Class<? extends BaseIdentity> context, final BindingIndependentMappingService mappingService,
105         final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry, final RpcProviderRegistryImpl registryImpl) {
106         this(service, mappingService, biRpcRegistry, baRpcRegistry,registryImpl);
107
108         final ImmutableSet.Builder<Broker.RoutedRpcRegistration> registrationsBuilder = ImmutableSet.builder();
109         try {
110             for (QName rpc : supportedRpcs) {
111                 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
112             }
113             createDefaultDomForwarder();
114         } catch (Exception e) {
115             LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
116         }
117         registrations = registrationsBuilder.build();
118     }
119
120
121
122     private void createStrategies(final BindingIndependentMappingService mappingService) {
123         try {
124             for (QName rpc : supportedRpcs) {
125                 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, rpcServiceType.get(), mappingService);
126                 strategiesByMethod.put(strategy.targetMethod, strategy);
127                 strategiesByQName.put(rpc, strategy);
128             }
129         } catch (Exception e) {
130             LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
131         }
132
133     }
134
135     /**
136      * Registers RPC Forwarder to DOM Broker,
137      * this means Binding Aware Broker has implementation of RPC
138      * which is registered to it.
139      *
140      * If RPC Forwarder was previously registered to DOM Broker
141      * or to Bidning Broker this method is noop to prevent
142      * creating forwarding loop.
143      *
144      */
145     public void registerToDOMBroker() {
146         if(!registrationInProgress && forwarderRegistration == null) {
147             registrationInProgress = true;
148             CompositeObjectRegistration.CompositeObjectRegistrationBuilder<DomToBindingRpcForwarder> builder = CompositeObjectRegistration.builderFor(this);
149             try {
150                 for (QName rpc : supportedRpcs) {
151                     builder.add(biRpcRegistry.addRpcImplementation(rpc, this));
152                 }
153             } catch (Exception e) {
154                 LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
155             }
156             this.forwarderRegistration = builder.toInstance();
157             registrationInProgress = false;
158         }
159     }
160
161
162     public void registerPaths(final Class<? extends BaseIdentity> context,
163         final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
164         QName ctx = BindingReflections.findQName(context);
165         for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier path : FluentIterable.from(set).transform(
166             toDOMInstanceIdentifier)) {
167             for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
168                 reg.registerPath(ctx, path);
169             }
170         }
171     }
172
173     @Override
174     public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
175         if (EQUALS_METHOD.equals(method)) {
176             return false;
177         }
178         RpcInvocationStrategy strategy = strategiesByMethod.get(method);
179         checkState(strategy != null);
180         checkArgument(args.length <= 2);
181         if (args.length == 1) {
182             checkArgument(args[0] instanceof DataObject);
183             return strategy.forwardToDomBroker((DataObject) args[0]);
184         }
185         return strategy.forwardToDomBroker(null);
186     }
187
188     public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
189         final Set<InstanceIdentifier<?>> set) {
190         QName ctx = BindingReflections.findQName(context);
191         for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier path : FluentIterable.from(set).transform(
192             toDOMInstanceIdentifier)) {
193             for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
194                 reg.unregisterPath(ctx, path);
195             }
196         }
197     }
198
199     @Override
200     public Set<QName> getSupportedRpcs() {
201         return supportedRpcs;
202     }
203
204     @SuppressWarnings({ "unchecked", "rawtypes" })
205     public void createDefaultDomForwarder() {
206         if (baRpcRegistryImpl != null) {
207             Class<?> cls = rpcServiceType.get();
208             ClassLoader clsLoader = cls.getClassLoader();
209             RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
210
211             RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
212             rpcRouter.registerDefaultService(proxy);
213         }
214     }
215
216     @Override
217     public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
218         checkArgument(rpc != null);
219         checkArgument(domInput != null);
220
221         Class<? extends RpcService> rpcType = rpcServiceType.get();
222         checkState(rpcType != null);
223         RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
224         checkState(rpcService != null);
225         CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
226
227         try {
228             return Futures.immediateFuture(resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput));
229         } catch (Exception e) {
230             return Futures.immediateFailedFuture(e);
231         }
232     }
233
234     private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc) {
235         return strategiesByQName.get(rpc);
236     }
237
238     private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
239         final Class<? extends RpcService> rpcType, final BindingIndependentMappingService mappingService) throws Exception {
240         return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
241             @Override
242             public RpcInvocationStrategy call() throws Exception {
243                 String methodName = BindingMapping.getMethodName(rpc);
244                 Method targetMethod = null;
245                 for (Method possibleMethod : rpcType.getMethods()) {
246                     if (possibleMethod.getName().equals(methodName)
247                         && BindingReflections.isRpcMethod(possibleMethod)) {
248                         targetMethod = possibleMethod;
249                         break;
250                     }
251                 }
252                 checkState(targetMethod != null, "Rpc method not found");
253                 return new RpcInvocationStrategy(rpc, targetMethod, mappingService, biRpcRegistry);
254             }
255
256         });
257     }
258
259     /**
260      * Registers RPC Forwarder to Binding Broker,
261      * this means DOM Broekr has implementation of RPC
262      * which is registered to it.
263      *
264      * If RPC Forwarder was previously registered to DOM Broker
265      * or to Bidning Broker this method is noop to prevent
266      * creating forwarding loop.
267      *
268      */
269     public void registerToBindingBroker() {
270         if(!registrationInProgress && forwarderRegistration == null) {
271             try {
272                 registrationInProgress = true;
273                 this.forwarderRegistration = baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy);
274             } catch (Exception e) {
275                 LOG.error("Unable to forward RPCs for {}",rpcServiceType.get(),e);
276             } finally {
277                 registrationInProgress = false;
278             }
279         }
280     }
281 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.