Fix a race PingPongTransactionChain
[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.checkNotNull;
11 import static com.google.common.base.Preconditions.checkState;
12
13 import java.util.Collection;
14 import java.util.Collections;
15
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import org.opendaylight.controller.md.sal.binding.impl.AbstractForwardedDataBroker;
19 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
20 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
21 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
22 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
23 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
24 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
25 import org.opendaylight.controller.sal.binding.impl.MountPointManagerImpl.BindingMountPointImpl;
26 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
27 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
28 import org.opendaylight.controller.sal.core.api.Provider;
29 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
30 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
31 import org.opendaylight.yangtools.concepts.ListenerRegistration;
32 import org.opendaylight.yangtools.concepts.Registration;
33 import org.opendaylight.yangtools.yang.binding.Augmentable;
34 import org.opendaylight.yangtools.yang.binding.Augmentation;
35 import org.opendaylight.yangtools.yang.binding.DataObject;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
38 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
39 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 public class BindingIndependentConnector implements //
44         RuntimeDataProvider, //
45         Provider, //
46         AutoCloseable {
47
48     private static final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
49     private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
50             .builder().toInstance();
51
52     private BindingIndependentMappingService mappingService;
53     private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
54     private DataProviderService baDataService;
55
56     private final ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions;
57     private final ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions;
58     private final BindingToDomCommitHandler bindingToDomCommitHandler;
59     private final DomToBindingCommitHandler domToBindingCommitHandler;
60
61     private Registration biCommitHandlerRegistration;
62     private RpcProvisionRegistry biRpcRegistry;
63     private RpcProviderRegistry baRpcRegistry;
64
65     private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
66
67     private boolean rpcForwarding;
68     private boolean dataForwarding;
69     private boolean notificationForwarding;
70
71     private RpcProviderRegistryImpl baRpcRegistryImpl;
72
73     private NotificationProviderService baNotifyService;
74
75     private NotificationPublishService domNotificationService;
76
77     public BindingIndependentConnector() {
78         domOpenedTransactions = new ConcurrentHashMap<>();
79         bindingOpenedTransactions = new ConcurrentHashMap<>();
80
81         bindingToDomCommitHandler = new BindingToDomCommitHandler(bindingOpenedTransactions, domOpenedTransactions);
82         domToBindingCommitHandler = new DomToBindingCommitHandler(bindingOpenedTransactions, domOpenedTransactions);
83         rpcForwarding = false;
84         dataForwarding = false;
85         notificationForwarding = false;
86     }
87
88     @Override
89     public DataObject readOperationalData(final InstanceIdentifier<? extends DataObject> path) {
90         try {
91             org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier biPath = mappingService.toDataDom(path);
92             CompositeNode result = biDataService.readOperationalData(biPath);
93             return potentialAugmentationRead(path, biPath, result);
94         } catch (DeserializationException e) {
95             throw new IllegalStateException(e);
96         }
97     }
98
99     private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
100             final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier biPath, final CompositeNode result)
101             throws DeserializationException {
102         Class<? extends DataObject> targetType = path.getTargetType();
103         if (Augmentation.class.isAssignableFrom(targetType)) {
104             path = mappingService.fromDataDom(biPath);
105             Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
106             DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
107             if (parentTo instanceof Augmentable<?>) {
108                 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
109             }
110         }
111         return mappingService.dataObjectFromDataDom(path, result);
112     }
113
114     @Override
115     public DataObject readConfigurationData(final InstanceIdentifier<? extends DataObject> path) {
116         try {
117             org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier biPath = mappingService.toDataDom(path);
118             CompositeNode result = biDataService.readConfigurationData(biPath);
119             return potentialAugmentationRead(path, biPath, result);
120         } catch (DeserializationException e) {
121             throw new IllegalStateException(e);
122         }
123     }
124
125     public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
126         return biDataService;
127     }
128
129     protected void setDomDataService(
130             final org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
131         this.biDataService = biDataService;
132         bindingToDomCommitHandler.setBindingIndependentDataService(this.biDataService);
133     }
134
135     public DataProviderService getBaDataService() {
136         return baDataService;
137     }
138
139     protected void setBindingDataService(final DataProviderService baDataService) {
140         this.baDataService = baDataService;
141         domToBindingCommitHandler.setBindingAwareDataService(this.baDataService);
142     }
143
144     public RpcProviderRegistry getRpcRegistry() {
145         return baRpcRegistry;
146     }
147
148     protected void setBindingRpcRegistry(final RpcProviderRegistry rpcRegistry) {
149         this.baRpcRegistry = rpcRegistry;
150     }
151
152     public void startDataForwarding() {
153         if (baDataService instanceof AbstractForwardedDataBroker) {
154             dataForwarding = true;
155             return;
156         }
157
158         final DataProviderService baData;
159         if (baDataService instanceof BindingMountPointImpl) {
160             baData = ((BindingMountPointImpl) baDataService).getDataBrokerImpl();
161             LOG.debug("Extracted BA Data provider {} from mount point {}", baData, baDataService);
162         } else {
163             baData = baDataService;
164         }
165
166         if (baData instanceof DataBrokerImpl) {
167             checkState(!dataForwarding, "Connector is already forwarding data.");
168             ((DataBrokerImpl) baData).setDataReadDelegate(this);
169             ((DataBrokerImpl) baData).setRootCommitHandler(bindingToDomCommitHandler);
170             biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
171             baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
172         }
173
174         dataForwarding = true;
175     }
176
177     //WTF? - cycle references to biFwdManager - need to solve :-/
178     public void startRpcForwarding() {
179         checkNotNull(mappingService, "Unable to start Rpc forwarding. Reason: Mapping Service is not initialized properly!");
180         if (biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
181             checkState(!rpcForwarding, "Connector is already forwarding RPCs");
182             final DomToBindingRpcForwardingManager biFwdManager = new DomToBindingRpcForwardingManager(mappingService, biRpcRegistry, baRpcRegistry);
183
184             domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(biFwdManager);
185             biRpcRegistry.addRpcRegistrationListener(biFwdManager);
186             if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
187                 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
188                 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
189                 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
190                 biFwdManager.setRegistryImpl(baRpcRegistryImpl);
191             }
192             rpcForwarding = true;
193         }
194     }
195
196     public void startNotificationForwarding() {
197         checkState(!notificationForwarding, "Connector is already forwarding notifications.");
198         if (mappingService == null) {
199             LOG.warn("Unable to start Notification forwarding. Reason: Mapping Service is not initialized properly!");
200         } else if (baNotifyService == null) {
201             LOG.warn("Unable to start Notification forwarding. Reason: Binding Aware Notify Service is not initialized properly!");
202         } else if (domNotificationService == null) {
203             LOG.warn("Unable to start Notification forwarding. Reason: DOM Notification Service is not initialized properly!");
204         } else {
205             baNotifyService.registerInterestListener(
206                 new DomToBindingNotificationForwarder(mappingService, baNotifyService, domNotificationService));
207             notificationForwarding = true;
208         }
209     }
210
211     protected void setMappingService(final BindingIndependentMappingService mappingService) {
212         this.mappingService = mappingService;
213         bindingToDomCommitHandler.setMappingService(this.mappingService);
214         domToBindingCommitHandler.setMappingService(this.mappingService);
215     }
216
217     @Override
218     public Collection<ProviderFunctionality> getProviderFunctionality() {
219         return Collections.emptyList();
220     }
221
222     @Override
223     public void onSessionInitiated(final ProviderSession session) {
224         setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
225         setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
226
227     }
228
229     public void setDomRpcRegistry(final RpcProvisionRegistry registry) {
230         biRpcRegistry = registry;
231     }
232
233     @Override
234     public void close() throws Exception {
235         if (biCommitHandlerRegistration != null) {
236             biCommitHandlerRegistration.close();
237         }
238     }
239
240     public boolean isRpcForwarding() {
241         return rpcForwarding;
242     }
243
244     public boolean isDataForwarding() {
245         return dataForwarding;
246     }
247
248     public boolean isNotificationForwarding() {
249         return notificationForwarding;
250     }
251
252     public BindingIndependentMappingService getMappingService() {
253         return mappingService;
254     }
255
256     public void setBindingNotificationService(final NotificationProviderService baService) {
257         this.baNotifyService = baService;
258
259     }
260
261     public void setDomNotificationService(final NotificationPublishService domService) {
262         this.domNotificationService = domService;
263     }
264 }