Merge changes I0f752636,Idd154499,Ic35fa3e8
[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 {
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         org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
63         CompositeNode result = biDataService.readOperationalData(biPath);
64         return mappingService.dataObjectFromDataDom(path, result);
65     }
66
67     @Override
68     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
69         org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
70         CompositeNode result = biDataService.readConfigurationData(biPath);
71         return mappingService.dataObjectFromDataDom(path, result);
72     }
73
74     private DataModificationTransaction createBindingToDomTransaction(
75             DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
76         DataModificationTransaction target = biDataService.beginTransaction();
77         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
78                 .entrySet()) {
79             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
80                     .toDataDom(entry);
81             target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
82         }
83         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
84                 .entrySet()) {
85             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
86                     .toDataDom(entry);
87             target.putOperationalData(biEntry.getKey(), biEntry.getValue());
88         }
89         for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
90             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
91             target.removeConfigurationData(biEntry);
92         }
93         for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
94             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
95             target.removeOperationalData(biEntry);
96         }
97         return target;
98     }
99
100     private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
101             DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
102         org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
103                 .beginTransaction();
104         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
105                 .getUpdatedConfigurationData().entrySet()) {
106             InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
107             DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
108             target.putConfigurationData(baKey, baData);
109         }
110         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
111                 .getUpdatedOperationalData().entrySet()) {
112             InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
113             DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
114             target.putOperationalData(baKey, baData);
115         }
116         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
117             InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
118             target.removeConfigurationData(baEntry);
119         }
120         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
121             InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
122             target.removeOperationalData(baEntry);
123         }
124         return target;
125     }
126
127     public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
128         return biDataService;
129     }
130
131     public void setBiDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
132         this.biDataService = biDataService;
133     }
134
135     public DataProviderService getBaDataService() {
136         return baDataService;
137     }
138
139     public void setBaDataService(DataProviderService baDataService) {
140         this.baDataService = baDataService;
141     }
142
143     public void start() {
144         baDataService.registerDataReader(ROOT, this);
145         baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
146         biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
147         baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
148     }
149
150     public void setMappingService(BindingIndependentMappingService mappingService) {
151         this.mappingService = mappingService;
152     }
153
154     @Override
155     public Collection<ProviderFunctionality> getProviderFunctionality() {
156         return Collections.emptyList();
157     }
158
159     @Override
160     public void onSessionInitiated(ProviderSession session) {
161         setBiDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
162         start();
163     }
164
165     private class DomToBindingTransaction implements
166             DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
167
168         private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
169         private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
170
171         public DomToBindingTransaction(
172                 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
173                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
174             super();
175             this.backing = backing;
176             this.modification = modification;
177             bindingOpenedTransactions.put(backing.getIdentifier(), this);
178         }
179
180         @Override
181         public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
182             return modification;
183         }
184
185         @Override
186         public RpcResult<Void> rollback() throws IllegalStateException {
187             // backing.cancel();
188             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
189         }
190
191         @Override
192         public RpcResult<Void> finish() throws IllegalStateException {
193             Future<RpcResult<TransactionStatus>> result = backing.commit();
194             try {
195                 RpcResult<TransactionStatus> baResult = result.get();
196                 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
197             } catch (InterruptedException e) {
198                 throw new IllegalStateException("", e);
199             } catch (ExecutionException e) {
200                 throw new IllegalStateException("", e);
201             }
202         }
203     }
204
205     private class BindingToDomTransaction implements
206             DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
207
208         private DataModificationTransaction backing;
209         private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
210
211         public BindingToDomTransaction(DataModificationTransaction backing,
212                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
213             this.backing = backing;
214             this.modification = modification;
215             domOpenedTransactions.put(backing.getIdentifier(), this);
216         }
217
218         @Override
219         public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
220             return modification;
221         }
222
223         @Override
224         public RpcResult<Void> finish() throws IllegalStateException {
225             Future<RpcResult<TransactionStatus>> result = backing.commit();
226             try {
227                 RpcResult<TransactionStatus> biResult = result.get();
228                 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
229             } catch (InterruptedException e) {
230                 throw new IllegalStateException("", e);
231             } catch (ExecutionException e) {
232                 throw new IllegalStateException("", e);
233             } finally {
234                 domOpenedTransactions.remove(backing.getIdentifier());
235             }
236         }
237
238         @Override
239         public RpcResult<Void> rollback() throws IllegalStateException {
240             domOpenedTransactions.remove(backing.getIdentifier());
241             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
242         }
243     }
244
245     private class BindingToDomCommitHandler implements
246             DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
247
248         @Override
249         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
250                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
251
252             /**
253              * Transaction was created as DOM transaction, in that case we do
254              * not need to forward it back.
255              */
256             if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
257
258                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(bindingTransaction);
259             }
260             DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
261             BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
262             LOG.info("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
263                     domTransaction.getIdentifier());
264             return wrapped;
265         }
266     }
267
268     private class DomToBindingCommitHandler implements //
269             RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject>>, //
270             DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
271
272         @Override
273         public void onRegister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
274             
275             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration.getPath());
276             // FIXME: do registration based on only active commit handlers.
277             
278         }
279
280         @Override
281         public void onUnregister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
282             // NOOP for now
283             // FIXME: do registration based on only active commit handlers.
284         }
285
286         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
287                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
288             Object identifier = domTransaction.getIdentifier();
289
290             /**
291              * We checks if the transcation was originated in this mapper. If it
292              * was originated in this mapper we are returing allways success
293              * commit hanlder to prevent creating loop in two-phase commit and
294              * duplicating data.
295              */
296             if (domOpenedTransactions.containsKey(identifier)) {
297                 return CommitHandlersTransactions.allwaysSuccessfulTransaction(domTransaction);
298             }
299
300             org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
301             DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
302             LOG.info("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
303                     baTransaction.getIdentifier());
304             return forwardedTransaction;
305         }
306     }
307 }