Bug 1363: Introduced ModifiedNodeDoesNotExistsException. 58/9058/3
authorTony Tkacik <ttkacik@cisco.com>
Wed, 16 Jul 2014 11:50:53 +0000 (13:50 +0200)
committerTony Tkacik <ttkacik@cisco.com>
Wed, 23 Jul 2014 10:47:26 +0000 (12:47 +0200)
Introduced new checked exception ModifiedNodeDoesNotExists.
This exception is thrown when node which has subtree
modification did not exist at time of transaction allocation
and also do not exist when allocation was processed
to be commited.

Change-Id: I54f040034b43bfaf4bdda089ad9d2378ddd6ab09
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/ModifiedNodeDoesNotExistException.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NormalizedNodeContainerModificationStrategy.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ErrorReportingTest.java [new file with mode: 0644]

diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/ModifiedNodeDoesNotExistException.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/ModifiedNodeDoesNotExistException.java
new file mode 100644 (file)
index 0000000..068fe09
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.yangtools.yang.data.api.schema.tree;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+/**
+ * Exception thrown when a proposed change fails validation before being
+ * applied into the Data Tree because tree node which child nodes are
+ * modified or written did not exist when transaction started
+ * and still does not exists when transaction is processed.
+ *
+ * Note if node existed in first place and was removed by other transaction,
+ * thrown exception should be {@link ConflictingModificationAppliedException}.
+ *
+ *
+ */
+public class ModifiedNodeDoesNotExistException extends DataValidationFailedException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    public ModifiedNodeDoesNotExistException(final InstanceIdentifier path, final String message, final Throwable cause) {
+        super(path, message, cause);
+    }
+
+    public ModifiedNodeDoesNotExistException(final InstanceIdentifier path, final String message) {
+        super(path, message);
+    }
+
+}
index e868dc92aca62a7d7c4726169cbed9622df48cfd..a59a8718a5d6ebd3469f62f3df91bfbb088c41b2 100644 (file)
@@ -7,9 +7,10 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.Map;
+
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
@@ -23,6 +24,7 @@ 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.tree.DataValidationFailedException;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.MutableTreeNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory;
@@ -40,9 +42,9 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkArgument;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 
 abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
 
@@ -164,10 +166,17 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
     @Override
     protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
             final Optional<TreeNode> current) throws DataValidationFailedException {
+        checkDoesNotExists(path, modification.getOriginal().isPresent() || current.isPresent(), "Node does not exist. Could not modify its children.");
         SchemaAwareApplyOperation.checkConflicting(path, current.isPresent(), "Node was deleted by other transaction.");
         checkChildPreconditions(path, modification, current);
     }
 
+    private static void checkDoesNotExists(final InstanceIdentifier path, final boolean condition, final String message) throws DataValidationFailedException {
+        if(!condition) {
+            throw new ModifiedNodeDoesNotExistException(path,message);
+        }
+    }
+
     private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataValidationFailedException {
         final TreeNode currentMeta = current.get();
         for (NodeModification childMod : modification.getChildren()) {
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ErrorReportingTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ErrorReportingTest.java
new file mode 100644 (file)
index 0000000..4388f3d
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.yangtools.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+
+public class ErrorReportingTest {
+
+    private InMemoryDataTree tree;
+
+    @Before
+    public void setup() {
+        tree = InMemoryDataTreeFactory.getInstance().create();
+        tree.setSchemaContext(TestModel.createTestContext());
+    }
+
+    @Test
+    public void writeWithoutParentExisting() {
+        InMemoryDataTreeModification modification = tree.takeSnapshot().newModification();
+        // We write node without creating parent
+        modification.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+        modification.ready();
+        try {
+            tree.validate(modification);
+            fail("ModifiedNodeDoesNotExistException should be raised");
+        } catch (ModifiedNodeDoesNotExistException e) {
+            assertEquals(TestModel.TEST_PATH, e.getPath());
+        } catch (DataValidationFailedException e) {
+            fail("ModifiedNodeDoesNotExistException expected");
+        }
+    }
+
+    @Test
+    public void parentConcurrentlyDeletedExisting() {
+        InMemoryDataTreeModification initial = tree.takeSnapshot().newModification();
+        // We write node without creating parent
+        initial.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+        initial.ready();
+        // We commit transaction
+        tree.commit(tree.prepare(initial));
+
+        InMemoryDataTreeModification writeTx = tree.takeSnapshot().newModification();
+        InMemoryDataTreeModification deleteTx = tree.takeSnapshot().newModification();
+        deleteTx.delete(TestModel.TEST_PATH);
+        deleteTx.ready();
+        // We commit delete modification
+        tree.commit(tree.prepare(deleteTx));
+
+        writeTx.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+        try {
+            tree.validate(writeTx);
+            fail("ConflictingModificationAppliedException should be raised");
+        } catch (ConflictingModificationAppliedException e) {
+            assertEquals(TestModel.TEST_PATH, e.getPath());
+        } catch (DataValidationFailedException e) {
+            fail("ConflictingModificationAppliedException expected");
+        }
+
+    }
+
+}