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.Collection;
13 import java.util.Optional;
14 import javax.ws.rs.core.Response;
15 import javax.ws.rs.core.Response.Status;
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.DOMTransactionChain;
20 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
21 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
22 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
23 import org.opendaylight.restconf.common.errors.RestconfError;
24 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
25 import org.opendaylight.restconf.nb.rfc8040.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.EffectiveModelContext;
36 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
40 * Util class to post data to DS.
43 public final class PostDataTransactionUtil {
44 private PostDataTransactionUtil() {
49 * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} if any inside of object
50 * {@link RestconfStrategy} provided as a parameter.
52 * @param uriInfo uri info
54 * @param strategy Object that perform the actual DS operations
55 * @param schemaContext reference to actual {@link EffectiveModelContext}
57 * @param insert insert
58 * @return {@link Response}
60 public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
61 final RestconfStrategy strategy,
62 final EffectiveModelContext schemaContext, final String insert,
64 final YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier();
65 final FluentFuture<? extends CommitInfo> future = submitData(path, payload.getData(),
66 strategy, schemaContext, insert, point);
67 final URI location = resolveLocation(uriInfo, path, schemaContext, payload.getData());
68 final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
69 //This method will close transactionChain if any
70 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory,
71 strategy.getTransactionChain());
72 return dataFactory.build();
80 * @param strategy object that perform the actual DS operations
81 * @param schemaContext schema context of data
82 * @param point query parameter
83 * @param insert query parameter
84 * @return {@link FluentFuture}
86 private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
87 final NormalizedNode<?, ?> data,
88 final RestconfStrategy strategy,
89 final EffectiveModelContext schemaContext,
90 final String insert, final String point) {
91 strategy.prepareReadWriteExecution();
93 makePost(path, data, schemaContext, strategy);
94 return strategy.commit();
97 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
100 if (schemaNode instanceof ListSchemaNode) {
101 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
102 schemaContext, strategy, schemaNode);
103 final OrderedMapNode readList = (OrderedMapNode) readData;
104 if (readList == null || readList.getValue().isEmpty()) {
105 makePost(path, data, schemaContext, strategy);
106 return strategy.commit();
109 strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
110 simplePost(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext, strategy);
111 makePost(path, readData, schemaContext, strategy);
112 return strategy.commit();
114 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
115 schemaContext, strategy, schemaNode);
117 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
118 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
119 makePost(path, data, schemaContext, strategy);
120 return strategy.commit();
123 strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
124 simplePost(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext, strategy);
125 makePost(path, readData, schemaContext, strategy);
126 return strategy.commit();
129 makePost(path, data, schemaContext, strategy);
130 return strategy.commit();
132 if (schemaNode instanceof ListSchemaNode) {
133 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
134 schemaContext, strategy, schemaNode);
135 final OrderedMapNode readList = (OrderedMapNode) readData;
136 if (readList == null || readList.getValue().isEmpty()) {
137 makePost(path, data, schemaContext, strategy);
138 return strategy.commit();
141 insertWithPointListPost(LogicalDatastoreType.CONFIGURATION, path,
142 data, schemaContext, point, readList, true, strategy);
143 return strategy.commit();
145 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
146 schemaContext, strategy, schemaNode);
148 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
149 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
150 makePost(path, data, schemaContext, strategy);
151 return strategy.commit();
154 insertWithPointLeafListPost(LogicalDatastoreType.CONFIGURATION,
155 path, data, schemaContext, point, readLeafList, true, strategy);
156 return strategy.commit();
159 if (schemaNode instanceof ListSchemaNode) {
160 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
161 schemaContext, strategy, schemaNode);
162 final OrderedMapNode readList = (OrderedMapNode) readData;
163 if (readList == null || readList.getValue().isEmpty()) {
164 makePost(path, data, schemaContext, strategy);
165 return strategy.commit();
168 insertWithPointListPost(LogicalDatastoreType.CONFIGURATION, path,
169 data, schemaContext, point, readList, false, strategy);
170 return strategy.commit();
172 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
173 schemaContext, strategy, schemaNode);
175 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
176 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
177 makePost(path, data, schemaContext, strategy);
178 return strategy.commit();
181 insertWithPointLeafListPost(LogicalDatastoreType.CONFIGURATION,
182 path, data, schemaContext, point, readLeafList, true, strategy);
183 return strategy.commit();
186 throw new RestconfDocumentedException(
187 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
188 + insert, RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.BAD_ATTRIBUTE);
192 private static void insertWithPointLeafListPost(final LogicalDatastoreType datastore,
193 final YangInstanceIdentifier path,
194 final NormalizedNode<?, ?> payload,
195 final EffectiveModelContext schemaContext, final String point,
196 final OrderedLeafSetNode<?> readLeafList,
197 final boolean before, final RestconfStrategy strategy) {
198 strategy.delete(datastore, path.getParent().getParent());
199 final InstanceIdentifierContext<?> instanceIdentifier =
200 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
201 int lastItemPosition = 0;
202 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
203 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
211 int lastInsertedPosition = 0;
212 final NormalizedNode<?, ?> emptySubtree =
213 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
214 strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
215 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
216 if (lastInsertedPosition == lastItemPosition) {
217 TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
218 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
219 strategy.create(datastore, path, payload);
221 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
222 TransactionUtil.checkItemDoesNotExists(strategy, datastore, childPath,
223 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
224 strategy.create(datastore, childPath, nodeChild);
225 lastInsertedPosition++;
229 private static void insertWithPointListPost(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
230 final NormalizedNode<?, ?> payload,
231 final EffectiveModelContext schemaContext, final String point,
232 final MapNode readList, final boolean before,
233 final RestconfStrategy strategy) {
234 strategy.delete(datastore, path.getParent().getParent());
235 final InstanceIdentifierContext<?> instanceIdentifier =
236 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
237 int lastItemPosition = 0;
238 for (final MapEntryNode mapEntryNode : readList.getValue()) {
239 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
247 int lastInsertedPosition = 0;
248 final NormalizedNode<?, ?> emptySubtree =
249 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
250 strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
251 for (final MapEntryNode mapEntryNode : readList.getValue()) {
252 if (lastInsertedPosition == lastItemPosition) {
253 TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
254 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
255 strategy.create(datastore, path, payload);
257 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
258 TransactionUtil.checkItemDoesNotExists(strategy, datastore, childPath,
259 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
260 strategy.create(datastore, childPath, mapEntryNode);
261 lastInsertedPosition++;
265 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
266 final SchemaContext schemaContext, final RestconfStrategy strategy) {
267 if (data instanceof MapNode) {
268 boolean merge = false;
269 for (final MapEntryNode child : ((MapNode) data).getValue()) {
270 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
271 TransactionUtil.checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, childPath,
272 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
275 TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
276 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
277 strategy.merge(LogicalDatastoreType.CONFIGURATION,
278 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
280 strategy.create(LogicalDatastoreType.CONFIGURATION, childPath, child);
283 TransactionUtil.checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, path,
284 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
286 TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
287 strategy.create(LogicalDatastoreType.CONFIGURATION, path, data);
292 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
294 * @param uriInfo uri info
295 * @param initialPath data path
296 * @param schemaContext reference to {@link SchemaContext}
297 * @return {@link URI}
299 private static URI resolveLocation(final UriInfo uriInfo, final YangInstanceIdentifier initialPath,
300 final EffectiveModelContext schemaContext, final NormalizedNode<?, ?> data) {
301 if (uriInfo == null) {
305 YangInstanceIdentifier path = initialPath;
306 if (data instanceof MapNode) {
307 final Collection<MapEntryNode> children = ((MapNode) data).getValue();
308 if (!children.isEmpty()) {
309 path = path.node(children.iterator().next().getIdentifier());
313 return uriInfo.getBaseUriBuilder()
315 .path(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext))
319 private static void simplePost(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
320 final NormalizedNode<?, ?> payload,
321 final SchemaContext schemaContext, final RestconfStrategy strategy) {
322 TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
323 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
324 TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
325 strategy.create(datastore, path, payload);