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 FluentFuture<? extends CommitInfo> future = submitData(
65 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
66 strategy, schemaContext, insert, point);
67 final URI location = resolveLocation(uriInfo, strategy.getInstanceIdentifier(),
68 schemaContext, payload.getData());
69 final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
70 //This method will close transactionChain if any
71 FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory,
72 strategy.getTransactionChain());
73 return dataFactory.build();
81 * @param strategy object that perform the actual DS operations
82 * @param schemaContext schema context of data
83 * @param point query parameter
84 * @param insert query parameter
85 * @return {@link FluentFuture}
87 private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
88 final NormalizedNode<?, ?> data,
89 final RestconfStrategy strategy,
90 final EffectiveModelContext schemaContext,
91 final String insert, final String point) {
92 strategy.prepareReadWriteExecution();
94 makePost(path, data, schemaContext, strategy);
95 return strategy.commit();
98 final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
101 if (schemaNode instanceof ListSchemaNode) {
102 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
103 schemaContext, strategy, schemaNode);
104 final OrderedMapNode readList = (OrderedMapNode) readData;
105 if (readList == null || readList.getValue().isEmpty()) {
106 makePost(path, data, schemaContext, strategy);
107 return strategy.commit();
110 strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
111 simplePost(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext, strategy);
112 makePost(path, readData, schemaContext, strategy);
113 return strategy.commit();
115 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
116 schemaContext, strategy, schemaNode);
118 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
119 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
120 makePost(path, data, schemaContext, strategy);
121 return strategy.commit();
124 strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
125 simplePost(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext, strategy);
126 makePost(path, readData, schemaContext, strategy);
127 return strategy.commit();
130 makePost(path, data, schemaContext, strategy);
131 return strategy.commit();
133 if (schemaNode instanceof ListSchemaNode) {
134 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
135 schemaContext, strategy, schemaNode);
136 final OrderedMapNode readList = (OrderedMapNode) readData;
137 if (readList == null || readList.getValue().isEmpty()) {
138 makePost(path, data, schemaContext, strategy);
139 return strategy.commit();
142 insertWithPointListPost(LogicalDatastoreType.CONFIGURATION, path,
143 data, schemaContext, point, readList, true, strategy);
144 return strategy.commit();
146 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
147 schemaContext, strategy, schemaNode);
149 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
150 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
151 makePost(path, data, schemaContext, strategy);
152 return strategy.commit();
155 insertWithPointLeafListPost(LogicalDatastoreType.CONFIGURATION,
156 path, data, schemaContext, point, readLeafList, true, strategy);
157 return strategy.commit();
160 if (schemaNode instanceof ListSchemaNode) {
161 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
162 schemaContext, strategy, schemaNode);
163 final OrderedMapNode readList = (OrderedMapNode) readData;
164 if (readList == null || readList.getValue().isEmpty()) {
165 makePost(path, data, schemaContext, strategy);
166 return strategy.commit();
169 insertWithPointListPost(LogicalDatastoreType.CONFIGURATION, path,
170 data, schemaContext, point, readList, false, strategy);
171 return strategy.commit();
173 final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
174 schemaContext, strategy, schemaNode);
176 final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
177 if (readLeafList == null || readLeafList.getValue().isEmpty()) {
178 makePost(path, data, schemaContext, strategy);
179 return strategy.commit();
182 insertWithPointLeafListPost(LogicalDatastoreType.CONFIGURATION,
183 path, data, schemaContext, point, readLeafList, true, strategy);
184 return strategy.commit();
187 throw new RestconfDocumentedException(
188 "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
189 + insert, RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.BAD_ATTRIBUTE);
193 private static void insertWithPointLeafListPost(final LogicalDatastoreType datastore,
194 final YangInstanceIdentifier path,
195 final NormalizedNode<?, ?> payload,
196 final EffectiveModelContext schemaContext, final String point,
197 final OrderedLeafSetNode<?> readLeafList,
198 final boolean before, final RestconfStrategy strategy) {
199 strategy.delete(datastore, path.getParent().getParent());
200 final InstanceIdentifierContext<?> instanceIdentifier =
201 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
202 int lastItemPosition = 0;
203 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
204 if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
212 int lastInsertedPosition = 0;
213 final NormalizedNode<?, ?> emptySubtree =
214 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
215 strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
216 for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
217 if (lastInsertedPosition == lastItemPosition) {
218 TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
219 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
220 strategy.create(datastore, path, payload);
222 final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
223 TransactionUtil.checkItemDoesNotExists(strategy, datastore, childPath,
224 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
225 strategy.create(datastore, childPath, nodeChild);
226 lastInsertedPosition++;
230 private static void insertWithPointListPost(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
231 final NormalizedNode<?, ?> payload,
232 final EffectiveModelContext schemaContext, final String point,
233 final MapNode readList, final boolean before,
234 final RestconfStrategy strategy) {
235 strategy.delete(datastore, path.getParent().getParent());
236 final InstanceIdentifierContext<?> instanceIdentifier =
237 ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
238 int lastItemPosition = 0;
239 for (final MapEntryNode mapEntryNode : readList.getValue()) {
240 if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
248 int lastInsertedPosition = 0;
249 final NormalizedNode<?, ?> emptySubtree =
250 ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
251 strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
252 for (final MapEntryNode mapEntryNode : readList.getValue()) {
253 if (lastInsertedPosition == lastItemPosition) {
254 TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
255 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
256 strategy.create(datastore, path, payload);
258 final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
259 TransactionUtil.checkItemDoesNotExists(strategy, datastore, childPath,
260 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
261 strategy.create(datastore, childPath, mapEntryNode);
262 lastInsertedPosition++;
266 private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
267 final SchemaContext schemaContext, final RestconfStrategy strategy) {
268 if (data instanceof MapNode) {
269 boolean merge = false;
270 for (final MapEntryNode child : ((MapNode) data).getValue()) {
271 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
272 TransactionUtil.checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, childPath,
273 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
276 TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
277 final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
278 strategy.merge(LogicalDatastoreType.CONFIGURATION,
279 YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
281 strategy.create(LogicalDatastoreType.CONFIGURATION, childPath, child);
284 TransactionUtil.checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, path,
285 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
287 TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
288 strategy.create(LogicalDatastoreType.CONFIGURATION, path, data);
293 * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
295 * @param uriInfo uri info
296 * @param yangInstanceIdentifier reference to {@link InstanceIdentifierContext}
297 * @param schemaContext reference to {@link SchemaContext}
298 * @return {@link URI}
300 private static URI resolveLocation(final UriInfo uriInfo, final InstanceIdentifierContext<?> yangInstanceIdentifier,
301 final EffectiveModelContext schemaContext, final NormalizedNode<?, ?> data) {
302 if (uriInfo == null) {
306 YangInstanceIdentifier path = yangInstanceIdentifier.getInstanceIdentifier();
308 if (data instanceof MapNode) {
309 final Collection<MapEntryNode> children = ((MapNode) data).getValue();
310 if (!children.isEmpty()) {
311 path = path.node(children.iterator().next().getIdentifier());
315 return uriInfo.getBaseUriBuilder()
317 .path(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext))
321 private static void simplePost(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
322 final NormalizedNode<?, ?> payload,
323 final SchemaContext schemaContext, final RestconfStrategy strategy) {
324 TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
325 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
326 TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
327 strategy.create(datastore, path, payload);