Bug 6325 - Fix for draft15 update 21/43121/14
authorJakub Toth <jatoth@cisco.com>
Thu, 4 Aug 2016 14:32:19 +0000 (16:32 +0200)
committerJakub Toth <jatoth@cisco.com>
Mon, 15 Aug 2016 15:24:23 +0000 (17:24 +0200)
- transaction chain must be updated
in transaction handler

- adapt utility methods to reset
transaction chain

Change-Id: I20578f97c9a8d002c0ebcc6b8a89a152c1e1c47a
Signed-off-by: Ivan Hrasko <ihrasko@cisco.com>
Signed-off-by: Jakub Toth <jatoth@cisco.com>
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/RestConnectorProvider.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/handlers/Handler.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/handlers/TransactionChainHandler.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/DeleteDataTransactionUtil.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PatchDataTransactionUtil.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PostDataTransactionUtil.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/TransactionUtil.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/RestConnectorProviderTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/DeleteDataTransactionUtilTest.java

index 7c7ae377e17b9ed85020ad46e6b429a9e1e02868..8205eba6adfcfa0604de47b3c756fd2e28ea437d 100644 (file)
@@ -5,6 +5,7 @@
  * 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;
 
 import com.google.common.base.Preconditions;
@@ -16,7 +17,6 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListen
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
@@ -57,8 +57,8 @@ public class RestConnectorProvider implements Provider, RestConnector, AutoClose
     };
 
     private ListenerRegistration<SchemaContextListener> listenerRegistration;
+    private static TransactionChainHandler transactionChainHandler;
     private static DOMDataBroker dataBroker;
-    private static DOMTransactionChain transactionChain;
 
     @Override
     public void onSessionInitiated(final ProviderSession session) {
@@ -72,30 +72,32 @@ public class RestConnectorProvider implements Provider, RestConnector, AutoClose
         final DOMMountPointServiceHandler domMountPointServiceHandler = new DOMMountPointServiceHandler(
                 session.getService(DOMMountPointService.class));
 
-        dataBroker = session.getService(DOMDataBroker.class);
-        final DOMDataBrokerHandler brokerHandler = new DOMDataBrokerHandler(dataBroker);
+        RestConnectorProvider.dataBroker = session.getService(DOMDataBroker.class);
+        final DOMDataBrokerHandler brokerHandler = new DOMDataBrokerHandler(RestConnectorProvider.dataBroker);
 
-        transactionChain = dataBroker.createTransactionChain(transactionListener);
-        final TransactionChainHandler transactionChainHandler = new TransactionChainHandler(transactionChain);
+        RestConnectorProvider.transactionChainHandler = new TransactionChainHandler(RestConnectorProvider.dataBroker
+                .createTransactionChain(RestConnectorProvider.transactionListener));
 
         final DOMRpcService rpcService = session.getService(DOMRpcService.class);
         final RpcServiceHandler rpcServiceHandler = new RpcServiceHandler(rpcService);
 
-        wrapperServices.setHandlers(schemaCtxHandler, domMountPointServiceHandler, transactionChainHandler,
-                brokerHandler, rpcServiceHandler);
+        wrapperServices.setHandlers(schemaCtxHandler, domMountPointServiceHandler,
+                RestConnectorProvider.transactionChainHandler, brokerHandler, rpcServiceHandler);
     }
 
     /**
-     * After {@link TransactionChain} failed, this is creating new transaction
-     * with listener.
+     * After {@link TransactionChain} failed, this updates {@link TransactionChainHandler} with new transaction chain.
      *
      * @param chain
      *            - old {@link TransactionChain}
      */
     public static void resetTransactionChainForAdapaters(final TransactionChain<?, ?> chain) {
-        LOG.trace("Resetting TransactionChain({}) to {}", chain, transactionChain);
+        LOG.trace("Resetting TransactionChain({})", chain);
         chain.close();
-        transactionChain = Preconditions.checkNotNull(dataBroker).createTransactionChain(transactionListener);
+        RestConnectorProvider.transactionChainHandler.update(
+                Preconditions.checkNotNull(RestConnectorProvider.dataBroker).createTransactionChain(
+                        RestConnectorProvider.transactionListener)
+        );
     }
 
     @Override
@@ -105,11 +107,14 @@ public class RestConnectorProvider implements Provider, RestConnector, AutoClose
 
     @Override
     public void close() throws Exception {
+        // close registration
         if (this.listenerRegistration != null) {
             this.listenerRegistration.close();
         }
-        if (transactionChain != null) {
-            transactionChain.close();
+
+        // close transaction chain
+        if (RestConnectorProvider.transactionChainHandler != null) {
+            RestConnectorProvider.transactionChainHandler.get().close();
         }
     }
 }
index 69c2276e13179280206cbcbde0fceddfbfa8e650..ceece0ffdd88faae2d75ea288cd367be2d917136 100644 (file)
@@ -5,9 +5,8 @@
  * 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.handlers;
 
-import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+package org.opendaylight.restconf.handlers;
 
 /**
  * Handler for handling object prepared by provider for Restconf services
@@ -20,7 +19,15 @@ interface Handler<T> {
     /**
      * Get prepared object
      *
-     * @return {@link DOMTransactionChain}
+     * @return T
      */
     T get();
+
+    /**
+     * Update object
+     *
+     * @param object
+     *            - new object to update old object
+     */
+    default void update(T object) {}
 }
index 450a8ed2b6607cd19446c096d21964cf054799ae..7cceef1dcd170e4332f43fbb06bd3874579fad0b 100644 (file)
@@ -5,6 +5,7 @@
  * 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.handlers;
 
 import com.google.common.base.Preconditions;
@@ -17,7 +18,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
  */
 public class TransactionChainHandler implements Handler<DOMTransactionChain> {
 
-    private final DOMTransactionChain transactionChain;
+    private DOMTransactionChain transactionChain;
 
     /**
      * Prepare transaction chain service for Restconf services
@@ -29,6 +30,12 @@ public class TransactionChainHandler implements Handler<DOMTransactionChain> {
         this.transactionChain = transactionChain;
     }
 
+    @Override
+    public void update(final DOMTransactionChain transactionChain) {
+        Preconditions.checkNotNull(transactionChain);
+        this.transactionChain = transactionChain;
+    }
+
     @Override
     public DOMTransactionChain get() {
         return this.transactionChain;
index 15d1f1c95d43326dd641a22497576cc2c99de7de..15ce3f76608dc9d6d4e5024ede52b77da6ce76c9 100644 (file)
@@ -12,6 +12,7 @@ import javax.ws.rs.core.Response;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 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.DOMTransactionChain;
 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
@@ -34,7 +35,7 @@ public final class DeleteDataTransactionUtil {
      */
     public static Response deleteData(final TransactionVarsWrapper transactionNode) {
         final CheckedFuture<Void, TransactionCommitFailedException> future = submitData(
-                transactionNode.getTransactionChain().newReadWriteTransaction(),
+                transactionNode.getTransactionChain(), transactionNode.getTransactionChain().newReadWriteTransaction(),
                 transactionNode.getInstanceIdentifier().getInstanceIdentifier());
         final ResponseFactory response = new ResponseFactory();
         FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE, response);
@@ -44,6 +45,8 @@ public final class DeleteDataTransactionUtil {
     /**
      * Delete data via transaction. Return error if data to delete does not exist.
      *
+     * @param transactionChain
+     *            - transaction chain
      * @param readWriteTx
      *            - read and write transaction
      * @param path
@@ -51,8 +54,9 @@ public final class DeleteDataTransactionUtil {
      * @return {@link CheckedFuture}
      */
     private static CheckedFuture<Void, TransactionCommitFailedException> submitData(
-            final DOMDataReadWriteTransaction readWriteTx, final YangInstanceIdentifier path) {
-        TransactionUtil.checkItemExists(readWriteTx, LogicalDatastoreType.CONFIGURATION, path,
+            final DOMTransactionChain transactionChain, final DOMDataReadWriteTransaction readWriteTx,
+            final YangInstanceIdentifier path) {
+        TransactionUtil.checkItemExists(transactionChain, readWriteTx, LogicalDatastoreType.CONFIGURATION, path,
                 RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE);
         readWriteTx.delete(LogicalDatastoreType.CONFIGURATION, path);
         return readWriteTx.submit();
index 0b350a7667c4608c648ffedfd856813328f5a3c6..4741592977562a631056fe57949ff4f220ddeaa3 100644 (file)
@@ -14,6 +14,7 @@ import com.google.common.util.concurrent.CheckedFuture;
 import java.util.ArrayList;
 import java.util.List;
 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;
@@ -185,7 +186,7 @@ public final class PatchDataTransactionUtil {
                                                     final YangInstanceIdentifier path,
                                                     final DOMDataReadWriteTransaction readWriteTransaction) {
         LOG.trace("Delete {} within Restconf PATCH: {}", dataStore.name(), path);
-        TransactionUtil.checkItemExists(readWriteTransaction, dataStore, path, PatchData.PATCH_TX_TYPE);
+        checkItemExistsWithinTransaction(readWriteTransaction, dataStore, path);
         readWriteTransaction.delete(dataStore, path);
     }
 
@@ -264,20 +265,62 @@ public final class PatchDataTransactionUtil {
                 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
 
                 if (errorIfExists) {
-                    TransactionUtil.checkItemDoesNotExists(
-                            rWTransaction, dataStore, childPath, PatchData.PATCH_TX_TYPE);
+                    checkItemDoesNotExistsWithinTransaction(rWTransaction, dataStore, childPath);
                 }
 
                 rWTransaction.put(dataStore, childPath, child);
             }
         } else {
             if (errorIfExists) {
-                TransactionUtil.checkItemDoesNotExists(
-                        rWTransaction, dataStore, path, PatchData.PATCH_TX_TYPE);
+                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) {
+            final String errMsg = "Operation via Restconf was not executed because data does not exist";
+            LOG.trace("{}:{}", errMsg, 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) {
+            final String errMsg = "Operation via Restconf was not executed because data already exists";
+            LOG.trace("{}:{}", errMsg, path);
+            throw new RestconfDocumentedException(
+                    "Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, path);
+        }
+    }
 }
index bc464069e0832dd36bd7d351a7f2ea4aec3d8d86..f507837630e83d2c0b5b836130a203dba85187a4 100644 (file)
@@ -15,6 +15,7 @@ import javax.ws.rs.core.UriInfo;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 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.DOMTransactionChain;
 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
 import org.opendaylight.restconf.common.references.SchemaContextRef;
 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
@@ -89,32 +90,34 @@ public final class PostDataTransactionUtil {
     private static CheckedFuture<Void, TransactionCommitFailedException> submitData(final YangInstanceIdentifier path,
             final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
             final SchemaContext schemaContext) {
-        final DOMDataReadWriteTransaction transaction = transactionNode.getTransactionChain().newReadWriteTransaction();
+        final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
+        final DOMDataReadWriteTransaction transaction = transactionChain.newReadWriteTransaction();
         final NormalizedNode<?, ?> node = ImmutableNodes.fromInstanceId(schemaContext, path);
         transaction.put(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(node.getIdentifier()), node);
         TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
 
         if (data instanceof MapNode) {
             for (final MapEntryNode child : ((MapNode) data).getValue()) {
-                putChild(child, transaction, path);
+                putChild(child, transactionChain, transaction, path);
             }
         } else if (data instanceof AugmentationNode) {
             for (final DataContainerChild<? extends PathArgument, ?> child : ((AugmentationNode) data).getValue()) {
-                putChild(child, transaction, path);
+                putChild(child, transactionChain, transaction, path);
             }
         } else if (data instanceof ChoiceNode) {
             for (final DataContainerChild<? extends PathArgument, ?> child : ((ChoiceNode) data).getValue()) {
-                putChild(child, transaction, path);
+                putChild(child, transactionChain, transaction, path);
             }
         } else if (data instanceof LeafSetNode<?>) {
             for (final LeafSetEntryNode<?> child : ((LeafSetNode<?>) data).getValue()) {
-                putChild(child, transaction, path);
+                putChild(child, transactionChain, transaction, path);
             }
         } else if (data instanceof ContainerNode) {
             for (final DataContainerChild<? extends PathArgument, ?> child : ((ContainerNode) data).getValue()) {
-                putChild(child, transaction, path);
+                putChild(child, transactionChain, transaction, path);
             }
         }
+
         return transaction.submit();
     }
 
@@ -123,15 +126,18 @@ public final class PostDataTransactionUtil {
      *
      * @param child
      *            - data
+     * @param transactionChain
+     *            - transaction chain
      * @param readWriteTx
      *            - transaction
      * @param path
      *            - path to data
      */
-    private static void putChild(final NormalizedNode<?, ?> child, final DOMDataReadWriteTransaction readWriteTx,
-            final YangInstanceIdentifier path) {
+    private static void putChild(final NormalizedNode<?, ?> child, final DOMTransactionChain transactionChain,
+                                 final DOMDataReadWriteTransaction readWriteTx, final YangInstanceIdentifier path) {
         final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
-        TransactionUtil.checkItemDoesNotExists(readWriteTx, LogicalDatastoreType.CONFIGURATION, childPath,
+        TransactionUtil.checkItemDoesNotExists(
+                transactionChain, readWriteTx, LogicalDatastoreType.CONFIGURATION, childPath,
                 RestconfDataServiceConstant.PostData.POST_TX_TYPE);
         readWriteTx.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
     }
index 6f63088d50085dd2806498ea3807719965dbe31d..2cd6899e3290b34289efa4b5d08cbc1f743e8ed1 100644 (file)
@@ -5,6 +5,7 @@
  * 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.restful.utils;
 
 import com.google.common.base.Preconditions;
@@ -16,9 +17,11 @@ 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.dom.api.DOMDataReadWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.restconf.RestConnectorProvider;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -88,12 +91,14 @@ public final class TransactionUtil {
     /**
      * Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
      * data does NOT already exists.
+     * @param transactionChain Transaction chain
      * @param rWTransaction Transaction
      * @param store Datastore
      * @param path Path to be checked
      * @param operationType Type of operation (READ, POST, PUT, DELETE...)
      */
-    public static void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
+    public static void checkItemExists(final DOMTransactionChain transactionChain,
+                                       final DOMDataReadWriteTransaction rWTransaction,
                                        final LogicalDatastoreType store, final YangInstanceIdentifier path,
                                        final String operationType) {
         final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
@@ -102,6 +107,11 @@ public final class TransactionUtil {
         FutureCallbackTx.addCallback(future, operationType, response);
 
         if (!response.result) {
+            // close transaction and reset transaction chain
+            rWTransaction.cancel();
+            RestConnectorProvider.resetTransactionChainForAdapaters(transactionChain);
+
+            // throw error
             final String errMsg = "Operation via Restconf was not executed because data does not exist";
             LOG.trace("{}:{}", errMsg, path);
             throw new RestconfDocumentedException(
@@ -112,12 +122,14 @@ public final class TransactionUtil {
     /**
      * Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
      * data already exists.
+     * @param transactionChain Transaction chain
      * @param rWTransaction Transaction
      * @param store Datastore
      * @param path Path to be checked
      * @param operationType Type of operation (READ, POST, PUT, DELETE...)
      */
-    public static void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
+    public static void checkItemDoesNotExists(final DOMTransactionChain transactionChain,
+                                              final DOMDataReadWriteTransaction rWTransaction,
                                               final LogicalDatastoreType store, final YangInstanceIdentifier path,
                                               final String operationType) {
         final CheckedFuture<Boolean, ReadFailedException> future = rWTransaction.exists(store, path);
@@ -126,6 +138,11 @@ public final class TransactionUtil {
         FutureCallbackTx.addCallback(future, operationType, response);
 
         if (response.result) {
+            // close transaction and reset transaction chain
+            rWTransaction.cancel();
+            RestConnectorProvider.resetTransactionChainForAdapaters(transactionChain);
+
+            // throw error
             final String errMsg = "Operation via Restconf was not executed because data already exists";
             LOG.trace("{}:{}", errMsg, path);
             throw new RestconfDocumentedException(
index 9b3b450b747cb3308a82d1e503e57c205f0ced75..f2ade260efe4152460a147736a72244d6b645b20 100644 (file)
@@ -171,5 +171,6 @@ public class RestConnectorProviderTest {
 
         // verify interaction
         verify(this.mockRegistration, times(1)).close();
+        verify(mockTransactionChain, times(1)).close();
     }
 }
index f38923d9522b00e73f1c27cc0f6385cb511d3dd0..38db430eab408064dfeaa85318aeebb7fa218c1a 100644 (file)
@@ -10,21 +10,29 @@ package org.opendaylight.restconf.restful.utils;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
 import com.google.common.util.concurrent.Futures;
+import java.lang.reflect.Field;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.restconf.RestConnectorProvider;
+import org.opendaylight.restconf.handlers.TransactionChainHandler;
 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
@@ -36,6 +44,31 @@ public class DeleteDataTransactionUtilTest {
     @Mock
     private DOMDataReadWriteTransaction readWrite;
 
+    // Fields used when delete operation fails to reset transaction chain
+    private static Field handler;
+    private static Field broker;
+
+    @BeforeClass
+    public static void setup() throws Exception {
+        DeleteDataTransactionUtilTest.handler = RestConnectorProvider.class.getDeclaredField("transactionChainHandler");
+        DeleteDataTransactionUtilTest.broker = RestConnectorProvider.class.getDeclaredField("dataBroker");
+
+        DeleteDataTransactionUtilTest.handler.setAccessible(true);
+        DeleteDataTransactionUtilTest.handler.set(RestConnectorProvider.class, mock(TransactionChainHandler.class));
+
+        DeleteDataTransactionUtilTest.broker.setAccessible(true);
+        DeleteDataTransactionUtilTest.broker.set(RestConnectorProvider.class, mock(DOMDataBroker.class));
+    }
+
+    @AfterClass
+    public static void clean() throws Exception {
+        DeleteDataTransactionUtilTest.handler.set(RestConnectorProvider.class, null);
+        DeleteDataTransactionUtilTest.handler.setAccessible(false);
+
+        DeleteDataTransactionUtilTest.broker.set(RestConnectorProvider.class, null);
+        DeleteDataTransactionUtilTest.broker.setAccessible(false);
+    }
+
     @Before
     public void init() throws Exception {
         MockitoAnnotations.initMocks(this);