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.references.SchemaContextRef;
25 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
26 import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
34 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
35 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * Util class to post data to DS.
45 public final class PostDataTransactionUtil {
47 private static final Logger LOG = LoggerFactory.getLogger(PostDataTransactionUtil.class);
49 private PostDataTransactionUtil() {
50 throw new UnsupportedOperationException("Util class.");
54 * Check mount point and prepare variables for post data.
60 * @param transactionNode
61 * wrapper for transaction data
62 * @param schemaContextRef
63 * reference to actual {@link SchemaContext}
68 * @return {@link CheckedFuture}
70 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
71 final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
73 final CheckedFuture<Void, TransactionCommitFailedException> future = submitData(
74 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
75 transactionNode, schemaContextRef.get(), insert, point);
76 final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
77 final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
78 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
79 return dataFactory.build();
89 * @param transactionNode
90 * wrapper for data to transaction
91 * @param schemaContext
92 * schema context of data
97 * @return {@link CheckedFuture}
99 private static CheckedFuture<Void, TransactionCommitFailedException> submitData(final YangInstanceIdentifier path,
100 final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
101 final SchemaContext schemaContext, final String insert, final String point) {
102 final DOMTransactionChain domTransactionChain = transactionNode.getTransactionChain();
103 final DOMDataReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction();
104 if (insert == null) {
105 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
106 return newReadWriteTransaction.submit();
108 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
111 if (schemaNode instanceof ListSchemaNode) {
112 final NormalizedNode<?, ?> readData =
113 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
115 final OrderedMapNode readList = (OrderedMapNode) readData;
116 if (readList == null || readList.getValue().isEmpty()) {
117 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
118 return newReadWriteTransaction.submit();
120 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
121 path.getParent().getParent());
122 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
123 schemaContext, domTransactionChain);
124 makePost(path, readData, schemaContext, domTransactionChain,
125 newReadWriteTransaction);
126 return newReadWriteTransaction.submit();
129 final NormalizedNode<?, ?> readData = PutDataTransactionUtil
130 .readList(path.getParent(), schemaContext, domTransactionChain, schemaNode);
132 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
133 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
134 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
135 return newReadWriteTransaction.submit();
137 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
138 path.getParent().getParent());
139 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
140 schemaContext, domTransactionChain);
141 makePost(path, readData, schemaContext, domTransactionChain, newReadWriteTransaction);
142 return newReadWriteTransaction.submit();
146 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
147 return newReadWriteTransaction.submit();
149 if (schemaNode instanceof ListSchemaNode) {
150 final NormalizedNode<?, ?> readData =
151 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
153 final OrderedMapNode readList = (OrderedMapNode) readData;
154 if (readList == null || readList.getValue().isEmpty()) {
155 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
156 return newReadWriteTransaction.submit();
158 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
159 data, schemaContext, point, readList, true, domTransactionChain);
160 return newReadWriteTransaction.submit();
163 final NormalizedNode<?, ?> readData =
164 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
167 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
168 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
169 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
170 return newReadWriteTransaction.submit();
172 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
173 path, data, schemaContext, point, readLeafList, true, domTransactionChain);
174 return newReadWriteTransaction.submit();
178 if (schemaNode instanceof ListSchemaNode) {
179 final NormalizedNode<?, ?> readData =
180 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
182 final OrderedMapNode readList = (OrderedMapNode) readData;
183 if (readList == null || readList.getValue().isEmpty()) {
184 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
185 return newReadWriteTransaction.submit();
187 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
188 data, schemaContext, point, readList, false, domTransactionChain);
189 return newReadWriteTransaction.submit();
192 final NormalizedNode<?, ?> readData =
193 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
196 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
197 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
198 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
199 return newReadWriteTransaction.submit();
201 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
202 path, data, schemaContext, point, readLeafList, true, domTransactionChain);
203 return newReadWriteTransaction.submit();
207 throw new RestconfDocumentedException(
208 "Used bad value of insert parameter. Possible values are first, last, before or after, "
209 + "but was: " + insert);
214 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
215 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
216 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
217 final boolean before, final DOMTransactionChain domTransactionChain) {
218 rwTransaction.delete(datastore, path.getParent().getParent());
219 final InstanceIdentifierContext<?> instanceIdentifier =
220 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.absent());
221 int lastItemPosition = 0;
222 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
223 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
231 int lastInsertedPosition = 0;
232 final NormalizedNode<?, ?> emptySubtree =
233 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
234 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
235 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
236 if (lastInsertedPosition == lastItemPosition) {
237 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, path,
238 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
239 rwTransaction.put(datastore, path, payload);
241 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
242 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, childPath,
243 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
244 rwTransaction.put(datastore, childPath, nodeChild);
245 lastInsertedPosition++;
249 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
250 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
251 final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
252 final DOMTransactionChain domTransactionChain) {
253 rwTransaction.delete(datastore, path.getParent().getParent());
254 final InstanceIdentifierContext<?> instanceIdentifier =
255 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.absent());
256 int lastItemPosition = 0;
257 for (final MapEntryNode mapEntryNode : readList.getValue()) {
258 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
266 int lastInsertedPosition = 0;
267 final NormalizedNode<?, ?> emptySubtree =
268 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
269 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
270 for (final MapEntryNode mapEntryNode : readList.getValue()) {
271 if (lastInsertedPosition == lastItemPosition) {
272 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, path,
273 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
274 rwTransaction.put(datastore, path, payload);
276 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
277 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, childPath,
278 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
279 rwTransaction.put(datastore, childPath, mapEntryNode);
280 lastInsertedPosition++;
284 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
285 final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
286 final DOMDataReadWriteTransaction transaction) {
287 if (data instanceof MapNode) {
288 boolean merge = false;
289 for (final MapEntryNode child : ((MapNode) data).getValue()) {
290 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
291 TransactionUtil.checkItemDoesNotExists(
292 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
293 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
296 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
297 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
298 transaction.merge(LogicalDatastoreType.CONFIGURATION,
299 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
301 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
304 TransactionUtil.checkItemDoesNotExists(
305 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
306 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
308 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
309 transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
314 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
318 * @param transactionNode
319 * wrapper for data of transaction
320 * @param schemaContextRef
321 * reference to {@link SchemaContext}
322 * @return {@link URI}
324 private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
325 final SchemaContextRef schemaContextRef) {
326 if (uriInfo == null) {
330 final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
331 uriBuilder.path("data");
332 uriBuilder.path(ParserIdentifier
333 .stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
334 schemaContextRef.get()));
336 return uriBuilder.build();
339 private static void simplePost(final DOMDataReadWriteTransaction rwTransaction,
340 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
341 final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
342 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
343 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
344 TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
345 rwTransaction.put(datastore, path, payload);