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