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