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.handlers.TransactionChainHandler;
26 import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
27 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
28 import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
36 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
37 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
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.
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 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
76 return dataFactory.build();
86 * @param transactionNode
87 * wrapper for data to transaction
88 * @param schemaContext
89 * schema context of data
94 * @return {@link FluentFuture}
96 private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
97 final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
98 final SchemaContext schemaContext, final String insert, final String point) {
99 final DOMTransactionChain domTransactionChain = transactionNode.getTransactionChain();
100 final DOMDataTreeReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction();
101 if (insert == null) {
102 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(), newReadWriteTransaction);
103 return newReadWriteTransaction.commit();
105 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
108 if (schemaNode instanceof ListSchemaNode) {
109 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
110 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
111 final OrderedMapNode readList = (OrderedMapNode) readData;
112 if (readList == null || readList.getValue().isEmpty()) {
113 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
114 newReadWriteTransaction);
115 return newReadWriteTransaction.commit();
117 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
118 path.getParent().getParent());
119 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
120 schemaContext, transactionNode.getTransactionChainHandler());
121 makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
122 newReadWriteTransaction);
123 return newReadWriteTransaction.commit();
126 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
127 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
129 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
130 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
131 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
132 newReadWriteTransaction);
133 return newReadWriteTransaction.commit();
135 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
136 path.getParent().getParent());
137 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
138 schemaContext, transactionNode.getTransactionChainHandler());
139 makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
140 newReadWriteTransaction);
141 return newReadWriteTransaction.commit();
145 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
146 newReadWriteTransaction);
147 return newReadWriteTransaction.commit();
149 if (schemaNode instanceof ListSchemaNode) {
150 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
151 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
152 final OrderedMapNode readList = (OrderedMapNode) readData;
153 if (readList == null || readList.getValue().isEmpty()) {
154 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
155 newReadWriteTransaction);
156 return newReadWriteTransaction.commit();
158 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
159 data, schemaContext, point, readList, true,
160 transactionNode.getTransactionChainHandler());
161 return newReadWriteTransaction.commit();
164 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
165 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
167 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
168 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
169 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
170 newReadWriteTransaction);
171 return newReadWriteTransaction.commit();
173 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
174 path, data, schemaContext, point, readLeafList, true,
175 transactionNode.getTransactionChainHandler());
176 return newReadWriteTransaction.commit();
180 if (schemaNode instanceof ListSchemaNode) {
181 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
182 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
183 final OrderedMapNode readList = (OrderedMapNode) readData;
184 if (readList == null || readList.getValue().isEmpty()) {
185 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
186 newReadWriteTransaction);
187 return newReadWriteTransaction.commit();
189 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
190 data, schemaContext, point, readList, false,
191 transactionNode.getTransactionChainHandler());
192 return newReadWriteTransaction.commit();
195 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
196 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
198 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
199 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
200 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
201 newReadWriteTransaction);
202 return newReadWriteTransaction.commit();
204 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
205 path, data, schemaContext, point, readLeafList, true,
206 transactionNode.getTransactionChainHandler());
207 return newReadWriteTransaction.commit();
211 throw new RestconfDocumentedException(
212 "Used bad value of insert parameter. Possible values are first, last, before or after, "
213 + "but was: " + insert, RestconfError.ErrorType.PROTOCOL,
214 RestconfError.ErrorTag.BAD_ATTRIBUTE);
219 private static void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
220 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
221 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
222 final boolean before, final TransactionChainHandler transactionChainHandler) {
223 rwTransaction.delete(datastore, path.getParent().getParent());
224 final InstanceIdentifierContext<?> instanceIdentifier =
225 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
226 int lastItemPosition = 0;
227 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
228 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
236 int lastInsertedPosition = 0;
237 final NormalizedNode<?, ?> emptySubtree =
238 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
239 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
240 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
241 if (lastInsertedPosition == lastItemPosition) {
242 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
243 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
244 rwTransaction.put(datastore, path, payload);
246 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
247 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, childPath,
248 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
249 rwTransaction.put(datastore, childPath, nodeChild);
250 lastInsertedPosition++;
254 private static void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
255 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
256 final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
257 final TransactionChainHandler transactionChainHandler) {
258 rwTransaction.delete(datastore, path.getParent().getParent());
259 final InstanceIdentifierContext<?> instanceIdentifier =
260 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
261 int lastItemPosition = 0;
262 for (final MapEntryNode mapEntryNode : readList.getValue()) {
263 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
271 int lastInsertedPosition = 0;
272 final NormalizedNode<?, ?> emptySubtree =
273 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
274 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
275 for (final MapEntryNode mapEntryNode : readList.getValue()) {
276 if (lastInsertedPosition == lastItemPosition) {
277 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
278 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
279 rwTransaction.put(datastore, path, payload);
281 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
282 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, childPath,
283 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
284 rwTransaction.put(datastore, childPath, mapEntryNode);
285 lastInsertedPosition++;
289 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
290 final SchemaContext schemaContext, final TransactionChainHandler transactionChainHandler,
291 final DOMDataTreeReadWriteTransaction transaction) {
292 if (data instanceof MapNode) {
293 boolean merge = false;
294 for (final MapEntryNode child : ((MapNode) data).getValue()) {
295 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
296 TransactionUtil.checkItemDoesNotExists(
297 transactionChainHandler, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
298 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
301 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
302 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
303 transaction.merge(LogicalDatastoreType.CONFIGURATION,
304 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
306 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
309 TransactionUtil.checkItemDoesNotExists(
310 transactionChainHandler, transaction, LogicalDatastoreType.CONFIGURATION, path,
311 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
313 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
314 transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
319 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
323 * @param transactionNode
324 * wrapper for data of transaction
325 * @param schemaContextRef
326 * reference to {@link SchemaContext}
327 * @return {@link URI}
329 private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
330 final SchemaContextRef schemaContextRef) {
331 if (uriInfo == null) {
335 final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
336 uriBuilder.path("data");
337 uriBuilder.path(ParserIdentifier
338 .stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
339 schemaContextRef.get()));
341 return uriBuilder.build();
344 private static void simplePost(final DOMDataTreeReadWriteTransaction rwTransaction,
345 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
346 final SchemaContext schemaContext, final TransactionChainHandler transactionChainHandler) {
347 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
348 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
349 TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
350 rwTransaction.put(datastore, path, payload);