Bug 6936 - Fix post request 13/47113/6
authorIvan Hrasko <ivan.hrasko@pantheon.tech>
Wed, 19 Oct 2016 08:07:03 +0000 (10:07 +0200)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Wed, 19 Oct 2016 14:13:00 +0000 (14:13 +0000)
When post request sends data which already exist, it response with
data already exist.

Change-Id: I2ea60dfe4b8aa4236fbec0fd73b64a6f146146ee
Signed-off-by: miroslav.kovac <miroslav.kovac@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PostDataTransactionUtil.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/restful/utils/PostDataTransactionUtilTest.java

index fc9c676c4ea36a4bcaeb60bd591765d019a57813..f0958d79e9345a77d1ec25756802d57c26ef0b34 100644 (file)
@@ -17,20 +17,10 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFaile
 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.netconf.sal.restconf.impl.RestconfDocumentedException;
-import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
-import org.opendaylight.restconf.RestConnectorProvider;
 import org.opendaylight.restconf.common.references.SchemaContextRef;
 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
 import org.opendaylight.restconf.utils.parser.ParserIdentifier;
 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.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 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;
@@ -93,64 +83,35 @@ public final class PostDataTransactionUtil {
             final SchemaContext schemaContext) {
         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) {
+            boolean merge = false;
             for (final MapEntryNode child : ((MapNode) data).getValue()) {
-                putChild(child, transactionChain, transaction, path);
-            }
-        } else if (data instanceof AugmentationNode) {
-            for (final DataContainerChild<? extends PathArgument, ?> child : ((AugmentationNode) data).getValue()) {
-                putChild(child, transactionChain, transaction, path);
-            }
-        } else if (data instanceof ChoiceNode) {
-            for (final DataContainerChild<? extends PathArgument, ?> child : ((ChoiceNode) data).getValue()) {
-                putChild(child, transactionChain, transaction, path);
-            }
-        } else if (data instanceof LeafSetNode<?>) {
-            for (final LeafSetEntryNode<?> child : ((LeafSetNode<?>) data).getValue()) {
-                putChild(child, transactionChain, transaction, path);
-            }
-        } else if (data instanceof ContainerNode) {
-            for (final DataContainerChild<? extends PathArgument, ?> child : ((ContainerNode) data).getValue()) {
-                putChild(child, transactionChain, transaction, path);
+                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 {
-            transaction.cancel();
-            RestConnectorProvider.resetTransactionChainForAdapaters(transactionChain);
+            TransactionUtil.checkItemDoesNotExists(
+                    transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
+                    RestconfDataServiceConstant.PostData.POST_TX_TYPE);
 
-            final String errMsg = "Only Map, Choice, Augmentation, LeafSet and Container nodes are supported";
-            LOG.trace("{}:{}", errMsg, path);
-            throw new RestconfDocumentedException(
-                    "Node not supported", RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.BAD_ELEMENT, path);
+            TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
+            transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
         }
 
         return transaction.submit();
     }
 
-    /**
-     * Prepare data for submit
-     *
-     * @param child
-     *            - data
-     * @param transactionChain
-     *            - transaction chain
-     * @param readWriteTx
-     *            - transaction
-     * @param path
-     *            - path to data
-     */
-    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(
-                transactionChain, readWriteTx, LogicalDatastoreType.CONFIGURATION, childPath,
-                RestconfDataServiceConstant.PostData.POST_TX_TYPE);
-        readWriteTx.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
-    }
-
     /**
      * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}
      *
index 8c1a81c27862404bd76addffc133c8f093897859..c1fee42de5b1e8b357da3adc12e02ac84137fd89 100644 (file)
@@ -13,7 +13,6 @@ import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
-import com.google.common.base.Optional;
 import com.google.common.util.concurrent.Futures;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
@@ -39,7 +38,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 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.Builders;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
@@ -71,8 +69,9 @@ public class PostDataTransactionUtilTest {
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        refSchemaCtx = new SchemaContextRef(TestRestconfUtils.loadSchemaContext(PATH_FOR_NEW_SCHEMA_CONTEXT));
-        schema = refSchemaCtx.get();
+
+        this.refSchemaCtx = new SchemaContextRef(TestRestconfUtils.loadSchemaContext(PATH_FOR_NEW_SCHEMA_CONTEXT));
+        this.schema = this.refSchemaCtx.get();
 
         final QName baseQName = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
         final QName containerQname = QName.create(baseQName, "player");
@@ -81,7 +80,7 @@ public class PostDataTransactionUtilTest {
         final QName listKeyQname = QName.create(baseQName, "name");
         final YangInstanceIdentifier.NodeIdentifierWithPredicates nodeWithKey =
                 new YangInstanceIdentifier.NodeIdentifierWithPredicates(listQname, listKeyQname, "name of band");
-        iid2 = YangInstanceIdentifier.builder()
+        this.iid2 = YangInstanceIdentifier.builder()
                 .node(baseQName)
                 .build();
 
@@ -93,7 +92,8 @@ public class PostDataTransactionUtilTest {
                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(containerQname))
                 .withChild(buildLeaf)
                 .build();
-        buildBaseCont = Builders.containerBuilder()
+
+        this.buildBaseCont = Builders.containerBuilder()
                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(baseQName))
                 .withChild(buildPlayerCont)
                 .build();
@@ -111,70 +111,69 @@ public class PostDataTransactionUtilTest {
                 .withChild(content)
                 .withChild(content2)
                 .build();
-        buildList = Builders.mapBuilder()
+        this.buildList = Builders.mapBuilder()
                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(listQname))
                 .withChild(mapEntryNode)
                 .build();
 
-        doReturn(UriBuilder.fromUri("http://localhost:8181/restconf/15/")).when(uriInfo).getBaseUriBuilder();
-        doReturn(readWrite).when(transactionChain).newReadWriteTransaction();
-        doReturn(read).when(transactionChain).newReadOnlyTransaction();
+        doReturn(UriBuilder.fromUri("http://localhost:8181/restconf/17/")).when(this.uriInfo).getBaseUriBuilder();
+        doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
+        doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
     }
 
     @Test
     public void testPostContainerData() {
-        final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(iid2, null, null, schema);
-        final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, buildBaseCont);
+        final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(this.iid2, null, null, this.schema);
+        final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
 
-        doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read).read(LogicalDatastoreType.CONFIGURATION, iid2);
+        doReturn(Futures.immediateCheckedFuture(false)).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
         final YangInstanceIdentifier.NodeIdentifier identifier = ((ContainerNode) ((SingletonSet) payload.getData().getValue()).iterator().next()).getIdentifier();
         final YangInstanceIdentifier node = payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
-        doReturn(Futures.immediateCheckedFuture(false)).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
-        doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
-        doReturn(Futures.immediateCheckedFuture(null)).when(readWrite).submit();
-        final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChain);
-        final Response response = PostDataTransactionUtil.postData(uriInfo, payload, wrapper, refSchemaCtx);
+        doReturn(Futures.immediateCheckedFuture(false)).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+        doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
+        doReturn(Futures.immediateCheckedFuture(null)).when(this.readWrite).submit();
+        final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, this.transactionChain);
+        final Response response = PostDataTransactionUtil.postData(this.uriInfo, payload, wrapper, this.refSchemaCtx);
         assertEquals(201, response.getStatus());
-        verify(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
-        verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, (NormalizedNode<?, ?>) ((SingletonSet) payload.getData().getValue()).iterator().next());
+        verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
+        verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
     }
 
     @Test
     public void testPostListData() {
-        final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(iid2, null, null, schema);
-        final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, buildList);
+        final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(this.iid2, null, null, this.schema);
+        final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildList);
 
-        doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read).read(LogicalDatastoreType.CONFIGURATION, iid2);
         final MapNode data = (MapNode) payload.getData();
         final YangInstanceIdentifier.NodeIdentifierWithPredicates identifier = data.getValue().iterator().next().getIdentifier();
         final YangInstanceIdentifier node = payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
-        doReturn(Futures.immediateCheckedFuture(false)).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
-        doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
-        doReturn(Futures.immediateCheckedFuture(null)).when(readWrite).submit();
-        final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChain);
-        final Response response = PostDataTransactionUtil.postData(uriInfo, payload, wrapper, refSchemaCtx);
+        doReturn(Futures.immediateCheckedFuture(false)).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+        doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
+        doReturn(Futures.immediateCheckedFuture(null)).when(this.readWrite).submit();
+        final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, this.transactionChain);
+        final Response response = PostDataTransactionUtil.postData(this.uriInfo, payload, wrapper, this.refSchemaCtx);
         assertEquals(201, response.getStatus());
-        verify(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
-        verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, data.getValue().iterator().next());
+        verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+        verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, data.getValue().iterator().next());
     }
 
     @Test
     public void testPostDataFail() {
-        final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(iid2, null, null, schema);
-        final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, buildBaseCont);
+        final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(this.iid2, null, null, this.schema);
+        final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
 
-        doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read).read(LogicalDatastoreType.CONFIGURATION, iid2);
+        doReturn(Futures.immediateCheckedFuture(false)).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
         final YangInstanceIdentifier.NodeIdentifier identifier = ((ContainerNode) ((SingletonSet) payload.getData().getValue()).iterator().next()).getIdentifier();
         final YangInstanceIdentifier node = payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
-        doReturn(Futures.immediateCheckedFuture(false)).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
-        doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node,
+        doReturn(Futures.immediateCheckedFuture(false)).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+        doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node,
                 payload.getData());
-        doReturn(Futures.immediateFailedCheckedFuture(new DOMException((short) 414, "Post request failed"))).when(readWrite).submit();
-        final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChain);
-        final Response response = PostDataTransactionUtil.postData(uriInfo, payload, wrapper, refSchemaCtx);
+        doReturn(Futures.immediateFailedCheckedFuture(new DOMException((short) 414, "Post request failed"))).when(this.readWrite).submit();
+        final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, this.transactionChain);
+        final Response response = PostDataTransactionUtil.postData(this.uriInfo, payload, wrapper, this.refSchemaCtx);
         assertEquals(Response.Status.INTERNAL_SERVER_ERROR, response.getStatusInfo());
-        verify(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
-        verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, (NormalizedNode<?, ?>) ((SingletonSet) payload.getData().getValue()).iterator().next());
+        verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, iid2);
+        verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
     }
 
 }