2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
10 import com.google.common.util.concurrent.FluentFuture;
12 import java.util.Optional;
13 import javax.ws.rs.core.Response;
14 import javax.ws.rs.core.Response.Status;
15 import javax.ws.rs.core.UriBuilder;
16 import javax.ws.rs.core.UriInfo;
17 import org.opendaylight.mdsal.common.api.CommitInfo;
18 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
19 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
20 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
21 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
22 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
23 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
24 import org.opendaylight.restconf.common.errors.RestconfError;
25 import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
26 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
27 import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
35 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
36 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
41 * Util class to post data to DS.
44 public final class PostDataTransactionUtil {
45 private PostDataTransactionUtil() {
46 throw new UnsupportedOperationException("Util class.");
50 * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} inside of object
51 * {@link TransactionVarsWrapper} provided as a parameter.
57 * @param transactionNode
58 * wrapper for transaction data
59 * @param schemaContextRef
60 * reference to actual {@link SchemaContext}
65 * @return {@link Response}
67 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
68 final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
70 final FluentFuture<? extends CommitInfo> future = submitData(
71 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
72 transactionNode, schemaContextRef.get(), insert, point);
73 final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
74 final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
75 //This method will close transactionChain
76 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory,
77 transactionNode.getTransactionChain());
78 return dataFactory.build();
88 * @param transactionNode
89 * wrapper for data to transaction
90 * @param schemaContext
91 * schema context of data
96 * @return {@link FluentFuture}
98 private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
99 final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
100 final SchemaContext schemaContext, final String insert, final String point) {
101 final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
102 final DOMDataTreeReadWriteTransaction newReadWriteTransaction = transactionChain.newReadWriteTransaction();
103 if (insert == null) {
104 makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
105 return newReadWriteTransaction.commit();
107 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
110 if (schemaNode instanceof ListSchemaNode) {
111 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
112 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
113 final OrderedMapNode readList = (OrderedMapNode) readData;
114 if (readList == null || readList.getValue().isEmpty()) {
115 makePost(path, data, schemaContext, transactionChain,
116 newReadWriteTransaction);
117 return newReadWriteTransaction.commit();
119 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
120 path.getParent().getParent());
121 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
122 schemaContext, transactionChain);
123 makePost(path, readData, schemaContext, transactionChain,
124 newReadWriteTransaction);
125 return newReadWriteTransaction.commit();
128 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
129 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
131 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
132 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
133 makePost(path, data, schemaContext, transactionChain,
134 newReadWriteTransaction);
135 return newReadWriteTransaction.commit();
137 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
138 path.getParent().getParent());
139 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
140 schemaContext, transactionChain);
141 makePost(path, readData, schemaContext, transactionChain,
142 newReadWriteTransaction);
143 return newReadWriteTransaction.commit();
147 makePost(path, data, schemaContext, transactionChain,
148 newReadWriteTransaction);
149 return newReadWriteTransaction.commit();
151 if (schemaNode instanceof ListSchemaNode) {
152 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
153 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
154 final OrderedMapNode readList = (OrderedMapNode) readData;
155 if (readList == null || readList.getValue().isEmpty()) {
156 makePost(path, data, schemaContext, transactionChain,
157 newReadWriteTransaction);
158 return newReadWriteTransaction.commit();
160 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
161 data, schemaContext, point, readList, true,
163 return newReadWriteTransaction.commit();
166 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
167 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
169 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
170 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
171 makePost(path, data, schemaContext, transactionChain,
172 newReadWriteTransaction);
173 return newReadWriteTransaction.commit();
175 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
176 path, data, schemaContext, point, readLeafList, true,
178 return newReadWriteTransaction.commit();
182 if (schemaNode instanceof ListSchemaNode) {
183 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
184 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
185 final OrderedMapNode readList = (OrderedMapNode) readData;
186 if (readList == null || readList.getValue().isEmpty()) {
187 makePost(path, data, schemaContext, transactionChain,
188 newReadWriteTransaction);
189 return newReadWriteTransaction.commit();
191 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
192 data, schemaContext, point, readList, false,
194 return newReadWriteTransaction.commit();
197 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
198 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
200 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
201 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
202 makePost(path, data, schemaContext, transactionChain,
203 newReadWriteTransaction);
204 return newReadWriteTransaction.commit();
206 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
207 path, data, schemaContext, point, readLeafList, true,
209 return newReadWriteTransaction.commit();
213 throw new RestconfDocumentedException(
214 "Used bad value of insert parameter. Possible values are first, last, before or after, "
215 + "but was: " + insert, RestconfError.ErrorType.PROTOCOL,
216 RestconfError.ErrorTag.BAD_ATTRIBUTE);
221 private static void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
222 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
223 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
224 final boolean before, final DOMTransactionChain transactionChain) {
225 rwTransaction.delete(datastore, path.getParent().getParent());
226 final InstanceIdentifierContext<?> instanceIdentifier =
227 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
228 int lastItemPosition = 0;
229 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
230 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
238 int lastInsertedPosition = 0;
239 final NormalizedNode<?, ?> emptySubtree =
240 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
241 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
242 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
243 if (lastInsertedPosition == lastItemPosition) {
244 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
245 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
246 rwTransaction.put(datastore, path, payload);
248 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
249 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
250 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
251 rwTransaction.put(datastore, childPath, nodeChild);
252 lastInsertedPosition++;
256 private static void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
257 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
258 final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
259 final DOMTransactionChain transactionChain) {
260 rwTransaction.delete(datastore, path.getParent().getParent());
261 final InstanceIdentifierContext<?> instanceIdentifier =
262 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
263 int lastItemPosition = 0;
264 for (final MapEntryNode mapEntryNode : readList.getValue()) {
265 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
273 int lastInsertedPosition = 0;
274 final NormalizedNode<?, ?> emptySubtree =
275 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
276 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
277 for (final MapEntryNode mapEntryNode : readList.getValue()) {
278 if (lastInsertedPosition == lastItemPosition) {
279 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
280 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
281 rwTransaction.put(datastore, path, payload);
283 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
284 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
285 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
286 rwTransaction.put(datastore, childPath, mapEntryNode);
287 lastInsertedPosition++;
291 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
292 final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
293 final DOMDataTreeReadWriteTransaction transaction) {
294 if (data instanceof MapNode) {
295 boolean merge = false;
296 for (final MapEntryNode child : ((MapNode) data).getValue()) {
297 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
298 TransactionUtil.checkItemDoesNotExists(
299 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
300 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
303 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
304 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
305 transaction.merge(LogicalDatastoreType.CONFIGURATION,
306 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
308 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
311 TransactionUtil.checkItemDoesNotExists(
312 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
313 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
315 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
316 transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
321 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
325 * @param transactionNode
326 * wrapper for data of transaction
327 * @param schemaContextRef
328 * reference to {@link SchemaContext}
329 * @return {@link URI}
331 private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
332 final SchemaContextRef schemaContextRef) {
333 if (uriInfo == null) {
337 final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
338 uriBuilder.path("data");
339 uriBuilder.path(ParserIdentifier
340 .stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
341 schemaContextRef.get()));
343 return uriBuilder.build();
346 private static void simplePost(final DOMDataTreeReadWriteTransaction rwTransaction,
347 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
348 final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
349 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
350 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
351 TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
352 rwTransaction.put(datastore, path, payload);