BUG-1014: Moved recursive verify of written data to ready() 85/22885/2
authorTony Tkacik <ttkacik@cisco.com>
Tue, 16 Jun 2015 08:46:53 +0000 (10:46 +0200)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 26 Jun 2015 16:19:45 +0000 (16:19 +0000)
Moved recursive verify of written data to ready(), recursive
verify of written data needs only to be run for write and/or
merge.
For other operations validity of data was tested in previous
transactions or doing the walk of SchemaApplyOperation
to resolve necessary information.

Change-Id: I1958ff747225f87913e8eb603212228910e38df0
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
(cherry picked from commit eebec9b8c818d4c3b8437805809fdec67d2a6616)

18 files changed:
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractDataNodeContainerModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractNodeContainerModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractReadyIterator.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractValueNodeModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AlwaysFailOperation.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/MinMaxElementsValidation.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModificationApplyOperation.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ModifiedNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OperationWithModification.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OrderedLeafSetModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/OrderedMapModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/RootModificationApplyOperation.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnkeyedListModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnorderedLeafSetModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnorderedMapModificationStrategy.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ConfigStatementValidationTest.java

index 0260b3feb63224b691096a7fd326cd9ad5531294..f27477b78b1e2de1347cbdfeef03e59109cfdd65 100644 (file)
@@ -50,7 +50,7 @@ abstract class AbstractDataNodeContainerModificationStrategy<T extends DataNodeC
     private final TreeType treeType;
 
     protected AbstractDataNodeContainerModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass, final TreeType treeType) {
-        super(nodeClass);
+        super(nodeClass, treeType);
         this.schema = Preconditions.checkNotNull(schema,"schema");
         this.treeType = Preconditions.checkNotNull(treeType,"treeType");
     }
index 3e13dd454910e8f79c27c08c8d4582b2dcfe8d52..07f04ccc816a5172b5b403fc774ca7fdd00fbaee 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificat
 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.TreeType;
 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;
@@ -28,27 +29,31 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNo
 abstract class AbstractNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
 
     private final Class<? extends NormalizedNode<?, ?>> nodeClass;
+    private final boolean verifyChildrenStructure;
 
-    protected AbstractNodeContainerModificationStrategy(final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+    protected AbstractNodeContainerModificationStrategy(final Class<? extends NormalizedNode<?, ?>> nodeClass,
+            final TreeType treeType) {
         this.nodeClass = Preconditions.checkNotNull(nodeClass , "nodeClass");
+        this.verifyChildrenStructure = (treeType == TreeType.CONFIGURATION);
     }
 
     @SuppressWarnings("rawtypes")
     @Override
-    void verifyStructure(final NormalizedNode<?, ?> writtenValue) {
+    void verifyStructure(final NormalizedNode<?, ?> writtenValue, final boolean verifyChildren) {
         checkArgument(nodeClass.isInstance(writtenValue), "Node %s is not of type %s", writtenValue, nodeClass);
         checkArgument(writtenValue instanceof NormalizedNodeContainer);
-
-        final NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue;
-        for (final Object child : container.getValue()) {
-            checkArgument(child instanceof NormalizedNode);
-            final NormalizedNode<?, ?> castedChild = (NormalizedNode<?, ?>) child;
-            final Optional<ModificationApplyOperation> childOp = getChild(castedChild.getIdentifier());
-            if(childOp.isPresent()) {
-                childOp.get().verifyStructure(castedChild);
-            } else {
-                throw new SchemaValidationFailedException(String.format("Child %s is not valid child according to schema.",
-                        castedChild.getIdentifier()));
+        if (verifyChildrenStructure && verifyChildren) {
+            final NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue;
+            for (final Object child : container.getValue()) {
+                checkArgument(child instanceof NormalizedNode);
+                final NormalizedNode<?, ?> castedChild = (NormalizedNode<?, ?>) child;
+                final Optional<ModificationApplyOperation> childOp = getChild(castedChild.getIdentifier());
+                if (childOp.isPresent()) {
+                    childOp.get().verifyStructure(castedChild, verifyChildren);
+                } else {
+                    throw new SchemaValidationFailedException(String.format(
+                            "Child %s is not valid child according to schema.", castedChild.getIdentifier()));
+                }
             }
         }
     }
index 55911922499ff255b1ad3927cae4e629408f07ce..e7e80097dc3e2683a6c6d66dcdbf444e7fe1ad0b 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import java.util.Collection;
 import java.util.Iterator;
@@ -14,14 +15,17 @@ import java.util.Iterator;
 abstract class AbstractReadyIterator {
     final Iterator<ModifiedNode> children;
     final ModifiedNode node;
+    final ModificationApplyOperation op;
 
-    private AbstractReadyIterator(final ModifiedNode node, final Iterator<ModifiedNode> children) {
+    private AbstractReadyIterator(final ModifiedNode node, final Iterator<ModifiedNode> children,
+            final ModificationApplyOperation operation) {
         this.children = Preconditions.checkNotNull(children);
         this.node = Preconditions.checkNotNull(node);
+        this.op = Preconditions.checkNotNull(operation);
     }
 
-    static AbstractReadyIterator create(final ModifiedNode root) {
-        return new RootReadyIterator(root, root.getChildren().iterator());
+    static AbstractReadyIterator create(final ModifiedNode root, final ModificationApplyOperation operation) {
+        return new RootReadyIterator(root, root.getChildren().iterator(), operation);
     }
 
     final AbstractReadyIterator process() {
@@ -29,18 +33,22 @@ abstract class AbstractReadyIterator {
         // been modified. If a child
         while (children.hasNext()) {
             final ModifiedNode child = children.next();
+            final Optional<ModificationApplyOperation> childOperation = op.getChild(child.getIdentifier());
+            Preconditions.checkState(childOperation.isPresent(), "Schema for child %s is not present.",
+                    child.getIdentifier());
             final Collection<ModifiedNode> grandChildren = child.getChildren();
             if (grandChildren.isEmpty()) {
-                child.seal();
+
+                child.seal(childOperation.get());
                 if (child.getOperation() == LogicalOperation.NONE) {
                     children.remove();
                 }
             } else {
-                return new NestedReadyIterator(this, child, grandChildren.iterator());
+                return new NestedReadyIterator(this, child, grandChildren.iterator(), childOperation.get());
             }
         }
 
-        node.seal();
+        node.seal(op);
 
         // Remove from parent if we have one and this is a no-op
         if (node.getOperation() == LogicalOperation.NONE) {
@@ -55,8 +63,9 @@ abstract class AbstractReadyIterator {
     private static final class NestedReadyIterator extends AbstractReadyIterator {
         private final AbstractReadyIterator parent;
 
-        private NestedReadyIterator(final AbstractReadyIterator parent, final ModifiedNode node, final Iterator<ModifiedNode> children) {
-            super(node, children);
+        private NestedReadyIterator(final AbstractReadyIterator parent, final ModifiedNode node,
+                final Iterator<ModifiedNode> children, final ModificationApplyOperation operation) {
+            super(node, children, operation);
             this.parent = Preconditions.checkNotNull(parent);
         }
 
@@ -72,8 +81,9 @@ abstract class AbstractReadyIterator {
     }
 
     private static final class RootReadyIterator extends AbstractReadyIterator {
-        private RootReadyIterator(final ModifiedNode node, final Iterator<ModifiedNode> children) {
-            super(node, children);
+        private RootReadyIterator(final ModifiedNode node, final Iterator<ModifiedNode> children,
+                final ModificationApplyOperation operation) {
+            super(node, children, operation);
         }
 
         @Override
index 6291de5dbabaa63cd4537837c56417df12c4247d..bd23a4e46c905739d39a38bfadb81371545736e3 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
 import static com.google.common.base.Preconditions.checkArgument;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -30,7 +31,7 @@ abstract class AbstractValueNodeModificationStrategy<T extends DataSchemaNode> e
     }
 
     @Override
-    protected final void verifyStructure(final NormalizedNode<?, ?> writtenValue) {
+    protected final void verifyStructure(final NormalizedNode<?, ?> writtenValue, final boolean verifyChildren) {
         checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
     }
 
index f7719f2e05856c41f5711c9ae03f38111bff4490..b91d28f9b7d4516d095c37d9ad189024a492729a 100644 (file)
@@ -44,7 +44,7 @@ final class AlwaysFailOperation extends ModificationApplyOperation {
     }
 
     @Override
-    void verifyStructure(final NormalizedNode<?, ?> modification) {
+    void verifyStructure(final NormalizedNode<?, ?> modification, final boolean verifyChildren) {
         throw new IllegalStateException("Schema Context is not available.");
     }
 
index 8158792367be56c3e5231ef80378201ae9ec52bd..0f91a45c61f91e925a45d9493e36f4c354c9b987 100644 (file)
@@ -26,7 +26,7 @@ final class ChoiceModificationStrategy extends AbstractNodeContainerModification
     private final Map<YangInstanceIdentifier.PathArgument, ModificationApplyOperation> childNodes;
 
     ChoiceModificationStrategy(final ChoiceSchemaNode schemaNode, final TreeType treeType) {
-        super(ChoiceNode.class);
+        super(ChoiceNode.class, treeType);
         final ImmutableMap.Builder<YangInstanceIdentifier.PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
 
         for (final ChoiceCaseNode caze : schemaNode.getCases()) {
index a40b13a78c4aa55a7da55ae8ea9859bf121073ba..6ca6970637f249000a792bf796e4f635bd8dd531 100644 (file)
@@ -261,7 +261,7 @@ final class InMemoryDataTreeModification implements DataTreeModification {
         final boolean wasRunning = UPDATER.compareAndSet(this, 0, 1);
         Preconditions.checkState(wasRunning, "Attempted to seal an already-sealed Data Tree.");
 
-        AbstractReadyIterator current = AbstractReadyIterator.create(rootNode);
+        AbstractReadyIterator current = AbstractReadyIterator.create(rootNode, strategyTree);
         do {
             current = current.process();
         } while (current != null);
index c304cf16cf752bb74357e8f77e0f23a96c7aa1c5..7531723025731b047d4ae51a8785de5d0b7c93f3 100644 (file)
@@ -153,8 +153,8 @@ final class MinMaxElementsValidation extends SchemaAwareApplyOperation {
     }
 
     @Override
-    protected void verifyStructure(final NormalizedNode<?, ?> modification) {
-        delegate.verifyStructure(modification);
+    protected void verifyStructure(final NormalizedNode<?, ?> modification, final boolean verifyChildren) {
+        delegate.verifyStructure(modification, verifyChildren);
     }
 
     @Override
index 40eac7a1c5ac740dc3f0f4d66dbb74427426d501..cdeaa7c01adee901b4be7663c3b10afd37caaddf 100644 (file)
@@ -70,13 +70,16 @@ abstract class ModificationApplyOperation implements StoreTreeNode<ModificationA
 
     /**
      *
-     * Performs structural verification of NodeModification, such as writen values / types
-     * uses right structural elements.
+     * Performs structural verification of NodeModification, such as writen values / types uses
+     * right structural elements.
      *
-     * @param modification to be verified.
-     * @throws IllegalArgumentException If provided NodeModification does not adhere to the structure.
+     * @param modification data to be verified.
+     * @param verifyChildren true if structure verification should be run against children.
+     * @throws IllegalArgumentException If provided NodeModification does not adhere to the
+     *         structure.
      */
-    abstract void verifyStructure(NormalizedNode<?, ?> modification) throws IllegalArgumentException;
+    abstract void verifyStructure(NormalizedNode<?, ?> modification, boolean verifyChildren)
+            throws IllegalArgumentException;
 
     /**
      * Return the tracking policy for this node's children.
index 34aabf21cba93d0330dd0a6c742e27732b7e29ac..c42e5dd49c55b36ea9bed71fb0d1cf15a08c1daf 100644 (file)
@@ -233,14 +233,25 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode<Modif
     }
 
     /**
-     * Seal the modification node.
+     * Seal the modification node and prune any children which has not been modified.
+     * 
+     * @param schema
      */
-    void seal() {
+    void seal(final ModificationApplyOperation schema) {
         clearSnapshot();
 
         // A TOUCH node without any children is a no-op
-        if (operation == LogicalOperation.TOUCH && children.isEmpty()) {
-            updateOperationType(LogicalOperation.NONE);
+        switch (operation) {
+            case TOUCH:
+                if (children.isEmpty()) {
+                    updateOperationType(LogicalOperation.NONE);
+                }
+                break;
+            case WRITE:
+                schema.verifyStructure(value, true);
+                break;
+            default:
+                break;
         }
     }
 
index 27511507477d32fe14759f02e7818fcf85473d50..a375a90d74dcbca18df6ffb06ccb916727b7c09d 100644 (file)
@@ -28,7 +28,10 @@ final class OperationWithModification {
 
     void write(final NormalizedNode<?, ?> value) {
         modification.write(value);
-        applyOperation.verifyStructure(value);
+        /**
+         * Fast validation of structure, full validation on written data will be run during seal.
+         */
+        applyOperation.verifyStructure(value, false);
     }
 
     private void recursiveMerge(final NormalizedNode<?,?> data) {
@@ -64,14 +67,15 @@ final class OperationWithModification {
 
     void merge(final NormalizedNode<?, ?> data) {
         /*
-         * A merge operation will end up overwriting parts of the tree, retaining others.
-         * We want to make sure we do not validate the complete resulting structure, but
-         * rather just what was written. In order to do that, we first pretend the data
-         * was written, run verification and then perform the merge -- with the explicit
-         * assumption that adding the newly-validated data with the previously-validated
-         * data will not result in invalid data.
+         * A merge operation will end up overwriting parts of the tree, retaining others. We want to
+         * make sure we do not validate the complete resulting structure, but rather just what was
+         * written. In order to do that, we first pretend the data was written, run verification and
+         * then perform the merge -- with the explicit assumption that adding the newly-validated
+         * data with the previously-validated data will not result in invalid data.
+         *
+         * FIXME: Should be this moved to recursive merge and run for each node?
          */
-        applyOperation.verifyStructure(data);
+        applyOperation.verifyStructure(data, false);
         recursiveMerge(data);
     }
 
index cb058c08955add886d23df479bddef0e94ca0e3a..2e57dbbfc50d0007f109ffb09db7a4315b8d85ec 100644 (file)
@@ -24,7 +24,7 @@ final class OrderedLeafSetModificationStrategy extends AbstractNodeContainerModi
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema, final TreeType treeType) {
-        super((Class) LeafSetNode.class);
+        super((Class) LeafSetNode.class, treeType);
         entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
     }
 
index 6febd4e5cecf64577b2d7c324683f09af4d2b333..15db353a484153e3fe7631b97c55be6cda48d03e 100644 (file)
@@ -15,7 +15,7 @@ final class OrderedMapModificationStrategy extends AbstractNodeContainerModifica
     private final Optional<ModificationApplyOperation> entryStrategy;
 
     OrderedMapModificationStrategy(final ListSchemaNode schema, final TreeType treeType) {
-        super(OrderedMapNode.class);
+        super(OrderedMapNode.class, treeType);
         entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema, treeType));
     }
 
index d262d210c99696f87f5aeb3552c89d13881eb6cc..693ace4df2759b44f0b380ab70bd67d2bf6aa2e9 100644 (file)
@@ -94,8 +94,9 @@ abstract class RootModificationApplyOperation extends ModificationApplyOperation
     }
 
     @Override
-    final void verifyStructure(final NormalizedNode<?, ?> modification) throws IllegalArgumentException {
-        getDelegate().verifyStructure(modification);
+    final void verifyStructure(final NormalizedNode<?, ?> modification, final boolean verifyChildren)
+            throws IllegalArgumentException {
+        getDelegate().verifyStructure(modification, verifyChildren);
     }
 
     @Override
index 2cb33518996a74ded292c58ff5814052944c055a..32d73c9b61876aeeae38438c08a2eb71e1e87034 100644 (file)
@@ -123,7 +123,7 @@ final class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
     }
 
     @Override
-    protected void verifyStructure(final NormalizedNode<?, ?> writtenValue) {
+    protected void verifyStructure(final NormalizedNode<?, ?> writtenValue, final boolean verifyChildren) {
 
     }
 
index 8963f3cbce41114075b946ce23f7c3ba5627ca8d..8e001d0c7c3ab214f061c99c49bf5e9a3b3c0483 100644 (file)
@@ -23,7 +23,7 @@ final class UnorderedLeafSetModificationStrategy extends AbstractNodeContainerMo
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema, final TreeType treeType) {
-        super((Class) LeafSetNode.class);
+        super((Class) LeafSetNode.class, treeType);
         entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
     }
 
index a416b0d329e53aef8a22cfd008da278be42a0ca4..54aad342bcf0ea7fe82a5d60b8eaf21fc9c8ec8b 100644 (file)
@@ -22,7 +22,7 @@ final class UnorderedMapModificationStrategy extends AbstractNodeContainerModifi
     private final Optional<ModificationApplyOperation> entryStrategy;
 
     UnorderedMapModificationStrategy(final ListSchemaNode schema, final TreeType treeType) {
-        super(MapNode.class);
+        super(MapNode.class, treeType);
         entryStrategy = Optional.<ModificationApplyOperation>of(new ListEntryModificationStrategy(schema, treeType));
     }
 
index a3c5dc772efb8c52bc4296795d6f9031823f5e0d..0a9182c1887e0fa61a6477d7e2f0961254bd3712 100644 (file)
@@ -109,7 +109,7 @@ public class ConfigStatementValidationTest {
         inMemoryDataTree.setSchemaContext(schemaContext);
         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
         modificationTree.write(TestModel.TEST_PATH, createFooTestContainerNode());
-
+        modificationTree.ready();
         inMemoryDataTree.validate(modificationTree);
         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
         inMemoryDataTree.commit(prepare);
@@ -122,7 +122,7 @@ public class ConfigStatementValidationTest {
         inMemoryDataTree.setSchemaContext(schemaContext);
         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
         modificationTree.write(TestModel.TEST_PATH, createBarTestContainerNode());
-
+        modificationTree.ready();
         inMemoryDataTree.validate(modificationTree);
         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
         inMemoryDataTree.commit(prepare);
@@ -162,7 +162,7 @@ public class ConfigStatementValidationTest {
 
         final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
         modificationTree.write(ii, choice1);
-
+        modificationTree.ready();
         inMemoryDataTree.validate(modificationTree);
         final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
         inMemoryDataTree.commit(prepare);