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.EffectiveModelContext;
38 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 * Util class to post data to DS.
45 public final class PostDataTransactionUtil {
46 private PostDataTransactionUtil() {
47 throw new UnsupportedOperationException("Util class.");
51 * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} inside of object
52 * {@link TransactionVarsWrapper} provided as a parameter.
58 * @param transactionNode
59 * wrapper for transaction data
60 * @param schemaContextRef
61 * reference to actual {@link SchemaContext}
66 * @return {@link Response}
68 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
69 final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
71 final FluentFuture<? extends CommitInfo> future = submitData(
72 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
73 transactionNode, schemaContextRef.get(), insert, point);
74 final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
75 final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
76 //This method will close transactionChain
77 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory,
78 transactionNode.getTransactionChain());
79 return dataFactory.build();
89 * @param transactionNode
90 * wrapper for data to transaction
91 * @param schemaContext
92 * schema context of data
97 * @return {@link FluentFuture}
99 private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
100 final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
101 final EffectiveModelContext schemaContext, final String insert, final String point) {
102 final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
103 final DOMDataTreeReadWriteTransaction newReadWriteTransaction = transactionChain.newReadWriteTransaction();
104 if (insert == null) {
105 makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
106 return newReadWriteTransaction.commit();
108 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
111 if (schemaNode instanceof ListSchemaNode) {
112 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
113 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
114 final OrderedMapNode readList = (OrderedMapNode) readData;
115 if (readList == null || readList.getValue().isEmpty()) {
116 makePost(path, data, schemaContext, transactionChain,
117 newReadWriteTransaction);
118 return newReadWriteTransaction.commit();
120 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
121 path.getParent().getParent());
122 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
123 schemaContext, transactionChain);
124 makePost(path, readData, schemaContext, transactionChain,
125 newReadWriteTransaction);
126 return newReadWriteTransaction.commit();
129 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
130 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
132 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
133 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
134 makePost(path, data, schemaContext, transactionChain,
135 newReadWriteTransaction);
136 return newReadWriteTransaction.commit();
138 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
139 path.getParent().getParent());
140 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
141 schemaContext, transactionChain);
142 makePost(path, readData, schemaContext, transactionChain,
143 newReadWriteTransaction);
144 return newReadWriteTransaction.commit();
148 makePost(path, data, schemaContext, transactionChain,
149 newReadWriteTransaction);
150 return newReadWriteTransaction.commit();
152 if (schemaNode instanceof ListSchemaNode) {
153 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
154 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
155 final OrderedMapNode readList = (OrderedMapNode) readData;
156 if (readList == null || readList.getValue().isEmpty()) {
157 makePost(path, data, schemaContext, transactionChain,
158 newReadWriteTransaction);
159 return newReadWriteTransaction.commit();
161 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
162 data, schemaContext, point, readList, true,
164 return newReadWriteTransaction.commit();
167 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
168 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
170 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
171 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
172 makePost(path, data, schemaContext, transactionChain,
173 newReadWriteTransaction);
174 return newReadWriteTransaction.commit();
176 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
177 path, data, schemaContext, point, readLeafList, true,
179 return newReadWriteTransaction.commit();
183 if (schemaNode instanceof ListSchemaNode) {
184 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
185 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
186 final OrderedMapNode readList = (OrderedMapNode) readData;
187 if (readList == null || readList.getValue().isEmpty()) {
188 makePost(path, data, schemaContext, transactionChain,
189 newReadWriteTransaction);
190 return newReadWriteTransaction.commit();
192 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
193 data, schemaContext, point, readList, false,
195 return newReadWriteTransaction.commit();
198 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
199 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
201 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
202 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
203 makePost(path, data, schemaContext, transactionChain,
204 newReadWriteTransaction);
205 return newReadWriteTransaction.commit();
207 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
208 path, data, schemaContext, point, readLeafList, true,
210 return newReadWriteTransaction.commit();
214 throw new RestconfDocumentedException(
215 "Used bad value of insert parameter. Possible values are first, last, before or after, "
216 + "but was: " + insert, RestconfError.ErrorType.PROTOCOL,
217 RestconfError.ErrorTag.BAD_ATTRIBUTE);
222 private static void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
223 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
224 final EffectiveModelContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
225 final boolean before, final DOMTransactionChain transactionChain) {
226 rwTransaction.delete(datastore, path.getParent().getParent());
227 final InstanceIdentifierContext<?> instanceIdentifier =
228 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
229 int lastItemPosition = 0;
230 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
231 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
239 int lastInsertedPosition = 0;
240 final NormalizedNode<?, ?> emptySubtree =
241 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
242 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
243 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
244 if (lastInsertedPosition == lastItemPosition) {
245 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
246 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
247 rwTransaction.put(datastore, path, payload);
249 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
250 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
251 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
252 rwTransaction.put(datastore, childPath, nodeChild);
253 lastInsertedPosition++;
257 private static void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
258 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
259 final EffectiveModelContext schemaContext, final String point, final MapNode readList, final boolean before,
260 final DOMTransactionChain transactionChain) {
261 rwTransaction.delete(datastore, path.getParent().getParent());
262 final InstanceIdentifierContext<?> instanceIdentifier =
263 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
264 int lastItemPosition = 0;
265 for (final MapEntryNode mapEntryNode : readList.getValue()) {
266 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
274 int lastInsertedPosition = 0;
275 final NormalizedNode<?, ?> emptySubtree =
276 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
277 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
278 for (final MapEntryNode mapEntryNode : readList.getValue()) {
279 if (lastInsertedPosition == lastItemPosition) {
280 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
281 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
282 rwTransaction.put(datastore, path, payload);
284 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
285 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
286 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
287 rwTransaction.put(datastore, childPath, mapEntryNode);
288 lastInsertedPosition++;
292 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
293 final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
294 final DOMDataTreeReadWriteTransaction transaction) {
295 if (data instanceof MapNode) {
296 boolean merge = false;
297 for (final MapEntryNode child : ((MapNode) data).getValue()) {
298 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
299 TransactionUtil.checkItemDoesNotExists(
300 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
301 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
304 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
305 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
306 transaction.merge(LogicalDatastoreType.CONFIGURATION,
307 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
309 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
312 TransactionUtil.checkItemDoesNotExists(
313 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
314 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
316 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
317 transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
322 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
326 * @param transactionNode
327 * wrapper for data of transaction
328 * @param schemaContextRef
329 * reference to {@link SchemaContext}
330 * @return {@link URI}
332 private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
333 final SchemaContextRef schemaContextRef) {
334 if (uriInfo == null) {
338 final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
339 uriBuilder.path("data");
340 uriBuilder.path(ParserIdentifier
341 .stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
342 schemaContextRef.get()));
344 return uriBuilder.build();
347 private static void simplePost(final DOMDataTreeReadWriteTransaction rwTransaction,
348 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
349 final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
350 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
351 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
352 TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
353 rwTransaction.put(datastore, path, payload);