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