package org.opendaylight.restconf.nb.rfc8040.rests.utils;
import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.ListenableFuture;
import java.net.URI;
-import java.util.Optional;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
-import org.opendaylight.restconf.api.query.InsertParam;
import org.opendaylight.restconf.api.query.PointParam;
-import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
-import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec;
-import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
+import org.opendaylight.restconf.nb.rfc8040.utils.parser.YangInstanceIdentifierDeserializer;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
* {@link RestconfStrategy} provided as a parameter.
*
* @param uriInfo uri info
- * @param payload data
+ * @param path path
+ * @param data data
* @param strategy Object that perform the actual DS operations
* @param schemaContext reference to actual {@link EffectiveModelContext}
* @param params {@link WriteDataParams}
* @return {@link Response}
*/
- public static Response postData(final UriInfo uriInfo, final NormalizedNodePayload payload,
- final RestconfStrategy strategy,
- final EffectiveModelContext schemaContext, final WriteDataParams params) {
- final YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier();
- final FluentFuture<? extends CommitInfo> future = submitData(path, payload.getData(),
- strategy, schemaContext, params);
- final URI location = resolveLocation(uriInfo, path, schemaContext, payload.getData());
- final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
- //This method will close transactionChain if any
- FutureCallbackTx.addCallback(future, POST_TX_TYPE, dataFactory, path);
- return dataFactory.build();
+ public static Response postData(final UriInfo uriInfo, final YangInstanceIdentifier path, final NormalizedNode data,
+ final RestconfStrategy strategy, final EffectiveModelContext schemaContext, final WriteDataParams params) {
+ TransactionUtil.syncCommit(submitData(path, data, strategy, schemaContext, params), POST_TX_TYPE, path);
+ return Response.created(resolveLocation(uriInfo, path, schemaContext, data)).build();
}
/**
* @param insert query parameter
* @return {@link FluentFuture}
*/
- private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
- final NormalizedNode data,
- final RestconfStrategy strategy,
- final EffectiveModelContext schemaContext,
- final WriteDataParams params) {
- final RestconfTransaction transaction = strategy.prepareWriteExecution();
- final InsertParam insert = params.insert();
+ private static ListenableFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
+ final NormalizedNode data, final RestconfStrategy strategy, final EffectiveModelContext schemaContext,
+ final WriteDataParams params) {
+ final var transaction = strategy.prepareWriteExecution();
+ final var insert = params.insert();
if (insert == null) {
- makePost(path, data, schemaContext, transaction);
- return transaction.commit();
+ return makePost(path, data, schemaContext, transaction);
}
- PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
- final NormalizedNode readData;
- switch (insert) {
- case FIRST:
- readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
+ final var parentPath = path.coerceParent();
+ PutDataTransactionUtil.checkListAndOrderedType(schemaContext, parentPath);
+ final var grandParentPath = parentPath.coerceParent();
+
+ return switch (insert) {
+ case FIRST -> {
+ final var readData = PutDataTransactionUtil.readList(strategy, grandParentPath);
if (readData == null || ((NormalizedNodeContainer<?>) readData).isEmpty()) {
transaction.replace(path, data, schemaContext);
- return transaction.commit();
+ yield transaction.commit();
}
checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
- transaction.remove(path.getParent().getParent());
+ transaction.remove(grandParentPath);
transaction.replace(path, data, schemaContext);
- transaction.replace(path.getParent().getParent(), readData, schemaContext);
- return transaction.commit();
- case LAST:
- makePost(path, data, schemaContext, transaction);
- return transaction.commit();
- case BEFORE:
- readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
+ transaction.replace(grandParentPath, readData, schemaContext);
+ yield transaction.commit();
+ }
+ case LAST -> makePost(path, data, schemaContext, transaction);
+ case BEFORE -> {
+ final var readData = PutDataTransactionUtil.readList(strategy, grandParentPath);
if (readData == null || ((NormalizedNodeContainer<?>) readData).isEmpty()) {
transaction.replace(path, data, schemaContext);
- return transaction.commit();
+ yield transaction.commit();
}
checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
insertWithPointPost(path, data, schemaContext, params.getPoint(),
(NormalizedNodeContainer<?>) readData, true, transaction);
- return transaction.commit();
- case AFTER:
- readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
+ yield transaction.commit();
+ }
+ case AFTER -> {
+ final var readData = PutDataTransactionUtil.readList(strategy, grandParentPath);
if (readData == null || ((NormalizedNodeContainer<?>) readData).isEmpty()) {
transaction.replace(path, data, schemaContext);
- return transaction.commit();
+ yield transaction.commit();
}
checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
insertWithPointPost(path, data, schemaContext, params.getPoint(),
(NormalizedNodeContainer<?>) readData, false, transaction);
- return transaction.commit();
- default:
- throw new RestconfDocumentedException(
- "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
- + insert, ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE);
- }
+ yield transaction.commit();
+ }
+ };
}
private static void insertWithPointPost(final YangInstanceIdentifier path, final NormalizedNode data,
final EffectiveModelContext schemaContext, final PointParam point,
final NormalizedNodeContainer<?> readList, final boolean before,
final RestconfTransaction transaction) {
- final YangInstanceIdentifier parent = path.getParent().getParent();
+ final YangInstanceIdentifier parent = path.coerceParent().coerceParent();
transaction.remove(parent);
- final InstanceIdentifierContext instanceIdentifier =
- // FIXME: Point should be able to give us this method
- ParserIdentifier.toInstanceIdentifier(point.value(), schemaContext, Optional.empty());
+ final var pointArg = YangInstanceIdentifierDeserializer.create(schemaContext, point.value()).path
+ .getLastPathArgument();
int lastItemPosition = 0;
- for (final NormalizedNode nodeChild : readList.body()) {
- if (nodeChild.name().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
+ for (var nodeChild : readList.body()) {
+ if (nodeChild.name().equals(pointArg)) {
break;
}
lastItemPosition++;
lastItemPosition++;
}
int lastInsertedPosition = 0;
- final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, parent);
+ final var emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, parent);
transaction.merge(YangInstanceIdentifier.of(emptySubtree.name()), emptySubtree);
- for (final NormalizedNode nodeChild : readList.body()) {
+ for (var nodeChild : readList.body()) {
if (lastInsertedPosition == lastItemPosition) {
transaction.replace(path, data, schemaContext);
}
}
}
- private static void makePost(final YangInstanceIdentifier path, final NormalizedNode data,
- final EffectiveModelContext schemaContext, final RestconfTransaction transaction) {
+ private static ListenableFuture<? extends CommitInfo> makePost(final YangInstanceIdentifier path,
+ final NormalizedNode data, final EffectiveModelContext schemaContext,
+ final RestconfTransaction transaction) {
try {
transaction.create(path, data, schemaContext);
} catch (RestconfDocumentedException e) {
transaction.cancel();
throw e;
}
+
+ return transaction.commit();
}
/**
}
/**
- * Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
- * data already exists.
+ * Check if items do NOT already exists at specified {@code path}.
*
- * @param isExistsFuture if checked data exists
- * @param path Path to be checked
+ * @param existsFuture if checked data exists
+ * @param path Path to be checked
+ * @throws RestconfDocumentedException if data already exists.
*/
- public static void checkItemDoesNotExists(final FluentFuture<Boolean> isExistsFuture,
+ public static void checkItemDoesNotExists(final ListenableFuture<Boolean> existsFuture,
final YangInstanceIdentifier path) {
- final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
- FutureCallbackTx.addCallback(isExistsFuture, POST_TX_TYPE, response);
-
- if (response.result) {
+ if (TransactionUtil.syncAccess(existsFuture, path)) {
LOG.trace("Operation via Restconf was not executed because data at {} already exists", path);
- throw new RestconfDocumentedException(
- "Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, path);
+ throw new RestconfDocumentedException("Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS,
+ path);
}
}
}