Merge "Update config-module-archetype."
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / broker / impl / compat / BackwardsCompatibleTransaction.java
1 package org.opendaylight.controller.md.sal.dom.broker.impl.compat;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Map.Entry;
11 import java.util.Set;
12 import java.util.concurrent.ExecutionException;
13 import java.util.concurrent.Future;
14
15 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
18 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
19 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
20 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
21 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
22 import org.opendaylight.yangtools.concepts.Delegator;
23 import org.opendaylight.yangtools.concepts.ListenerRegistration;
24 import org.opendaylight.yangtools.yang.common.RpcResult;
25 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
26 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
30 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
35 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import com.google.common.base.Optional;
40 import com.google.common.base.Preconditions;
41 import com.google.common.collect.Iterables;
42 import com.google.common.util.concurrent.ListenableFuture;
43
44 public abstract class BackwardsCompatibleTransaction<T extends DOMDataReadTransaction> implements
45         DataModificationTransaction, Delegator<T> {
46
47     private static final Logger LOG = LoggerFactory.getLogger(BackwardsCompatibleTransaction.class);
48
49     private final T asyncTx;
50     private final DataNormalizer normalizer;
51
52     protected BackwardsCompatibleTransaction(final T asyncTx, final DataNormalizer normalizer) {
53         super();
54         this.asyncTx = asyncTx;
55         this.normalizer = normalizer;
56     }
57
58     public static BackwardsCompatibleTransaction<?> readOnlyTransaction(final DOMDataReadTransaction readTx,
59             final DataNormalizer normalizer) {
60
61         return new BackwardsCompatibleTransaction<DOMDataReadTransaction>(readTx, normalizer) {
62
63             @Override
64             public TransactionStatus getStatus() {
65                 return TransactionStatus.NEW;
66             }
67
68             @Override
69             public Future<RpcResult<TransactionStatus>> commit() {
70                 getDelegate().close();
71                 return null;
72             }
73         };
74     }
75
76     public static BackwardsCompatibleTransaction<?> readWriteTransaction(final DOMDataReadWriteTransaction rwTx,
77             final DataNormalizer normalizer) {
78         return new ReadWriteTransaction(rwTx, normalizer);
79     }
80
81     protected DataNormalizer getNormalizer() {
82         return normalizer;
83     }
84
85     @Override
86     public T getDelegate() {
87         return asyncTx;
88     };
89
90     @Override
91     public CompositeNode readConfigurationData(final InstanceIdentifier legacyPath) {
92
93         InstanceIdentifier normalizedPath = normalizer.toNormalized(legacyPath);
94
95         ListenableFuture<Optional<NormalizedNode<?, ?>>> normalizedData = asyncTx.read(
96                 LogicalDatastoreType.CONFIGURATION, normalizedPath);
97
98         try {
99             return normalizer.toLegacy(normalizedPath, normalizedData.get().orNull());
100         } catch (InterruptedException | ExecutionException e) {
101             return null;
102         }
103     }
104
105     @Override
106     public CompositeNode readOperationalData(final InstanceIdentifier legacyPath) {
107         InstanceIdentifier normalizedPath = normalizer.toNormalized(legacyPath);
108
109         ListenableFuture<Optional<NormalizedNode<?, ?>>> normalizedData = asyncTx.read(
110                 LogicalDatastoreType.OPERATIONAL, normalizedPath);
111
112         try {
113             return normalizer.toLegacy(normalizedPath, normalizedData.get().orNull());
114         } catch (InterruptedException | ExecutionException e) {
115             return null;
116         }
117     }
118
119     @Override
120     public ListenerRegistration<DataTransactionListener> registerListener(final DataTransactionListener listener) {
121         throw new UnsupportedOperationException();
122     }
123
124     @Override
125     public Map<InstanceIdentifier, CompositeNode> getCreatedConfigurationData() {
126         return Collections.emptyMap();
127     }
128
129     @Override
130     public Map<InstanceIdentifier, CompositeNode> getCreatedOperationalData() {
131         return Collections.emptyMap();
132     }
133
134     @Override
135     public Map<InstanceIdentifier, CompositeNode> getOriginalConfigurationData() {
136         return Collections.emptyMap();
137     }
138
139     @Override
140     public Map<InstanceIdentifier, CompositeNode> getOriginalOperationalData() {
141         return Collections.emptyMap();
142     }
143
144     @Override
145     public Set<InstanceIdentifier> getRemovedConfigurationData() {
146         return Collections.emptySet();
147     }
148
149     @Override
150     public Set<InstanceIdentifier> getRemovedOperationalData() {
151         return Collections.emptySet();
152     }
153
154     @Override
155     public Map<InstanceIdentifier, CompositeNode> getUpdatedConfigurationData() {
156         return Collections.emptyMap();
157     }
158
159     @Override
160     public Map<InstanceIdentifier, CompositeNode> getUpdatedOperationalData() {
161         return Collections.emptyMap();
162     }
163
164     @Override
165     public void putConfigurationData(final InstanceIdentifier path, final CompositeNode data) {
166         throw new UnsupportedOperationException();
167     }
168
169     @Override
170     public void putOperationalData(final InstanceIdentifier path, final CompositeNode data) {
171         throw new UnsupportedOperationException();
172     }
173
174     @Override
175     public void removeConfigurationData(final InstanceIdentifier path) {
176         throw new UnsupportedOperationException();
177     }
178
179     @Override
180     public void removeOperationalData(final InstanceIdentifier path) {
181         throw new UnsupportedOperationException();
182     }
183
184     @Override
185     public Object getIdentifier() {
186         return asyncTx.getIdentifier();
187     }
188
189     private static final class ReadWriteTransaction extends BackwardsCompatibleTransaction<DOMDataReadWriteTransaction> {
190
191         private TransactionStatus status = TransactionStatus.NEW;
192
193         protected ReadWriteTransaction(final DOMDataReadWriteTransaction asyncTx, final DataNormalizer normalizer) {
194             super(asyncTx, normalizer);
195         }
196
197         @Override
198         public TransactionStatus getStatus() {
199             return status;
200         }
201
202         @Override
203         public Future<RpcResult<TransactionStatus>> commit() {
204             Preconditions.checkState(status == TransactionStatus.NEW);
205             status = TransactionStatus.SUBMITED;
206             return getDelegate().commit();
207         }
208
209         @Override
210         public void putConfigurationData(final InstanceIdentifier legacyPath, final CompositeNode legacyData) {
211             checkNotNull(legacyPath, "Path MUST NOT be null.");
212             checkNotNull(legacyData, "Data for path %s MUST NOT be null",legacyData);
213             Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedData = getNormalizer().toNormalized(legacyPath, legacyData);
214             putWithEnsuredParents(LogicalDatastoreType.CONFIGURATION, normalizedData.getKey(), normalizedData.getValue());
215         }
216
217         @Override
218         public void putOperationalData(final InstanceIdentifier legacyPath, final CompositeNode legacyData) {
219             checkNotNull(legacyPath, "Path MUST NOT be null.");
220             checkNotNull(legacyData, "Data for path %s MUST NOT be null",legacyData);
221             Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedData = getNormalizer().toNormalized(legacyPath, legacyData);
222             putWithEnsuredParents(LogicalDatastoreType.OPERATIONAL, normalizedData.getKey(), normalizedData.getValue());
223         }
224
225         private void putWithEnsuredParents(final LogicalDatastoreType store, final InstanceIdentifier normalizedPath,
226                 final NormalizedNode<?, ?> normalizedData) {
227
228             LOG.trace("write {}:{} ",store,normalizedPath);
229             try {
230             List<PathArgument> currentArguments = new ArrayList<>();
231             DataNormalizationOperation<?> currentOp = getNormalizer().getRootOperation();
232             Iterator<PathArgument> iterator = normalizedPath.getPath().iterator();
233             while(iterator.hasNext()) {
234                 PathArgument currentArg = iterator.next();
235                 currentOp = currentOp.getChild(currentArg);
236                 currentArguments.add(currentArg);
237                 InstanceIdentifier currentPath = new InstanceIdentifier(currentArguments);
238                 boolean isPresent = getDelegate().read(store, currentPath).get().isPresent();
239                 if(isPresent == false && iterator.hasNext()) {
240                     getDelegate().put(store, currentPath, currentOp.createDefault(currentArg));
241                 }
242             }
243             } catch (InterruptedException | ExecutionException e) {
244                 LOG.error("Exception durring read.",e);
245             }
246
247             getDelegate().put(store, normalizedPath, normalizedData);
248         }
249
250         private boolean isAugmentationChild(final InstanceIdentifier normalizedPath) {
251             List<PathArgument> parentArgs = parentPath(normalizedPath).getPath();
252             if(parentArgs.isEmpty()) {
253                 return false;
254             }
255             return Iterables.getLast(parentArgs) instanceof AugmentationIdentifier;
256         }
257
258         private void ensureParentNode(final LogicalDatastoreType store, final InstanceIdentifier normalizedPath,
259                 final NormalizedNode<?, ?> normalizedData) {
260             InstanceIdentifier parentPath = parentPath(normalizedPath);
261             PathArgument parentType = Iterables.getLast(parentPath.getPath());
262             if(parentType instanceof AugmentationIdentifier) {
263                 AugmentationNode node = Builders.augmentationBuilder()
264                         .withNodeIdentifier((AugmentationIdentifier) parentType)
265                         .build();
266                 getDelegate().put(store, parentPath, node);
267             }
268             if(normalizedData instanceof MapEntryNode) {
269                 MapNode mapNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(normalizedData.getNodeType())).build();
270                 getDelegate().put(store, parentPath, mapNode);
271             } else if (normalizedData instanceof LeafSetNode<?>){
272                 LeafSetNode<Object> leafNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(normalizedData.getNodeType())).build();
273                 getDelegate().put(store, parentPath, leafNode);
274             }
275
276
277         }
278
279         private InstanceIdentifier parentPath(final InstanceIdentifier normalizedPath) {
280             List<PathArgument> childArgs = normalizedPath.getPath();
281             return new InstanceIdentifier(childArgs.subList(0, childArgs.size() -1));
282         }
283
284         private boolean parentNodeDoesNotExists(final LogicalDatastoreType store, final InstanceIdentifier normalizedPath) {
285             try {
286                 return !getDelegate().read(store, parentPath(normalizedPath)).get().isPresent();
287             } catch (InterruptedException | ExecutionException e) {
288                 throw new IllegalStateException(e);
289             }
290         }
291
292         @Override
293         public void removeConfigurationData(final InstanceIdentifier legacyPath) {
294             checkNotNull(legacyPath, "Path MUST NOT be null.");
295             getDelegate().delete(LogicalDatastoreType.CONFIGURATION, getNormalizer().toNormalized(legacyPath));
296         }
297
298         @Override
299         public void removeOperationalData(final InstanceIdentifier legacyPath) {
300             checkNotNull(legacyPath, "Path MUST NOT be null.");
301             getDelegate().delete(LogicalDatastoreType.OPERATIONAL, getNormalizer().toNormalized(legacyPath));
302         }
303     }
304 }