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.nb.rfc8040.handlers.TransactionChainHandler;
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.
56 * @param transactionNode
57 * wrapper for transaction data
58 * @param schemaContextRef
59 * reference to actual {@link SchemaContext}
64 * @return {@link Response}
66 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
67 final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
69 final FluentFuture<? extends CommitInfo> future = submitData(
70 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
71 transactionNode, schemaContextRef.get(), insert, point);
72 final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
73 final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
74 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
75 return dataFactory.build();
85 * @param transactionNode
86 * wrapper for data to transaction
87 * @param schemaContext
88 * schema context of data
93 * @return {@link FluentFuture}
95 private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
96 final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
97 final SchemaContext schemaContext, final String insert, final String point) {
98 final DOMTransactionChain domTransactionChain = transactionNode.getTransactionChain();
99 final DOMDataTreeReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction();
100 if (insert == null) {
101 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(), newReadWriteTransaction);
102 return newReadWriteTransaction.commit();
104 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
107 if (schemaNode instanceof ListSchemaNode) {
108 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
109 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
110 final OrderedMapNode readList = (OrderedMapNode) readData;
111 if (readList == null || readList.getValue().isEmpty()) {
112 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
113 newReadWriteTransaction);
114 return newReadWriteTransaction.commit();
116 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
117 path.getParent().getParent());
118 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
119 schemaContext, transactionNode.getTransactionChainHandler());
120 makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
121 newReadWriteTransaction);
122 return newReadWriteTransaction.commit();
125 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
126 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
128 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
129 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
130 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
131 newReadWriteTransaction);
132 return newReadWriteTransaction.commit();
134 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
135 path.getParent().getParent());
136 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
137 schemaContext, transactionNode.getTransactionChainHandler());
138 makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
139 newReadWriteTransaction);
140 return newReadWriteTransaction.commit();
144 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
145 newReadWriteTransaction);
146 return newReadWriteTransaction.commit();
148 if (schemaNode instanceof ListSchemaNode) {
149 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
150 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
151 final OrderedMapNode readList = (OrderedMapNode) readData;
152 if (readList == null || readList.getValue().isEmpty()) {
153 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
154 newReadWriteTransaction);
155 return newReadWriteTransaction.commit();
157 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
158 data, schemaContext, point, readList, true,
159 transactionNode.getTransactionChainHandler());
160 return newReadWriteTransaction.commit();
163 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
164 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
166 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
167 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
168 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
169 newReadWriteTransaction);
170 return newReadWriteTransaction.commit();
172 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
173 path, data, schemaContext, point, readLeafList, true,
174 transactionNode.getTransactionChainHandler());
175 return newReadWriteTransaction.commit();
179 if (schemaNode instanceof ListSchemaNode) {
180 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
181 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
182 final OrderedMapNode readList = (OrderedMapNode) readData;
183 if (readList == null || readList.getValue().isEmpty()) {
184 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
185 newReadWriteTransaction);
186 return newReadWriteTransaction.commit();
188 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
189 data, schemaContext, point, readList, false,
190 transactionNode.getTransactionChainHandler());
191 return newReadWriteTransaction.commit();
194 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
195 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
197 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
198 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
199 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
200 newReadWriteTransaction);
201 return newReadWriteTransaction.commit();
203 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
204 path, data, schemaContext, point, readLeafList, true,
205 transactionNode.getTransactionChainHandler());
206 return newReadWriteTransaction.commit();
210 throw new RestconfDocumentedException(
211 "Used bad value of insert parameter. Possible values are first, last, before or after, "
212 + "but was: " + insert);
217 private static void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
218 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
219 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
220 final boolean before, final TransactionChainHandler transactionChainHandler) {
221 rwTransaction.delete(datastore, path.getParent().getParent());
222 final InstanceIdentifierContext<?> instanceIdentifier =
223 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
224 int lastItemPosition = 0;
225 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
226 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
234 int lastInsertedPosition = 0;
235 final NormalizedNode<?, ?> emptySubtree =
236 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
237 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
238 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
239 if (lastInsertedPosition == lastItemPosition) {
240 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
241 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
242 rwTransaction.put(datastore, path, payload);
244 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
245 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, childPath,
246 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
247 rwTransaction.put(datastore, childPath, nodeChild);
248 lastInsertedPosition++;
252 private static void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
253 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
254 final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
255 final TransactionChainHandler transactionChainHandler) {
256 rwTransaction.delete(datastore, path.getParent().getParent());
257 final InstanceIdentifierContext<?> instanceIdentifier =
258 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
259 int lastItemPosition = 0;
260 for (final MapEntryNode mapEntryNode : readList.getValue()) {
261 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
269 int lastInsertedPosition = 0;
270 final NormalizedNode<?, ?> emptySubtree =
271 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
272 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
273 for (final MapEntryNode mapEntryNode : readList.getValue()) {
274 if (lastInsertedPosition == lastItemPosition) {
275 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
276 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
277 rwTransaction.put(datastore, path, payload);
279 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
280 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, childPath,
281 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
282 rwTransaction.put(datastore, childPath, mapEntryNode);
283 lastInsertedPosition++;
287 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
288 final SchemaContext schemaContext, final TransactionChainHandler transactionChainHandler,
289 final DOMDataTreeReadWriteTransaction transaction) {
290 if (data instanceof MapNode) {
291 boolean merge = false;
292 for (final MapEntryNode child : ((MapNode) data).getValue()) {
293 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
294 TransactionUtil.checkItemDoesNotExists(
295 transactionChainHandler, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
296 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
299 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
300 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
301 transaction.merge(LogicalDatastoreType.CONFIGURATION,
302 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
304 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
307 TransactionUtil.checkItemDoesNotExists(
308 transactionChainHandler, transaction, LogicalDatastoreType.CONFIGURATION, path,
309 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
311 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
312 transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
317 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
321 * @param transactionNode
322 * wrapper for data of transaction
323 * @param schemaContextRef
324 * reference to {@link SchemaContext}
325 * @return {@link URI}
327 private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
328 final SchemaContextRef schemaContextRef) {
329 if (uriInfo == null) {
333 final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
334 uriBuilder.path("data");
335 uriBuilder.path(ParserIdentifier
336 .stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
337 schemaContextRef.get()));
339 return uriBuilder.build();
342 private static void simplePost(final DOMDataTreeReadWriteTransaction rwTransaction,
343 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
344 final SchemaContext schemaContext, final TransactionChainHandler transactionChainHandler) {
345 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
346 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
347 TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
348 rwTransaction.put(datastore, path, payload);