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}
65 * @return {@link CheckedFuture}
67 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
68 final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
70 final CheckedFuture<Void, TransactionCommitFailedException> 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(null, 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 CheckedFuture}
96 private static CheckedFuture<Void, TransactionCommitFailedException> 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 DOMDataReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction();
101 if (insert == null) {
102 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
103 return newReadWriteTransaction.submit();
105 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
108 if (schemaNode instanceof ListSchemaNode) {
109 final NormalizedNode<?, ?> readData =
110 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
112 final OrderedMapNode readList = (OrderedMapNode) readData;
113 if ((readList == null) || readList.getValue().isEmpty()) {
114 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
115 return newReadWriteTransaction.submit();
117 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
118 path.getParent().getParent());
119 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
120 schemaContext, domTransactionChain);
121 makePost(path, readData, schemaContext, domTransactionChain,
122 newReadWriteTransaction);
123 return newReadWriteTransaction.submit();
126 final NormalizedNode<?, ?> readData =
127 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain, schemaNode);
129 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
130 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
131 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
132 return newReadWriteTransaction.submit();
134 newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,
135 path.getParent().getParent());
136 simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data,
137 schemaContext, domTransactionChain);
138 makePost(path, readData, schemaContext, domTransactionChain, newReadWriteTransaction);
139 return newReadWriteTransaction.submit();
143 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
144 return newReadWriteTransaction.submit();
146 if (schemaNode instanceof ListSchemaNode) {
147 final NormalizedNode<?, ?> readData =
148 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
150 final OrderedMapNode readList = (OrderedMapNode) readData;
151 if ((readList == null) || readList.getValue().isEmpty()) {
152 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
153 return newReadWriteTransaction.submit();
155 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
156 data, schemaContext, point, readList, true, domTransactionChain);
157 return newReadWriteTransaction.submit();
160 final NormalizedNode<?, ?> readData =
161 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
164 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
165 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
166 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
167 return newReadWriteTransaction.submit();
169 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
170 path, data, schemaContext, point, readLeafList, true, domTransactionChain);
171 return newReadWriteTransaction.submit();
175 if (schemaNode instanceof ListSchemaNode) {
176 final NormalizedNode<?, ?> readData =
177 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
179 final OrderedMapNode readList = (OrderedMapNode) readData;
180 if ((readList == null) || readList.getValue().isEmpty()) {
181 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
182 return newReadWriteTransaction.submit();
184 insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
185 data, schemaContext, point, readList, false, domTransactionChain);
186 return newReadWriteTransaction.submit();
189 final NormalizedNode<?, ?> readData =
190 PutDataTransactionUtil.readList(path.getParent(), schemaContext, domTransactionChain,
193 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
194 if ((readLeafList == null) || readLeafList.getValue().isEmpty()) {
195 makePost(path, data, schemaContext, domTransactionChain, newReadWriteTransaction);
196 return newReadWriteTransaction.submit();
198 insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
199 path, data, schemaContext, point, readLeafList, true, domTransactionChain);
200 return newReadWriteTransaction.submit();
204 throw new RestconfDocumentedException(
205 "Used bad value of insert parameter. Possible values are first, last, before or after, "
206 + "but was: " + insert);
211 private static void insertWithPointLeafListPost(final DOMDataReadWriteTransaction rWTransaction,
212 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
213 final SchemaContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
214 final boolean before, final DOMTransactionChain domTransactionChain) {
215 rWTransaction.delete(datastore, path.getParent().getParent());
216 final InstanceIdentifierContext<?> instanceIdentifier =
217 ControllerContext.getInstance().toInstanceIdentifier(point);
219 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
220 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
229 final NormalizedNode<?, ?> emptySubtree =
230 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
231 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
232 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
234 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rWTransaction, datastore, path,
235 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
236 rWTransaction.put(datastore, path, payload);
238 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
239 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rWTransaction, datastore, childPath,
240 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
241 rWTransaction.put(datastore, childPath, nodeChild);
246 private static void insertWithPointListPost(final DOMDataReadWriteTransaction rWTransaction,
247 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
248 final SchemaContext schemaContext, final String point, final MapNode readList, final boolean before,
249 final DOMTransactionChain domTransactionChain) {
250 rWTransaction.delete(datastore, path.getParent().getParent());
251 final InstanceIdentifierContext<?> instanceIdentifier =
252 ControllerContext.getInstance().toInstanceIdentifier(point);
254 for (final MapEntryNode mapEntryNode : readList.getValue()) {
255 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
264 final NormalizedNode<?, ?> emptySubtree =
265 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
266 rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
267 for (final MapEntryNode mapEntryNode : readList.getValue()) {
269 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rWTransaction, datastore, path,
270 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
271 rWTransaction.put(datastore, path, payload);
273 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
274 TransactionUtil.checkItemDoesNotExists(domTransactionChain, rWTransaction, datastore, childPath,
275 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
276 rWTransaction.put(datastore, childPath, mapEntryNode);
281 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
282 final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
283 final DOMDataReadWriteTransaction transaction) {
284 if (data instanceof MapNode) {
285 boolean merge = false;
286 for (final MapEntryNode child : ((MapNode) data).getValue()) {
287 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
288 TransactionUtil.checkItemDoesNotExists(
289 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
290 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
293 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
294 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
295 transaction.merge(LogicalDatastoreType.CONFIGURATION,
296 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
298 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
301 TransactionUtil.checkItemDoesNotExists(
302 transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
303 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
305 TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
306 transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
311 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}
315 * @param transactionNode
316 * - wrapper for data of transaction
317 * @param schemaContextRef
318 * -reference to {@link SchemaContext}
319 * @return {@link URI}
321 private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
322 final SchemaContextRef schemaContextRef) {
323 if (uriInfo == null) {
327 final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
328 uriBuilder.path("data");
329 uriBuilder.path(ParserIdentifier.stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
330 schemaContextRef.get()));
332 return uriBuilder.build();
335 private static void simplePost(final DOMDataReadWriteTransaction rWTransaction,
336 final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
337 final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
338 TransactionUtil.checkItemDoesNotExists(transactionChain, rWTransaction, datastore, path,
339 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
340 TransactionUtil.ensureParentsByMerge(path, schemaContext, rWTransaction);
341 rWTransaction.put(datastore, path, payload);