7a72afc88550b3871ea72286f5b791b4a90f568c
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / impl / connect / dom / BindingIndependentDataServiceConnector.java
1 package org.opendaylight.controller.sal.binding.impl.connect.dom;
2
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.Map;
6 import java.util.Map.Entry;
7 import java.util.concurrent.ConcurrentHashMap;
8 import java.util.concurrent.ConcurrentMap;
9 import java.util.concurrent.ExecutionException;
10 import java.util.concurrent.Future;
11
12 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
13 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
14 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
15 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
17 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
18 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
19 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
20 import org.opendaylight.controller.sal.common.util.Rpcs;
21 import org.opendaylight.controller.sal.core.api.Provider;
22 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
23 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
24 import org.opendaylight.yangtools.concepts.Registration;
25 import org.opendaylight.yangtools.yang.binding.DataObject;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.opendaylight.yangtools.yang.common.RpcError;
28 import org.opendaylight.yangtools.yang.common.RpcResult;
29 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 public class BindingIndependentDataServiceConnector implements //
34         RuntimeDataProvider, //
35         Provider, AutoCloseable {
36
37     private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class);
38
39     private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
40
41     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
42             .builder().toInstance();
43
44     private BindingIndependentMappingService mappingService;
45
46     private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
47
48     private DataProviderService baDataService;
49
50     private ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
51     private ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
52
53     private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
54     private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
55
56     private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
57
58     private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
59
60     @Override
61     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
62         try {
63             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
64             CompositeNode result = biDataService.readOperationalData(biPath);
65             return mappingService.dataObjectFromDataDom(path, result);
66         } catch (DeserializationException e) {
67             throw new IllegalStateException(e);
68         }
69     }
70
71     @Override
72     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
73         try {
74             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
75             CompositeNode result = biDataService.readConfigurationData(biPath);
76             return mappingService.dataObjectFromDataDom(path, result);
77         } catch (DeserializationException e) {
78             throw new IllegalStateException(e);
79         }
80     }
81
82     private DataModificationTransaction createBindingToDomTransaction(
83             DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
84         DataModificationTransaction target = biDataService.beginTransaction();
85         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
86                 .entrySet()) {
87             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
88                     .toDataDom(entry);
89             target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
90         }
91         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
92                 .entrySet()) {
93             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
94                     .toDataDom(entry);
95             target.putOperationalData(biEntry.getKey(), biEntry.getValue());
96         }
97         for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
98             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
99             target.removeConfigurationData(biEntry);
100         }
101         for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
102             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
103             target.removeOperationalData(biEntry);
104         }
105         return target;
106     }
107
108     private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
109             DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
110         org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
111                 .beginTransaction();
112         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
113                 .getUpdatedConfigurationData().entrySet()) {
114             try {
115                 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
116                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
117                 target.putConfigurationData(baKey, baData);
118             } catch (DeserializationException e) {
119                 LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry.getKey(), e);
120             }
121         }
122         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
123                 .getUpdatedOperationalData().entrySet()) {
124             try {
125
126                 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
127                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
128                 target.putOperationalData(baKey, baData);
129             } catch (DeserializationException e) {
130                 LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry.getKey(), e);
131             }
132         }
133         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
134             try {
135
136                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
137                 target.removeConfigurationData(baEntry);
138             } catch (DeserializationException e) {
139                 LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e);
140             }
141         }
142         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
143             try {
144
145                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
146                 target.removeOperationalData(baEntry);
147             } catch (DeserializationException e) {
148                 LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e);
149             }
150         }
151         return target;
152     }
153
154     public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
155         return biDataService;
156     }
157
158     public void setBiDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
159         this.biDataService = biDataService;
160     }
161
162     public DataProviderService getBaDataService() {
163         return baDataService;
164     }
165
166     public void setBaDataService(DataProviderService baDataService) {
167         this.baDataService = baDataService;
168     }
169
170     public void start() {
171         baDataService.registerDataReader(ROOT, this);
172         baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
173         biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
174         baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
175     }
176
177     public void setMappingService(BindingIndependentMappingService mappingService) {
178         this.mappingService = mappingService;
179     }
180
181     @Override
182     public Collection<ProviderFunctionality> getProviderFunctionality() {
183         return Collections.emptyList();
184     }
185
186     @Override
187     public void onSessionInitiated(ProviderSession session) {
188         setBiDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
189         start();
190     }
191
192     @Override
193     public void close() throws Exception {
194
195         if (baCommitHandlerRegistration != null) {
196             baCommitHandlerRegistration.close();
197         }
198         if (biCommitHandlerRegistration != null) {
199             biCommitHandlerRegistration.close();
200         }
201
202     }
203
204     private class DomToBindingTransaction implements
205             DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
206
207         private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
208         private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
209
210         public DomToBindingTransaction(
211                 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
212                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
213             super();
214             this.backing = backing;
215             this.modification = modification;
216             bindingOpenedTransactions.put(backing.getIdentifier(), this);
217         }
218
219         @Override
220         public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
221             return modification;
222         }
223
224         @Override
225         public RpcResult<Void> rollback() throws IllegalStateException {
226             // backing.cancel();
227             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
228         }
229
230         @Override
231         public RpcResult<Void> finish() throws IllegalStateException {
232             Future<RpcResult<TransactionStatus>> result = backing.commit();
233             try {
234                 RpcResult<TransactionStatus> baResult = result.get();
235                 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
236             } catch (InterruptedException e) {
237                 throw new IllegalStateException("", e);
238             } catch (ExecutionException e) {
239                 throw new IllegalStateException("", e);
240             }
241         }
242     }
243
244     private class BindingToDomTransaction implements
245             DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
246
247         private DataModificationTransaction backing;
248         private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
249
250         public BindingToDomTransaction(DataModificationTransaction backing,
251                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
252             this.backing = backing;
253             this.modification = modification;
254             domOpenedTransactions.put(backing.getIdentifier(), this);
255         }
256
257         @Override
258         public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
259             return modification;
260         }
261
262         @Override
263         public RpcResult<Void> finish() throws IllegalStateException {
264             Future<RpcResult<TransactionStatus>> result = backing.commit();
265             try {
266                 RpcResult<TransactionStatus> biResult = result.get();
267                 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
268             } catch (InterruptedException e) {
269                 throw new IllegalStateException("", e);
270             } catch (ExecutionException e) {
271                 throw new IllegalStateException("", e);
272             } finally {
273                 domOpenedTransactions.remove(backing.getIdentifier());
274             }
275         }
276
277         @Override
278         public RpcResult<Void> rollback() throws IllegalStateException {
279             domOpenedTransactions.remove(backing.getIdentifier());
280             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
281         }
282     }
283
284     private class BindingToDomCommitHandler implements
285             DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
286
287         @Override
288         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
289                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
290
291             /**
292              * Transaction was created as DOM transaction, in that case we do
293              * not need to forward it back.
294              */
295             if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
296
297                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(bindingTransaction);
298             }
299             DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
300             BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
301             LOG.info("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
302                     domTransaction.getIdentifier());
303             return wrapped;
304         }
305     }
306
307     private class DomToBindingCommitHandler implements //
308             RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject>>, //
309             DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
310
311         @Override
312         public void onRegister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
313
314             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
315                     .getPath());
316             // FIXME: do registration based on only active commit handlers.
317
318         }
319
320         @Override
321         public void onUnregister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
322             // NOOP for now
323             // FIXME: do registration based on only active commit handlers.
324         }
325
326         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
327                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
328             Object identifier = domTransaction.getIdentifier();
329
330             /**
331              * We checks if the transcation was originated in this mapper. If it
332              * was originated in this mapper we are returing allways success
333              * commit hanlder to prevent creating loop in two-phase commit and
334              * duplicating data.
335              */
336             if (domOpenedTransactions.containsKey(identifier)) {
337                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(domTransaction);
338             }
339
340             org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
341             DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
342             LOG.info("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
343                     baTransaction.getIdentifier());
344             return forwardedTransaction;
345         }
346     }
347 }