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.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
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.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
19 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
20 import org.opendaylight.controller.md.sal.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;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * Util class to post data to DS.
46 public final class PostDataTransactionUtil {
48 private static final Logger LOG = LoggerFactory.getLogger(PostDataTransactionUtil.class);
50 private PostDataTransactionUtil() {
51 throw new UnsupportedOperationException("Util class.");
55 * Check mount point and prepare variables for post data.
61 * @param transactionNode
62 * wrapper for transaction data
63 * @param schemaContextRef
64 * reference to actual {@link SchemaContext}
69 * @return {@link CheckedFuture}
71 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
72 final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
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(Status.CREATED).location(location);
79 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
80 return dataFactory.build();
90 * @param transactionNode
91 * wrapper for data to transaction
92 * @param schemaContext
93 * schema context of data
98 * @return {@link CheckedFuture}
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, transactionNode.getTransactionChainHandler(), newReadWriteTransaction);
107 return newReadWriteTransaction.submit();
109 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
112 if (schemaNode instanceof ListSchemaNode) {
113 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
114 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
115 final OrderedMapNode readList = (OrderedMapNode) readData;
116 if (readList == null || readList.getValue().isEmpty()) {
117 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
118 newReadWriteTransaction);
119 return newReadWriteTransaction.submit();
121 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
122 path.getParent().getParent());
123 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
124 schemaContext, transactionNode.getTransactionChainHandler());
125 makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
126 newReadWriteTransaction);
127 return newReadWriteTransaction.submit();
130 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
131 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
133 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
134 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
135 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
136 newReadWriteTransaction);
137 return newReadWriteTransaction.submit();
139 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
140 path.getParent().getParent());
141 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
142 schemaContext, transactionNode.getTransactionChainHandler());
143 makePost(path, readData, schemaContext, transactionNode.getTransactionChainHandler(),
144 newReadWriteTransaction);
145 return newReadWriteTransaction.submit();
149 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
150 newReadWriteTransaction);
151 return newReadWriteTransaction.submit();
153 if (schemaNode instanceof ListSchemaNode) {
154 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
155 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
156 final OrderedMapNode readList = (OrderedMapNode) readData;
157 if (readList == null || readList.getValue().isEmpty()) {
158 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
159 newReadWriteTransaction);
160 return newReadWriteTransaction.submit();
162 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
163 data, schemaContext, point, readList, true,
164 transactionNode.getTransactionChainHandler());
165 return newReadWriteTransaction.submit();
168 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
169 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
171 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
172 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
173 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
174 newReadWriteTransaction);
175 return newReadWriteTransaction.submit();
177 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
178 path, data, schemaContext, point, readLeafList, true,
179 transactionNode.getTransactionChainHandler());
180 return newReadWriteTransaction.submit();
184 if (schemaNode instanceof ListSchemaNode) {
185 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
186 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
187 final OrderedMapNode readList = (OrderedMapNode) readData;
188 if (readList == null || readList.getValue().isEmpty()) {
189 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
190 newReadWriteTransaction);
191 return newReadWriteTransaction.submit();
193 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
194 data, schemaContext, point, readList, false,
195 transactionNode.getTransactionChainHandler());
196 return newReadWriteTransaction.submit();
199 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
200 schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
202 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
203 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
204 makePost(path, data, schemaContext, transactionNode.getTransactionChainHandler(),
205 newReadWriteTransaction);
206 return newReadWriteTransaction.submit();
208 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
209 path, data, schemaContext, point, readLeafList, true,
210 transactionNode.getTransactionChainHandler());
211 return newReadWriteTransaction.submit();
215 throw new RestconfDocumentedException(
216 "Used bad value of insert parameter. Possible values are first, last, before or after, "
217 + "but was: " + insert);
222 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
223 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
224 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
225 final boolean before, final TransactionChainHandler transactionChainHandler) {
226 rwTransaction.delete(datastore, path.getParent().getParent());
227 final InstanceIdentifierContext<?> instanceIdentifier =
228 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.absent());
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(transactionChainHandler, 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(transactionChainHandler, rwTransaction, datastore, childPath,
251 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
252 rwTransaction.put(datastore, childPath, nodeChild);
253 lastInsertedPosition++;
257 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
258 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
259 final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
260 final TransactionChainHandler transactionChainHandler) {
261 rwTransaction.delete(datastore, path.getParent().getParent());
262 final InstanceIdentifierContext<?> instanceIdentifier =
263 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.absent());
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(transactionChainHandler, 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(transactionChainHandler, 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 TransactionChainHandler transactionChainHandler,
294 final DOMDataReadWriteTransaction 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 transactionChainHandler, 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 transactionChainHandler, 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 DOMDataReadWriteTransaction rwTransaction,
348 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
349 final SchemaContext schemaContext, final TransactionChainHandler transactionChainHandler) {
350 TransactionUtil.checkItemDoesNotExists(transactionChainHandler, rwTransaction, datastore, path,
351 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
352 TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
353 rwTransaction.put(datastore, path, payload);