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