0a769921d80410742cb22b4ad7ee8cc0e9920f0a
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / impl / connect / dom / BindingIndependentConnector.java
1 package org.opendaylight.controller.sal.binding.impl.connect.dom;
2
3 import java.lang.ref.WeakReference;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.ParameterizedType;
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.Set;
14 import java.util.WeakHashMap;
15 import java.util.concurrent.Callable;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20
21
22 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
23 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
24 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
25 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
27 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
28 import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
29 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
30 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
31 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
32 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
33 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
34 import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier;
35 import org.opendaylight.controller.sal.binding.spi.RpcRouter;
36 import org.opendaylight.controller.sal.common.util.Rpcs;
37 import org.opendaylight.controller.sal.core.api.Provider;
38 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
39 import org.opendaylight.controller.sal.core.api.RpcImplementation;
40 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
41 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
42 import org.opendaylight.yangtools.concepts.ListenerRegistration;
43 import org.opendaylight.yangtools.concepts.Registration;
44 import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
45 import org.opendaylight.yangtools.yang.binding.Augmentable;
46 import org.opendaylight.yangtools.yang.binding.Augmentation;
47 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
48 import org.opendaylight.yangtools.yang.binding.BindingMapping;
49 import org.opendaylight.yangtools.yang.binding.DataContainer;
50 import org.opendaylight.yangtools.yang.binding.DataObject;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.opendaylight.yangtools.yang.binding.RpcInput;
53 import org.opendaylight.yangtools.yang.binding.RpcService;
54 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
55 import org.opendaylight.yangtools.yang.common.QName;
56 import org.opendaylight.yangtools.yang.common.RpcError;
57 import org.opendaylight.yangtools.yang.common.RpcResult;
58 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 import com.google.common.base.Function;
63 import com.google.common.base.Optional;
64 import com.google.common.collect.FluentIterable;
65 import com.google.common.collect.ImmutableSet;
66
67 import static com.google.common.base.Preconditions.*;
68 import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*;
69
70 public class BindingIndependentConnector implements //
71         RuntimeDataProvider, //
72         Provider, //
73         AutoCloseable {
74
75     private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
76
77     private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
78
79     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
80             .builder().toInstance();
81
82     private BindingIndependentMappingService mappingService;
83
84     private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
85
86     private DataProviderService baDataService;
87
88     private ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
89     private ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
90
91     private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
92     private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
93
94     private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
95
96     private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
97
98     private RpcProvisionRegistry biRpcRegistry;
99     private RpcProviderRegistryImpl baRpcRegistry;
100
101     private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
102     // private ListenerRegistration<BindingToDomRpcForwardingManager>
103     // bindingToDomRpcManager;
104
105     private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
106
107         @Override
108         public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
109             return mappingService.toDataDom(input);
110         }
111
112     };
113
114     @Override
115     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
116         try {
117             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
118             CompositeNode result = biDataService.readOperationalData(biPath);
119             return potentialAugmentationRead(path,biPath,result);
120         } catch (DeserializationException e) {
121             throw new IllegalStateException(e);
122         }
123     }
124
125     private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result) throws DeserializationException {
126         Class<? extends DataObject> targetType = path.getTargetType();
127         if (Augmentation.class.isAssignableFrom(targetType)) {
128             path = mappingService.fromDataDom(biPath);
129             Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
130             DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
131             if (parentTo instanceof Augmentable<?>) {
132                 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
133             }
134         }
135         return mappingService.dataObjectFromDataDom(path, result);
136     }
137
138     @Override
139     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
140         try {
141             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
142             CompositeNode result = biDataService.readConfigurationData(biPath);
143             return potentialAugmentationRead(path,biPath,result);
144         } catch (DeserializationException e) {
145             throw new IllegalStateException(e);
146         }
147     }
148
149     private DataModificationTransaction createBindingToDomTransaction(
150             DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
151         DataModificationTransaction target = biDataService.beginTransaction();
152         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
153                 .entrySet()) {
154             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
155                     .toDataDom(entry);
156             target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
157         }
158         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
159                 .entrySet()) {
160             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
161                     .toDataDom(entry);
162             target.putOperationalData(biEntry.getKey(), biEntry.getValue());
163         }
164         for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
165             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
166             target.removeConfigurationData(biEntry);
167         }
168         for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
169             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
170             target.removeOperationalData(biEntry);
171         }
172         return target;
173     }
174
175     private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
176             DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
177         org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
178                 .beginTransaction();
179         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
180                 .getUpdatedConfigurationData().entrySet()) {
181             try {
182                 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
183                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
184                 target.putConfigurationData(baKey, baData);
185             } catch (DeserializationException e) {
186                 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
187             }
188         }
189         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
190                 .getUpdatedOperationalData().entrySet()) {
191             try {
192
193                 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
194                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
195                 target.putOperationalData(baKey, baData);
196             } catch (DeserializationException e) {
197                 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
198             }
199         }
200         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
201             try {
202
203                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
204                 target.removeConfigurationData(baEntry);
205             } catch (DeserializationException e) {
206                 LOG.error("Ommiting from BA transaction: {}.", entry, e);
207             }
208         }
209         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
210             try {
211
212                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
213                 target.removeOperationalData(baEntry);
214             } catch (DeserializationException e) {
215                 LOG.error("Ommiting from BA transaction: {}.", entry, e);
216             }
217         }
218         return target;
219     }
220
221     public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
222         return biDataService;
223     }
224
225     public void setBiDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
226         this.biDataService = biDataService;
227     }
228
229     public DataProviderService getBaDataService() {
230         return baDataService;
231     }
232
233     public void setBaDataService(DataProviderService baDataService) {
234         this.baDataService = baDataService;
235     }
236
237     public RpcProviderRegistry getRpcRegistry() {
238         return baRpcRegistry;
239     }
240
241     public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) {
242         this.baRpcRegistry = rpcRegistry;
243     }
244
245     public void start() {
246         baDataService.registerDataReader(ROOT, this);
247         baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
248         biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
249         baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
250
251         if (baRpcRegistry != null && biRpcRegistry != null) {
252             domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
253
254         }
255     }
256
257     public void setMappingService(BindingIndependentMappingService mappingService) {
258         this.mappingService = mappingService;
259     }
260
261     @Override
262     public Collection<ProviderFunctionality> getProviderFunctionality() {
263         return Collections.emptyList();
264     }
265
266     @Override
267     public void onSessionInitiated(ProviderSession session) {
268         setBiDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
269         start();
270     }
271
272     public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
273
274     }
275
276     public void setDomRpcRegistry(RpcProvisionRegistry registry) {
277         biRpcRegistry = registry;
278     }
279
280     @Override
281     public void close() throws Exception {
282         if (baCommitHandlerRegistration != null) {
283             baCommitHandlerRegistration.close();
284         }
285         if (biCommitHandlerRegistration != null) {
286             biCommitHandlerRegistration.close();
287         }
288
289     }
290
291     private class DomToBindingTransaction implements
292             DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
293
294         private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
295         private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
296
297         public DomToBindingTransaction(
298                 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
299                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
300             super();
301             this.backing = backing;
302             this.modification = modification;
303             bindingOpenedTransactions.put(backing.getIdentifier(), this);
304         }
305
306         @Override
307         public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
308             return modification;
309         }
310
311         @Override
312         public RpcResult<Void> rollback() throws IllegalStateException {
313             // backing.cancel();
314             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
315         }
316
317         @Override
318         public RpcResult<Void> finish() throws IllegalStateException {
319             Future<RpcResult<TransactionStatus>> result = backing.commit();
320             try {
321                 RpcResult<TransactionStatus> baResult = result.get();
322                 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
323             } catch (InterruptedException e) {
324                 throw new IllegalStateException("", e);
325             } catch (ExecutionException e) {
326                 throw new IllegalStateException("", e);
327             }
328         }
329     }
330
331     private class BindingToDomTransaction implements
332             DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
333
334         private DataModificationTransaction backing;
335         private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
336
337         public BindingToDomTransaction(DataModificationTransaction backing,
338                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
339             this.backing = backing;
340             this.modification = modification;
341             domOpenedTransactions.put(backing.getIdentifier(), this);
342         }
343
344         @Override
345         public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
346             return modification;
347         }
348
349         @Override
350         public RpcResult<Void> finish() throws IllegalStateException {
351             Future<RpcResult<TransactionStatus>> result = backing.commit();
352             try {
353                 RpcResult<TransactionStatus> biResult = result.get();
354                 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
355             } catch (InterruptedException e) {
356                 throw new IllegalStateException("", e);
357             } catch (ExecutionException e) {
358                 throw new IllegalStateException("", e);
359             } finally {
360                 domOpenedTransactions.remove(backing.getIdentifier());
361             }
362         }
363
364         @Override
365         public RpcResult<Void> rollback() throws IllegalStateException {
366             domOpenedTransactions.remove(backing.getIdentifier());
367             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
368         }
369     }
370
371     private class BindingToDomCommitHandler implements
372             DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
373
374         @Override
375         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
376                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
377
378             /**
379              * Transaction was created as DOM transaction, in that case we do
380              * not need to forward it back.
381              */
382             if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
383
384                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(bindingTransaction);
385             }
386             DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
387             BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
388             LOG.info("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
389                     domTransaction.getIdentifier());
390             return wrapped;
391         }
392     }
393
394     private class DomToBindingCommitHandler implements //
395             RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject>>, //
396             DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
397
398         @Override
399         public void onRegister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
400
401             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
402                     .getPath());
403
404         }
405
406         @Override
407         public void onUnregister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
408             // NOOP for now
409             // FIXME: do registration based on only active commit handlers.
410         }
411
412         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
413                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
414             Object identifier = domTransaction.getIdentifier();
415
416             /**
417              * We checks if the transcation was originated in this mapper. If it
418              * was originated in this mapper we are returing allways success
419              * commit hanlder to prevent creating loop in two-phase commit and
420              * duplicating data.
421              */
422             if (domOpenedTransactions.containsKey(identifier)) {
423                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(domTransaction);
424             }
425
426             org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
427             DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
428             LOG.info("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
429                     baTransaction.getIdentifier());
430             return forwardedTransaction;
431         }
432     }
433
434     private class DomToBindingRpcForwardingManager implements
435             RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>> {
436
437         private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
438
439         @Override
440         public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
441             for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
442                 bindingRoutesAdded(entry);
443             }
444         }
445
446         private void bindingRoutesAdded(Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
447             Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
448             Class<? extends RpcService> service = entry.getKey().getRpcService();
449             if (context != null) {
450                 getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
451             }
452         }
453
454         private DomToBindingRpcForwarder getRpcForwarder(Class<? extends RpcService> service,
455                 Class<? extends BaseIdentity> context) {
456             DomToBindingRpcForwarder potential = forwarders.get(service);
457             if (potential != null) {
458                 return potential;
459             }
460             if (context == null) {
461                 potential = new DomToBindingRpcForwarder(service);
462             } else {
463                 potential = new DomToBindingRpcForwarder(service, context);
464             }
465             forwarders.put(service, potential);
466             return potential;
467         }
468
469     }
470
471     private class DomToBindingRpcForwarder implements RpcImplementation {
472
473         private final Set<QName> supportedRpcs;
474         private final WeakReference<Class<? extends RpcService>> rpcServiceType;
475         private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
476
477         public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
478             this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
479             this.supportedRpcs = mappingService.getRpcQNamesFor(service);
480             for (QName rpc : supportedRpcs) {
481                 biRpcRegistry.addRpcImplementation(rpc, this);
482             }
483             registrations = ImmutableSet.of();
484         }
485
486         public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
487             this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
488             this.supportedRpcs = mappingService.getRpcQNamesFor(service);
489             registrations = new HashSet<>();
490             for (QName rpc : supportedRpcs) {
491                 registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
492             }
493             registrations = ImmutableSet.copyOf(registrations);
494         }
495
496         public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
497                 Set<InstanceIdentifier<?>> set) {
498             QName ctx = BindingReflections.findQName(context);
499             for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
500                     toDOMInstanceIdentifier)) {
501                 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
502                     reg.registerPath(ctx, path);
503                 }
504             }
505         }
506
507         public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
508                 Set<InstanceIdentifier<?>> set) {
509             QName ctx = BindingReflections.findQName(context);
510             for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
511                     toDOMInstanceIdentifier)) {
512                 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
513                     reg.unregisterPath(ctx, path);
514                 }
515             }
516         }
517
518         @Override
519         public Set<QName> getSupportedRpcs() {
520             return supportedRpcs;
521         }
522
523         @Override
524         public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
525             checkArgument(rpc != null);
526             checkArgument(domInput != null);
527
528             Class<? extends RpcService> rpcType = rpcServiceType.get();
529             checkState(rpcType != null);
530             RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
531             checkState(rpcService != null);
532             CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
533             try {
534                 return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput);
535             } catch (Exception e) {
536                 throw new IllegalStateException(e);
537             }
538         }
539
540         private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc,
541                 final Class<? extends RpcService> rpcType) throws Exception {
542             return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
543                 @Override
544                 public RpcInvocationStrategy call() throws Exception {
545                     String methodName = BindingMapping.getMethodName(rpc);
546                     Method targetMethod = null;
547                     for (Method possibleMethod : rpcType.getMethods()) {
548                         if (possibleMethod.getName().equals(methodName)
549                                 && BindingReflections.isRpcMethod(possibleMethod)) {
550                             targetMethod = possibleMethod;
551                             break;
552                         }
553                     }
554                     checkState(targetMethod != null, "Rpc method not found");
555                     Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
556                     Optional<Class<? extends DataContainer>> inputClass = BindingReflections
557                             .resolveRpcInputClass(targetMethod);
558
559                     RpcInvocationStrategy strategy = null;
560                     if (outputClass.isPresent()) {
561                         if (inputClass.isPresent()) {
562                             strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get());
563                         } else {
564                             strategy = new NoInputNoOutputInvocationStrategy(targetMethod);
565                         }
566                     } else {
567                         strategy = null;
568                     }
569                     return strategy;
570                 }
571
572             });
573         }
574     }
575
576     private abstract class RpcInvocationStrategy {
577
578         protected final Method targetMethod;
579
580         public RpcInvocationStrategy(Method targetMethod) {
581             this.targetMethod = targetMethod;
582         }
583
584         public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
585                 throws Exception;
586
587         public RpcResult<CompositeNode> invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception {
588             return uncheckedInvoke(rpcService, domInput);
589         }
590     }
591
592     private class DefaultInvocationStrategy extends RpcInvocationStrategy {
593
594         @SuppressWarnings("rawtypes")
595         private WeakReference<Class> inputClass;
596
597         @SuppressWarnings("rawtypes")
598         private WeakReference<Class> outputClass;
599
600         public DefaultInvocationStrategy(Method targetMethod, Class<?> outputClass,
601                 Class<? extends DataContainer> inputClass) {
602             super(targetMethod);
603             this.outputClass = new WeakReference(outputClass);
604             this.inputClass = new WeakReference(inputClass);
605         }
606
607         @Override
608         public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
609             DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
610             Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
611             if (result == null) {
612                 return Rpcs.getRpcResult(false);
613             }
614             RpcResult<?> bindingResult = result.get();
615             return Rpcs.getRpcResult(true);
616         }
617
618     }
619
620     private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
621
622         public NoInputNoOutputInvocationStrategy(Method targetMethod) {
623             super(targetMethod);
624         }
625
626         public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
627             Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
628             RpcResult<Void> bindingResult = result.get();
629             return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
630         }
631
632     }
633 }