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