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.restful.utils;
10 import com.google.common.util.concurrent.CheckedFuture;
12 import javax.ws.rs.core.Response;
13 import javax.ws.rs.core.UriBuilder;
14 import javax.ws.rs.core.UriInfo;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
17 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
18 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
19 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
20 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
21 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
22 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
23 import org.opendaylight.restconf.common.references.SchemaContextRef;
24 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
25 import org.opendaylight.restconf.utils.parser.ParserIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
33 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * Util class to post data to DS.
44 public final class PostDataTransactionUtil {
46 private static final Logger LOG = LoggerFactory.getLogger(PostDataTransactionUtil.class);
48 private PostDataTransactionUtil() {
49 throw new UnsupportedOperationException("Util class.");
53 * Check mount point and prepare variables for post data.
59 * @param transactionNode
60 * wrapper for transaction data
61 * @param schemaContextRef
62 * reference to actual {@link SchemaContext}
67 * @return {@link CheckedFuture}
69 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
70 final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
72 final CheckedFuture<Void, TransactionCommitFailedException> future = submitData(
73 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
74 transactionNode, schemaContextRef.get(), insert, point);
75 final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
76 final ResponseFactory dataFactory = new ResponseFactory(null, location);
77 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
78 return dataFactory.build();
88 * @param transactionNode
89 * wrapper for data to transaction
90 * @param schemaContext
91 * schema context of data
96 * @return {@link CheckedFuture}
98 private static CheckedFuture<Void, TransactionCommitFailedException> submitData(final YangInstanceIdentifier path,
99 final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
100 final SchemaContext schemaContext, final String insert, final String point) {
101 final DOMTransactionChain domTransactionChain = transactionNode.getTransactionChain();
102 final DOMDataReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction();
103 if (insert == null) {
104 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
105 return newReadWriteTransaction.submit();
107 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
110 if (schemaNode instanceof ListSchemaNode) {
111 final NormalizedNode<?, ?> readData =
112 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
114 final OrderedMapNode readList = (OrderedMapNode) readData;
115 if ((readList == null) || readList.getValue().isEmpty()) {
116 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
117 return newReadWriteTransaction.submit();
119 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
120 path.getParent().getParent());
121 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
122 schemaContext, domTransactionChain);
123 makePost(path, readData, schemaContext, domTransactionChain,
124 newReadWriteTransaction);
125 return newReadWriteTransaction.submit();
128 final NormalizedNode<?, ?> readData = PutDataTransactionUtil
129 .readList(path.getParent(), schemaContext, domTransactionChain, schemaNode);
131 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
132 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
133 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
134 return newReadWriteTransaction.submit();
136 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
137 path.getParent().getParent());
138 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
139 schemaContext, domTransactionChain);
140 makePost(path, readData, schemaContext, domTransactionChain, newReadWriteTransaction);
141 return newReadWriteTransaction.submit();
145 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
146 return newReadWriteTransaction.submit();
148 if (schemaNode instanceof ListSchemaNode) {
149 final NormalizedNode<?, ?> readData =
150 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
152 final OrderedMapNode readList = (OrderedMapNode) readData;
153 if ((readList == null) || readList.getValue().isEmpty()) {
154 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
155 return newReadWriteTransaction.submit();
157 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
158 data, schemaContext, point, readList, true, domTransactionChain);
159 return newReadWriteTransaction.submit();
162 final NormalizedNode<?, ?> readData =
163 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
166 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
167 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
168 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
169 return newReadWriteTransaction.submit();
171 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
172 path, data, schemaContext, point, readLeafList, true, domTransactionChain);
173 return newReadWriteTransaction.submit();
177 if (schemaNode instanceof ListSchemaNode) {
178 final NormalizedNode<?, ?> readData =
179 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
181 final OrderedMapNode readList = (OrderedMapNode) readData;
182 if ((readList == null) || readList.getValue().isEmpty()) {
183 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
184 return newReadWriteTransaction.submit();
186 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
187 data, schemaContext, point, readList, false, domTransactionChain);
188 return newReadWriteTransaction.submit();
191 final NormalizedNode<?, ?> readData =
192 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
195 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
196 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
197 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
198 return newReadWriteTransaction.submit();
200 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
201 path, data, schemaContext, point, readLeafList, true, domTransactionChain);
202 return newReadWriteTransaction.submit();
206 throw new RestconfDocumentedException(
207 "Used bad value of insert parameter. Possible values are first, last, before or after, "
208 + "but was: " + insert);
213 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rwTransaction,
214 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
215 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
216 final boolean before, final DOMTransactionChain domTransactionChain) {
217 rwTransaction.delete(datastore, path.getParent().getParent());
218 final InstanceIdentifierContext<?> instanceIdentifier =
219 ControllerContext.getInstance().toInstanceIdentifier(point);
220 int lastItemPosition = 0;
221 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
222 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
230 int lastInsertedPosition = 0;
231 final NormalizedNode<?, ?> emptySubtree =
232 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
233 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
234 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
235 if (lastInsertedPosition == lastItemPosition) {
236 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, path,
237 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
238 rwTransaction.put(datastore, path, payload);
240 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
241 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, childPath,
242 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
243 rwTransaction.put(datastore, childPath, nodeChild);
244 lastInsertedPosition++;
248 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rwTransaction,
249 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
250 final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
251 final DOMTransactionChain domTransactionChain) {
252 rwTransaction.delete(datastore, path.getParent().getParent());
253 final InstanceIdentifierContext<?> instanceIdentifier =
254 ControllerContext.getInstance().toInstanceIdentifier(point);
255 int lastItemPosition = 0;
256 for (final MapEntryNode mapEntryNode : readList.getValue()) {
257 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
265 int lastInsertedPosition = 0;
266 final NormalizedNode<?, ?> emptySubtree =
267 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
268 rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
269 for (final MapEntryNode mapEntryNode : readList.getValue()) {
270 if (lastInsertedPosition == lastItemPosition) {
271 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, path,
272 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
273 rwTransaction.put(datastore, path, payload);
275 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
276 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rwTransaction, datastore, childPath,
277 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
278 rwTransaction.put(datastore, childPath, mapEntryNode);
279 lastInsertedPosition++;
283 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
284 final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
285 final DOMDataReadWriteTransaction transaction) {
286 if (data instanceof MapNode) {
287 boolean merge = false;
288 for (final MapEntryNode child : ((MapNode) data).getValue()) {
289 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
290 TransactionUtil.checkItemDoesNotExists(
291 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
292 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
295 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
296 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
297 transaction.merge(LogicalDatastoreType.CONFIGURATION,
298 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
300 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
303 TransactionUtil.checkItemDoesNotExists(
304 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
305 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
307 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
308 transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
313 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
317 * @param transactionNode
318 * wrapper for data of transaction
319 * @param schemaContextRef
320 * reference to {@link SchemaContext}
321 * @return {@link URI}
323 private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
324 final SchemaContextRef schemaContextRef) {
325 if (uriInfo == null) {
329 final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
330 uriBuilder.path("data");
331 uriBuilder.path(ParserIdentifier
332 .stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
333 schemaContextRef.get()));
335 return uriBuilder.build();
338 private static void simplePost(final DOMDataReadWriteTransaction rwTransaction,
339 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
340 final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
341 TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
342 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
343 TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
344 rwTransaction.put(datastore, path, payload);