Split Restconf implementations (draft02 and RFC) - Application
[netconf.git] / restconf / restconf-nb-bierman02 / src / main / java / org / opendaylight / restconf / restful / utils / PostDataTransactionUtil.java
1 /*
2  * Copyright (c) 2016 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.restconf.restful.utils;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
12 import java.net.URI;
13 import javax.ws.rs.core.Response;
14 import javax.ws.rs.core.UriBuilder;
15 import javax.ws.rs.core.UriInfo;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
18 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
20 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
21 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
22 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
23 import org.opendaylight.restconf.common.references.SchemaContextRef;
24 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
25 import org.opendaylight.restconf.utils.parser.ParserIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
33 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Util class to post data to DS.
42  *
43  * @deprecated move to splitted module restconf-nb-rfc8040
44  */
45 @Deprecated
46 public final class PostDataTransactionUtil {
47
48     private static final Logger LOG = LoggerFactory.getLogger(PostDataTransactionUtil.class);
49
50     private PostDataTransactionUtil() {
51         throw new UnsupportedOperationException("Util class.");
52     }
53
54     /**
55      * Check mount point and prepare variables for post data.
56      *
57      * @param uriInfo
58      *
59      * @param payload
60      *             data
61      * @param transactionNode
62      *             wrapper for transaction data
63      * @param schemaContextRef
64      *             reference to actual {@link SchemaContext}
65      * @param point
66      *             point
67      * @param insert
68      *             insert
69      * @return {@link CheckedFuture}
70      */
71     public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
72             final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
73             final String point) {
74         final CheckedFuture<Void, TransactionCommitFailedException> future = submitData(
75                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
76                 transactionNode, schemaContextRef.get(), insert, point);
77         final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
78         final ResponseFactory dataFactory = new ResponseFactory(null, location);
79         FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
80         return dataFactory.build();
81     }
82
83     /**
84      * Post data by type.
85      *
86      * @param path
87      *             path
88      * @param data
89      *             data
90      * @param transactionNode
91      *             wrapper for data to transaction
92      * @param schemaContext
93      *             schema context of data
94      * @param point
95      *             query parameter
96      * @param insert
97      *             query parameter
98      * @return {@link CheckedFuture}
99      */
100     private static CheckedFuture<Void, TransactionCommitFailedException> submitData(final YangInstanceIdentifier path,
101             final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
102             final SchemaContext schemaContext, final String insert, final String point) {
103         final DOMTransactionChain domTransactionChain = transactionNode.getTransactionChain();
104         final DOMDataReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction();
105         if (insert == null) {
106             makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
107             return newReadWriteTransaction.submit();
108         } else {
109             final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
110             switch (insert) {
111                 case "first":
112                     if (schemaNode instanceof ListSchemaNode) {
113                         final NormalizedNode<?, ?> readData =
114                                 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
115                                         schemaNode);
116                         final OrderedMapNode readList = (OrderedMapNode) readData;
117                         if ((readList == null) || readList.getValue().isEmpty()) {
118                             makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
119                             return newReadWriteTransaction.submit();
120                         } else {
121                             newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
122                                     path.getParent().getParent());
123                             simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
124                                     schemaContext, domTransactionChain);
125                             makePost(path, readData, schemaContext, domTransactionChain,
126                                     newReadWriteTransaction);
127                             return newReadWriteTransaction.submit();
128                         }
129                     } else {
130                         final NormalizedNode<?, ?> readData = PutDataTransactionUtil
131                                         .readList(path.getParent(), schemaContext, domTransactionChain, schemaNode);
132
133                         final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
134                         if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
135                             makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
136                             return newReadWriteTransaction.submit();
137                         } else {
138                             newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
139                                     path.getParent().getParent());
140                             simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
141                                     schemaContext, domTransactionChain);
142                             makePost(path, readData, schemaContext, domTransactionChain, newReadWriteTransaction);
143                             return newReadWriteTransaction.submit();
144                         }
145                     }
146                 case "last":
147                     makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
148                     return newReadWriteTransaction.submit();
149                 case "before":
150                     if (schemaNode instanceof ListSchemaNode) {
151                         final NormalizedNode<?, ?> readData =
152                                 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
153                                         schemaNode);
154                         final OrderedMapNode readList = (OrderedMapNode) readData;
155                         if ((readList == null) || readList.getValue().isEmpty()) {
156                             makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
157                             return newReadWriteTransaction.submit();
158                         } else {
159                             insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
160                                     data, schemaContext, point, readList, true, domTransactionChain);
161                             return newReadWriteTransaction.submit();
162                         }
163                     } else {
164                         final NormalizedNode<?, ?> readData =
165                                 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
166                                         schemaNode);
167
168                         final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
169                         if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
170                             makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
171                             return newReadWriteTransaction.submit();
172                         } else {
173                             insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
174                                     path, data, schemaContext, point, readLeafList, true, domTransactionChain);
175                             return newReadWriteTransaction.submit();
176                         }
177                     }
178                 case "after":
179                     if (schemaNode instanceof ListSchemaNode) {
180                         final NormalizedNode<?, ?> readData =
181                                 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
182                                         schemaNode);
183                         final OrderedMapNode readList = (OrderedMapNode) readData;
184                         if ((readList == null) || readList.getValue().isEmpty()) {
185                             makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
186                             return newReadWriteTransaction.submit();
187                         } else {
188                             insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
189                                     data, schemaContext, point, readList, false, domTransactionChain);
190                             return newReadWriteTransaction.submit();
191                         }
192                     } else {
193                         final NormalizedNode<?, ?> readData =
194                                 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
195                                         schemaNode);
196
197                         final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
198                         if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
199                             makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
200                             return newReadWriteTransaction.submit();
201                         } else {
202                             insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
203                                     path, data, schemaContext, point, readLeafList, true, domTransactionChain);
204                             return newReadWriteTransaction.submit();
205                         }
206                     }
207                 default:
208                     throw new RestconfDocumentedException(
209                             "Used bad value of insert parameter. Possible values are first, last, before or after, "
210                                     + "but was: " + insert);
211             }
212         }
213     }
214
215     private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
216             final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
217             final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
218             final boolean before, final DOMTransactionChain domTransactionChain) {
219         rwTransaction.delete(datastore, path.getParent().getParent());
220         final InstanceIdentifierContext<?> instanceIdentifier =
221                 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.absent());
222         int lastItemPosition = 0;
223         for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
224             if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
225                 break;
226             }
227             lastItemPosition++;
228         }
229         if (!before) {
230             lastItemPosition++;
231         }
232         int lastInsertedPosition = 0;
233         final NormalizedNode<?, ?> emptySubtree =
234                 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
235         rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
236         for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
237             if (lastInsertedPosition == lastItemPosition) {
238                 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, path,
239                         RestconfDataServiceConstant.PostData.POST_TX_TYPE);
240                 rwTransaction.put(datastore, path, payload);
241             }
242             final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
243             TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, childPath,
244                     RestconfDataServiceConstant.PostData.POST_TX_TYPE);
245             rwTransaction.put(datastore, childPath, nodeChild);
246             lastInsertedPosition++;
247         }
248     }
249
250     private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
251             final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
252             final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
253             final DOMTransactionChain domTransactionChain) {
254         rwTransaction.delete(datastore, path.getParent().getParent());
255         final InstanceIdentifierContext<?> instanceIdentifier =
256                 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.absent());
257         int lastItemPosition = 0;
258         for (final MapEntryNode mapEntryNode : readList.getValue()) {
259             if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
260                 break;
261             }
262             lastItemPosition++;
263         }
264         if (!before) {
265             lastItemPosition++;
266         }
267         int lastInsertedPosition = 0;
268         final NormalizedNode<?, ?> emptySubtree =
269                 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
270         rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
271         for (final MapEntryNode mapEntryNode : readList.getValue()) {
272             if (lastInsertedPosition == lastItemPosition) {
273                 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, path,
274                         RestconfDataServiceConstant.PostData.POST_TX_TYPE);
275                 rwTransaction.put(datastore, path, payload);
276             }
277             final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
278             TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, childPath,
279                     RestconfDataServiceConstant.PostData.POST_TX_TYPE);
280             rwTransaction.put(datastore, childPath, mapEntryNode);
281             lastInsertedPosition++;
282         }
283     }
284
285     private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
286             final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
287             final DOMDataReadWriteTransaction transaction) {
288         if (data instanceof MapNode) {
289             boolean merge = false;
290             for (final MapEntryNode child : ((MapNode) data).getValue()) {
291                 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
292                 TransactionUtil.checkItemDoesNotExists(
293                         transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
294                         RestconfDataServiceConstant.PostData.POST_TX_TYPE);
295                 if (!merge) {
296                     merge = true;
297                     TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
298                     final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
299                     transaction.merge(LogicalDatastoreType.CONFIGURATION,
300                             YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
301                 }
302                 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
303             }
304         } else {
305             TransactionUtil.checkItemDoesNotExists(
306                     transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
307                     RestconfDataServiceConstant.PostData.POST_TX_TYPE);
308
309             TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
310             transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
311         }
312     }
313
314     /**
315      * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
316      *
317      * @param uriInfo
318      *             uri info
319      * @param transactionNode
320      *             wrapper for data of transaction
321      * @param schemaContextRef
322      *            reference to {@link SchemaContext}
323      * @return {@link URI}
324      */
325     private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
326             final SchemaContextRef schemaContextRef) {
327         if (uriInfo == null) {
328             return null;
329         }
330
331         final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
332         uriBuilder.path("data");
333         uriBuilder.path(ParserIdentifier
334                 .stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
335                 schemaContextRef.get()));
336
337         return uriBuilder.build();
338     }
339
340     private static void simplePost(final DOMDataReadWriteTransaction rwTransaction,
341             final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
342             final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
343         TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
344                 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
345         TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
346         rwTransaction.put(datastore, path, payload);
347     }
348 }