Bump MRI upstreams
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / PatchDataTransactionUtil.java
index 2a843ce903689c29ac6e454a9dd4895a61c78cae..b9ca9798243a16a05ab2b7d3518b1a7423966cf7 100644 (file)
@@ -5,20 +5,17 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FluentFuture;
 import java.util.ArrayList;
 import java.util.List;
 import javax.ws.rs.core.Response.Status;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+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.common.errors.RestconfDocumentedException;
 import org.opendaylight.restconf.common.errors.RestconfError;
 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
@@ -27,45 +24,45 @@ import org.opendaylight.restconf.common.patch.PatchContext;
 import org.opendaylight.restconf.common.patch.PatchEntity;
 import org.opendaylight.restconf.common.patch.PatchStatusContext;
 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
-import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.PatchData;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-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.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public final class PatchDataTransactionUtil {
     private static final Logger LOG = LoggerFactory.getLogger(PatchDataTransactionUtil.class);
+    // FIXME: why is this used from other contexts?
+    static final String PATCH_TX_TYPE = "Patch";
 
     private PatchDataTransactionUtil() {
         throw new UnsupportedOperationException("Util class.");
     }
 
     /**
-     * Process edit operations of one {@link PatchContext}.
-     * @param context Patch context to be processed
-     * @param transactionNode Wrapper for transaction
-     * @param schemaContextRef Soft reference for global schema context
+     * Process edit operations of one {@link PatchContext}. Close {@link DOMTransactionChain} if any inside of object
+     * {@link RestconfStrategy} provided as a parameter.
+     *
+     * @param context       Patch context to be processed
+     * @param strategy      object that perform the actual DS operations
+     * @param schemaContext Global schema context
      * @return {@link PatchStatusContext}
      */
-    public static PatchStatusContext patchData(final PatchContext context, final TransactionVarsWrapper transactionNode,
-                                               final SchemaContextRef schemaContextRef) {
+    public static PatchStatusContext patchData(final PatchContext context, final RestconfStrategy strategy,
+                                               final EffectiveModelContext schemaContext) {
         final List<PatchStatusEntity> editCollection = new ArrayList<>();
         boolean noError = true;
-        final DOMDataReadWriteTransaction tx = transactionNode.getTransactionChain().newReadWriteTransaction();
+        final RestconfTransaction transaction = strategy.prepareWriteExecution();
 
         for (final PatchEntity patchEntity : context.getData()) {
             if (noError) {
                 switch (patchEntity.getOperation()) {
                     case CREATE:
                         try {
-                            createDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
-                                    patchEntity.getTargetNode(), patchEntity.getNode(), tx, schemaContextRef);
+                            createDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
+                                schemaContext, transaction);
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
                         } catch (final RestconfDocumentedException e) {
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
@@ -75,8 +72,7 @@ public final class PatchDataTransactionUtil {
                         break;
                     case DELETE:
                         try {
-                            deleteDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(),
-                                    tx);
+                            deleteDataWithinTransaction(patchEntity.getTargetNode(), transaction);
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
                         } catch (final RestconfDocumentedException e) {
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
@@ -86,8 +82,8 @@ public final class PatchDataTransactionUtil {
                         break;
                     case MERGE:
                         try {
-                            mergeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
-                                    patchEntity.getTargetNode(), patchEntity.getNode(), tx, schemaContextRef);
+                            mergeDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
+                                schemaContext, transaction);
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
                         } catch (final RestconfDocumentedException e) {
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
@@ -97,8 +93,8 @@ public final class PatchDataTransactionUtil {
                         break;
                     case REPLACE:
                         try {
-                            replaceDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
-                                    patchEntity.getTargetNode(), patchEntity.getNode(), schemaContextRef, tx);
+                            replaceDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
+                                schemaContext, transaction);
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
                         } catch (final RestconfDocumentedException e) {
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
@@ -108,8 +104,7 @@ public final class PatchDataTransactionUtil {
                         break;
                     case REMOVE:
                         try {
-                            removeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(),
-                                    tx);
+                            removeDataWithinTransaction(patchEntity.getTargetNode(), transaction);
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
                         } catch (final RestconfDocumentedException e) {
                             editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
@@ -132,10 +127,11 @@ public final class PatchDataTransactionUtil {
         // if no errors then submit transaction, otherwise cancel
         if (noError) {
             final ResponseFactory response = new ResponseFactory(Status.OK);
-            final CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
+            final FluentFuture<? extends CommitInfo> future = transaction.commit();
 
             try {
-                FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
+                //This method will close transactionChain if any
+                FutureCallbackTx.addCallback(future, PATCH_TX_TYPE, response, strategy, null);
             } catch (final RestconfDocumentedException e) {
                 // if errors occurred during transaction commit then patch failed and global errors are reported
                 return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false,
@@ -144,167 +140,78 @@ public final class PatchDataTransactionUtil {
 
             return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), true, null);
         } else {
-            tx.cancel();
-            transactionNode.getTransactionChainHandler().reset();
-            return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection),
-                    false, null);
+            transaction.cancel();
+            return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
         }
     }
 
     /**
      * Create data within one transaction, return error if already exists.
-     * @param dataStore Datastore to write data to
-     * @param path Path for data to be created
-     * @param payload Data to be created
-     * @param rWTransaction Transaction
-     * @param schemaContextRef Soft reference for global schema context
+     *
+     * @param path          Path for data to be created
+     * @param payload       Data to be created
+     * @param transaction   A handle to a set of DS operations
      */
-    private static void createDataWithinTransaction(final LogicalDatastoreType dataStore,
-                                                    final YangInstanceIdentifier path,
-                                                    final NormalizedNode<?, ?> payload,
-                                                    final DOMDataReadWriteTransaction rwTransaction,
-                                                    final SchemaContextRef schemaContextRef) {
-        LOG.trace("POST {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
-        createData(payload, schemaContextRef.get(), path, rwTransaction, dataStore, true);
+    private static void createDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload,
+                                                    final EffectiveModelContext schemaContext,
+                                                    final RestconfTransaction transaction) {
+        LOG.trace("POST {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
+            path, payload);
+        transaction.create(LogicalDatastoreType.CONFIGURATION, path, payload, schemaContext);
     }
 
     /**
-     * Check if data exists and remove it within one transaction.
-     * @param dataStore Datastore to delete data from
-     * @param path Path for data to be deleted
-     * @param readWriteTransaction Transaction
+     * Remove data within one transaction.
+     *
+     * @param path     Path for data to be deleted
+     * @param transaction   A handle to a set of DS operations
      */
-    private static void deleteDataWithinTransaction(final LogicalDatastoreType dataStore,
-                                                    final YangInstanceIdentifier path,
-                                                    final DOMDataReadWriteTransaction readWriteTransaction) {
-        LOG.trace("Delete {} within Restconf Patch: {}", dataStore.name(), path);
-        checkItemExistsWithinTransaction(readWriteTransaction, dataStore, path);
-        readWriteTransaction.delete(dataStore, path);
+    private static void deleteDataWithinTransaction(final YangInstanceIdentifier path,
+                                                    final RestconfTransaction transaction) {
+        LOG.trace("Delete {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
+        transaction.delete(LogicalDatastoreType.CONFIGURATION, path);
     }
 
     /**
      * Merge data within one transaction.
-     * @param dataStore Datastore to merge data to
-     * @param path Path for data to be merged
-     * @param payload Data to be merged
-     * @param writeTransaction Transaction
-     * @param schemaContextRef Soft reference for global schema context
+     *
+     * @param path     Path for data to be merged
+     * @param payload  Data to be merged
+     * @param transaction   A handle to a set of DS operations
      */
-    private static void mergeDataWithinTransaction(final LogicalDatastoreType dataStore,
-                                                   final YangInstanceIdentifier path,
-                                                   final NormalizedNode<?, ?> payload,
-                                                   final DOMDataReadWriteTransaction writeTransaction,
-                                                   final SchemaContextRef schemaContextRef) {
-        LOG.trace("Merge {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
-        TransactionUtil.ensureParentsByMerge(path, schemaContextRef.get(), writeTransaction);
-        writeTransaction.merge(dataStore, path, payload);
+    private static void mergeDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload,
+                                                   final EffectiveModelContext schemaContext,
+                                                   final RestconfTransaction transaction) {
+        LOG.trace("Merge {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
+            path, payload);
+        TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
+        transaction.merge(LogicalDatastoreType.CONFIGURATION, path, payload);
     }
 
     /**
      * Do NOT check if data exists and remove it within one transaction.
-     * @param dataStore Datastore to delete data from
-     * @param path Path for data to be deleted
-     * @param writeTransaction Transaction
+     *
+     * @param path     Path for data to be deleted
+     * @param transaction   A handle to a set of DS operations
      */
-    private static void removeDataWithinTransaction(final LogicalDatastoreType dataStore,
-                                                    final YangInstanceIdentifier path,
-                                                    final DOMDataWriteTransaction writeTransaction) {
-        LOG.trace("Remove {} within Restconf Patch: {}", dataStore.name(), path);
-        writeTransaction.delete(dataStore, path);
+    private static void removeDataWithinTransaction(final YangInstanceIdentifier path,
+                                                    final RestconfTransaction transaction) {
+        LOG.trace("Remove {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
+        transaction.remove(LogicalDatastoreType.CONFIGURATION, path);
     }
 
     /**
      * Create data within one transaction, replace if already exists.
-     * @param dataStore Datastore to write data to
-     * @param path Path for data to be created
-     * @param payload Data to be created
-     * @param schemaContextRef Soft reference for global schema context
-     * @param rwTransaction Transaction
-     */
-    private static void replaceDataWithinTransaction(final LogicalDatastoreType dataStore,
-                                                     final YangInstanceIdentifier path,
-                                                     final NormalizedNode<?, ?> payload,
-                                                     final SchemaContextRef schemaContextRef,
-                                                     final DOMDataReadWriteTransaction rwTransaction) {
-        LOG.trace("PUT {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
-        createData(payload, schemaContextRef.get(), path, rwTransaction, dataStore, false);
-    }
-
-    /**
-     * Create data within one transaction. If {@code errorIfExists} is set to {@code true} then data will be checked
-     * for existence before created, otherwise they will be overwritten.
-     * @param payload Data to be created
-     * @param schemaContext Global schema context
-     * @param path Path for data to be created
-     * @param rwTransaction Transaction
-     * @param dataStore Datastore to write data to
-     * @param errorIfExists Enable checking for existence of data (throws error if already exists)
+     *
+     * @param path          Path for data to be created
+     * @param payload       Data to be created
+     * @param transaction   A handle to a set of DS operations
      */
-    private static void createData(final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
-                                   final YangInstanceIdentifier path, final DOMDataReadWriteTransaction rwTransaction,
-                                   final LogicalDatastoreType dataStore, final boolean errorIfExists) {
-        if (payload instanceof MapNode) {
-            final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
-            rwTransaction.merge(dataStore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
-            TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
-            for (final MapEntryNode child : ((MapNode) payload).getValue()) {
-                final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
-
-                if (errorIfExists) {
-                    checkItemDoesNotExistsWithinTransaction(rwTransaction, dataStore, childPath);
-                }
-
-                rwTransaction.put(dataStore, childPath, child);
-            }
-        } else {
-            if (errorIfExists) {
-                checkItemDoesNotExistsWithinTransaction(rwTransaction, dataStore, path);
-            }
-
-            TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
-            rwTransaction.put(dataStore, path, payload);
-        }
-    }
-
-    /**
-     * Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
-     * data does NOT already exists.
-     * @param rwTransaction Transaction
-     * @param store Datastore
-     * @param path Path to be checked
-     */
-    public static void checkItemExistsWithinTransaction(final DOMDataReadWriteTransaction rwTransaction,
-                                                final LogicalDatastoreType store, final YangInstanceIdentifier path) {
-        final CheckedFuture<Boolean, ReadFailedException> future = rwTransaction.exists(store, path);
-        final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
-
-        FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
-
-        if (!response.result) {
-            LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
-            throw new RestconfDocumentedException("Data does not exist", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
-                path);
-        }
-    }
-
-    /**
-     * Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
-     * data already exists.
-     * @param rwTransaction Transaction
-     * @param store Datastore
-     * @param path Path to be checked
-     */
-    public static void checkItemDoesNotExistsWithinTransaction(final DOMDataReadWriteTransaction rwTransaction,
-                                               final LogicalDatastoreType store, final YangInstanceIdentifier path) {
-        final CheckedFuture<Boolean, ReadFailedException> future = rwTransaction.exists(store, path);
-        final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
-
-        FutureCallbackTx.addCallback(future, PatchData.PATCH_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);
-        }
+    private static void replaceDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload,
+                                                     final EffectiveModelContext schemaContext,
+                                                     final RestconfTransaction transaction) {
+        LOG.trace("PUT {} within Restconf Patch: {} with payload {}",
+            LogicalDatastoreType.CONFIGURATION.name(), path, payload);
+        transaction.replace(LogicalDatastoreType.CONFIGURATION, path, payload, schemaContext);
     }
 }