5f3189f7d2a196593ec2c903c1a2eb717c488ac5
[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         if (baCommitHandlerRegistration != null) {
195             baCommitHandlerRegistration.close();
196         }
197         if (biCommitHandlerRegistration != null) {
198             biCommitHandlerRegistration.close();
199         }
200
201     }
202
203     private class DomToBindingTransaction implements
204             DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
205
206         private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
207         private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
208
209         public DomToBindingTransaction(
210                 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
211                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
212             super();
213             this.backing = backing;
214             this.modification = modification;
215             bindingOpenedTransactions.put(backing.getIdentifier(), this);
216         }
217
218         @Override
219         public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
220             return modification;
221         }
222
223         @Override
224         public RpcResult<Void> rollback() throws IllegalStateException {
225             // backing.cancel();
226             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
227         }
228
229         @Override
230         public RpcResult<Void> finish() throws IllegalStateException {
231             Future<RpcResult<TransactionStatus>> result = backing.commit();
232             try {
233                 RpcResult<TransactionStatus> baResult = result.get();
234                 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
235             } catch (InterruptedException e) {
236                 throw new IllegalStateException("", e);
237             } catch (ExecutionException e) {
238                 throw new IllegalStateException("", e);
239             }
240         }
241     }
242
243     private class BindingToDomTransaction implements
244             DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
245
246         private DataModificationTransaction backing;
247         private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
248
249         public BindingToDomTransaction(DataModificationTransaction backing,
250                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
251             this.backing = backing;
252             this.modification = modification;
253             domOpenedTransactions.put(backing.getIdentifier(), this);
254         }
255
256         @Override
257         public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
258             return modification;
259         }
260
261         @Override
262         public RpcResult<Void> finish() throws IllegalStateException {
263             Future<RpcResult<TransactionStatus>> result = backing.commit();
264             try {
265                 RpcResult<TransactionStatus> biResult = result.get();
266                 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
267             } catch (InterruptedException e) {
268                 throw new IllegalStateException("", e);
269             } catch (ExecutionException e) {
270                 throw new IllegalStateException("", e);
271             } finally {
272                 domOpenedTransactions.remove(backing.getIdentifier());
273             }
274         }
275
276         @Override
277         public RpcResult<Void> rollback() throws IllegalStateException {
278             domOpenedTransactions.remove(backing.getIdentifier());
279             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
280         }
281     }
282
283     private class BindingToDomCommitHandler implements
284             DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
285
286         @Override
287         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
288                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
289
290             /**
291              * Transaction was created as DOM transaction, in that case we do
292              * not need to forward it back.
293              */
294             if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
295
296                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(bindingTransaction);
297             }
298             DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
299             BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
300             LOG.info("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
301                     domTransaction.getIdentifier());
302             return wrapped;
303         }
304     }
305
306     private class DomToBindingCommitHandler implements //
307             RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject>>, //
308             DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
309
310         @Override
311         public void onRegister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
312
313             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
314                     .getPath());
315
316         }
317
318         @Override
319         public void onUnregister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
320             // NOOP for now
321             // FIXME: do registration based on only active commit handlers.
322         }
323
324         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
325                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
326             Object identifier = domTransaction.getIdentifier();
327
328             /**
329              * We checks if the transcation was originated in this mapper. If it
330              * was originated in this mapper we are returing allways success
331              * commit hanlder to prevent creating loop in two-phase commit and
332              * duplicating data.
333              */
334             if (domOpenedTransactions.containsKey(identifier)) {
335                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(domTransaction);
336             }
337
338             org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
339             DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
340             LOG.info("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
341                     baTransaction.getIdentifier());
342             return forwardedTransaction;
343         }
344     }
345 }