Bump MRI upstreams
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / PostDataTransactionUtil.java
index 5e38fb92723fb8a4876be13e432243d558039506..32edd65421595349b748d6f425989ed11c9b04ff 100644 (file)
@@ -16,204 +16,144 @@ 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.DOMDataTreeReadWriteTransaction;
 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
 import org.opendaylight.restconf.common.context.NormalizedNodeContext;
 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
 import org.opendaylight.restconf.common.errors.RestconfError;
-import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
+import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
+import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.PostPutQueryParameters.Insert;
 import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Util class to post data to DS.
  *
  */
 public final class PostDataTransactionUtil {
+    private static final Logger LOG = LoggerFactory.getLogger(PostDataTransactionUtil.class);
+    // FIXME: why is this being reused from other places?
+    static final String POST_TX_TYPE = "POST";
+
     private PostDataTransactionUtil() {
         // Hidden on purpose
     }
 
     /**
-     * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} inside of object
-     * {@link TransactionVarsWrapper} provided as a parameter.
-     *
-     * @param uriInfo
+     * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} if any inside of object
+     * {@link RestconfStrategy} provided as a parameter.
      *
-     * @param payload
-     *             data
-     * @param transactionNode
-     *             wrapper for transaction data
-     * @param schemaContextRef
-     *             reference to actual {@link SchemaContext}
-     * @param point
-     *             point
-     * @param insert
-     *             insert
+     * @param uriInfo       uri info
+     * @param payload       data
+     * @param strategy      Object that perform the actual DS operations
+     * @param schemaContext reference to actual {@link EffectiveModelContext}
+     * @param point         point
+     * @param insert        insert
      * @return {@link Response}
      */
     public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
-            final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef, final String insert,
-            final String point) {
-        final FluentFuture<? extends CommitInfo> future = submitData(
-                payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
-                transactionNode, schemaContextRef.get(), insert, point);
-        final URI location = resolveLocation(uriInfo, transactionNode, schemaContextRef, payload.getData());
+                                    final RestconfStrategy strategy,
+                                    final EffectiveModelContext schemaContext, final Insert insert,
+                                    final String point) {
+        final YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier();
+        final FluentFuture<? extends CommitInfo> future = submitData(path, payload.getData(),
+                strategy, schemaContext, insert, point);
+        final URI location = resolveLocation(uriInfo, path, schemaContext, payload.getData());
         final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
-        //This method will close transactionChain
-        FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory,
-                transactionNode.getTransactionChain());
+        //This method will close transactionChain if any
+        FutureCallbackTx.addCallback(future, POST_TX_TYPE, dataFactory, strategy, path);
         return dataFactory.build();
     }
 
     /**
      * Post data by type.
      *
-     * @param path
-     *             path
-     * @param data
-     *             data
-     * @param transactionNode
-     *             wrapper for data to transaction
-     * @param schemaContext
-     *             schema context of data
-     * @param point
-     *             query parameter
-     * @param insert
-     *             query parameter
+     * @param path          path
+     * @param data          data
+     * @param strategy      object that perform the actual DS operations
+     * @param schemaContext schema context of data
+     * @param point         query parameter
+     * @param insert        query parameter
      * @return {@link FluentFuture}
      */
     private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
-            final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
-            final EffectiveModelContext schemaContext, final String insert, final String point) {
-        final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
-        final DOMDataTreeReadWriteTransaction newReadWriteTransaction = transactionChain.newReadWriteTransaction();
+                                                                 final NormalizedNode data,
+                                                                 final RestconfStrategy strategy,
+                                                                 final EffectiveModelContext schemaContext,
+                                                                 final Insert insert, final String point) {
+        final RestconfTransaction transaction = strategy.prepareWriteExecution();
         if (insert == null) {
-            makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
-            return newReadWriteTransaction.commit();
+            makePost(path, data, schemaContext, transaction);
+            return transaction.commit();
         }
 
-        final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
+        PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
+        final NormalizedNode readData;
         switch (insert) {
-            case "first":
-                if (schemaNode instanceof ListSchemaNode) {
-                    final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
-                        schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
-                    final OrderedMapNode readList = (OrderedMapNode) readData;
-                    if (readList == null || readList.getValue().isEmpty()) {
-                        makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
-                        return newReadWriteTransaction.commit();
-                    }
-
-                    newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
-                    simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, schemaContext,
-                        transactionChain);
-                    makePost(path, readData, schemaContext, transactionChain, newReadWriteTransaction);
-                    return newReadWriteTransaction.commit();
-                } else {
-                    final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
-                        schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
-
-                    final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
-                    if (readLeafList == null || readLeafList.getValue().isEmpty()) {
-                        makePost(path, data, schemaContext, transactionChain,
-                            newReadWriteTransaction);
-                        return newReadWriteTransaction.commit();
-                    }
-
-                    newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
-                    simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, schemaContext,
-                        transactionChain);
-                    makePost(path, readData, schemaContext, transactionChain, newReadWriteTransaction);
-                    return newReadWriteTransaction.commit();
+            case FIRST:
+                readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
+                if (readData == null || ((NormalizedNodeContainer<?>) readData).isEmpty()) {
+                    transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+                    return transaction.commit();
                 }
-            case "last":
-                makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
-                return newReadWriteTransaction.commit();
-            case "before":
-                if (schemaNode instanceof ListSchemaNode) {
-                    final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
-                        schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
-                    final OrderedMapNode readList = (OrderedMapNode) readData;
-                    if (readList == null || readList.getValue().isEmpty()) {
-                        makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
-                        return newReadWriteTransaction.commit();
-                    }
-
-                    insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
-                        data, schemaContext, point, readList, true, transactionChain);
-                    return newReadWriteTransaction.commit();
-                } else {
-                    final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
-                        schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
-
-                    final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
-                    if (readLeafList == null || readLeafList.getValue().isEmpty()) {
-                        makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
-                        return newReadWriteTransaction.commit();
-                    }
-
-                    insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
-                        path, data, schemaContext, point, readLeafList, true, transactionChain);
-                    return newReadWriteTransaction.commit();
+                checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
+                transaction.remove(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
+                transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+                transaction.replace(LogicalDatastoreType.CONFIGURATION, 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());
+                if (readData == null || ((NormalizedNodeContainer<?>) readData).isEmpty()) {
+                    transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+                    return transaction.commit();
                 }
-            case "after":
-                if (schemaNode instanceof ListSchemaNode) {
-                    final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
-                        schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
-                    final OrderedMapNode readList = (OrderedMapNode) readData;
-                    if (readList == null || readList.getValue().isEmpty()) {
-                        makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
-                        return newReadWriteTransaction.commit();
-                    }
-
-                    insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
-                        data, schemaContext, point, readList, false,
-                        transactionChain);
-                    return newReadWriteTransaction.commit();
-                } else {
-                    final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
-                        schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
-
-                    final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
-                    if (readLeafList == null || readLeafList.getValue().isEmpty()) {
-                        makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
-                        return newReadWriteTransaction.commit();
-                    }
-
-                    insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
-                        path, data, schemaContext, point, readLeafList, true, transactionChain);
-                    return newReadWriteTransaction.commit();
+                checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
+                insertWithPointPost(path, data, schemaContext, point,
+                    (NormalizedNodeContainer<?>) readData, true, transaction);
+                return transaction.commit();
+            case AFTER:
+                readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
+                if (readData == null || ((NormalizedNodeContainer<?>) readData).isEmpty()) {
+                    transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+                    return transaction.commit();
                 }
+                checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
+                insertWithPointPost(path, data, schemaContext, point,
+                    (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, RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.BAD_ATTRIBUTE);
+                        + insert, RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.BAD_ATTRIBUTE);
         }
     }
 
-    private static void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
-            final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
-            final EffectiveModelContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
-            final boolean before, final DOMTransactionChain transactionChain) {
-        rwTransaction.delete(datastore, path.getParent().getParent());
+    private static void insertWithPointPost(final YangInstanceIdentifier path, final NormalizedNode data,
+                                            final EffectiveModelContext schemaContext, final String point,
+                                            final NormalizedNodeContainer<?> readList, final boolean before,
+                                            final RestconfTransaction transaction) {
+        final YangInstanceIdentifier parent = path.getParent().getParent();
+        transaction.remove(LogicalDatastoreType.CONFIGURATION, parent);
         final InstanceIdentifierContext<?> instanceIdentifier =
-                ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
+            ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
         int lastItemPosition = 0;
-        for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
+        for (final NormalizedNode nodeChild : readList.body()) {
             if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
                 break;
             }
@@ -223,108 +163,47 @@ public final class PostDataTransactionUtil {
             lastItemPosition++;
         }
         int lastInsertedPosition = 0;
-        final NormalizedNode<?, ?> emptySubtree =
-                ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
-        rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
-        for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
-            if (lastInsertedPosition == lastItemPosition) {
-                TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
-                        RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-                rwTransaction.put(datastore, path, payload);
-            }
-            final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
-            TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
-                    RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-            rwTransaction.put(datastore, childPath, nodeChild);
-            lastInsertedPosition++;
-        }
-    }
-
-    private static void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
-            final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
-            final EffectiveModelContext schemaContext, final String point, final MapNode readList, final boolean before,
-            final DOMTransactionChain transactionChain) {
-        rwTransaction.delete(datastore, path.getParent().getParent());
-        final InstanceIdentifierContext<?> instanceIdentifier =
-                ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
-        int lastItemPosition = 0;
-        for (final MapEntryNode mapEntryNode : readList.getValue()) {
-            if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
-                break;
-            }
-            lastItemPosition++;
-        }
-        if (!before) {
-            lastItemPosition++;
-        }
-        int lastInsertedPosition = 0;
-        final NormalizedNode<?, ?> emptySubtree =
-                ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
-        rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
-        for (final MapEntryNode mapEntryNode : readList.getValue()) {
+        final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, parent);
+        transaction.merge(LogicalDatastoreType.CONFIGURATION,
+            YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+        for (final NormalizedNode nodeChild : readList.body()) {
             if (lastInsertedPosition == lastItemPosition) {
-                TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
-                        RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-                rwTransaction.put(datastore, path, payload);
+                transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
             }
-            final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
-            TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
-                    RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-            rwTransaction.put(datastore, childPath, mapEntryNode);
+            final YangInstanceIdentifier childPath = parent.node(nodeChild.getIdentifier());
+            transaction.replace(LogicalDatastoreType.CONFIGURATION, childPath, nodeChild, schemaContext);
             lastInsertedPosition++;
         }
     }
 
-    private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
-            final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
-            final DOMDataTreeReadWriteTransaction transaction) {
-        if (data instanceof MapNode) {
-            boolean merge = false;
-            for (final MapEntryNode child : ((MapNode) data).getValue()) {
-                final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
-                TransactionUtil.checkItemDoesNotExists(
-                        transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
-                        RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-                if (!merge) {
-                    merge = true;
-                    TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
-                    final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
-                    transaction.merge(LogicalDatastoreType.CONFIGURATION,
-                            YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
-                }
-                transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
-            }
-        } else {
-            TransactionUtil.checkItemDoesNotExists(
-                    transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
-                    RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-
-            TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
-            transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
+    private static void makePost(final YangInstanceIdentifier path, final NormalizedNode data,
+                                 final SchemaContext schemaContext, final RestconfTransaction transaction) {
+        try {
+            transaction.create(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+        } catch (RestconfDocumentedException e) {
+            // close transaction if any and pass exception further
+            transaction.cancel();
+            throw e;
         }
     }
 
     /**
      * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
      *
-     * @param uriInfo
-     *             uri info
-     * @param transactionNode
-     *             wrapper for data of transaction
-     * @param schemaContextRef
-     *            reference to {@link SchemaContext}
+     * @param uriInfo       uri info
+     * @param initialPath   data path
+     * @param schemaContext reference to {@link SchemaContext}
      * @return {@link URI}
      */
-    private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
-            final SchemaContextRef schemaContextRef, final NormalizedNode<?, ?> data) {
+    private static URI resolveLocation(final UriInfo uriInfo, final YangInstanceIdentifier initialPath,
+                                       final EffectiveModelContext schemaContext, final NormalizedNode data) {
         if (uriInfo == null) {
             return null;
         }
 
-        YangInstanceIdentifier path = transactionNode.getInstanceIdentifier().getInstanceIdentifier();
-
+        YangInstanceIdentifier path = initialPath;
         if (data instanceof MapNode) {
-            final Collection<MapEntryNode> children = ((MapNode) data).getValue();
+            final Collection<MapEntryNode> children = ((MapNode) data).body();
             if (!children.isEmpty()) {
                 path = path.node(children.iterator().next().getIdentifier());
             }
@@ -332,16 +211,26 @@ public final class PostDataTransactionUtil {
 
         return uriInfo.getBaseUriBuilder()
                 .path("data")
-                .path(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContextRef.get()))
+                .path(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext))
                 .build();
     }
 
-    private static void simplePost(final DOMDataTreeReadWriteTransaction rwTransaction,
-            final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
-            final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
-        TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
-                RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-        TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
-        rwTransaction.put(datastore, path, payload);
+    /**
+     * Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
+     * data already exists.
+     *
+     * @param isExistsFuture if checked data exists
+     * @param path           Path to be checked
+     */
+    public static void checkItemDoesNotExists(final FluentFuture<Boolean> isExistsFuture,
+                                              final YangInstanceIdentifier path) {
+        final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
+        FutureCallbackTx.addCallback(isExistsFuture, POST_TX_TYPE, response);
+
+        if (response.result) {
+            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);
+        }
     }
 }