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

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