Convert MinMaxElementsValidation to ModificationApplyOperation 38/80038/1
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 30 Jan 2019 17:12:03 +0000 (18:12 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 30 Jan 2019 17:12:03 +0000 (18:12 +0100)
This removes the fragile piggy-backing onto SchemaAwareOperation,
as done as part of YANGTOOLS-909 and modifying it to take advantage
of DelegatingModificationApplyOperation. This allows us to hide
SchemaAwareApplyOperation's checkWriteApplicable().

Change-Id: I804ddb5e4c8b7562bde11994be8b1a5615228d7c
JIRA: YANGTOOLS-944
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
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/ModifiedNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java

index 02335ff6765a2cb82181a7a09ffe80ce6673952b..2c6ec20a2002c447beacc9db07009e6e08bfa0e3 100644 (file)
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Verify;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
 import java.util.Optional;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -24,7 +25,7 @@ import org.opendaylight.yangtools.yang.model.api.ElementCountConstraintAware;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-final class MinMaxElementsValidation extends SchemaAwareApplyOperation {
+final class MinMaxElementsValidation extends DelegatingModificationApplyOperation {
     private static final Logger LOG = LoggerFactory.getLogger(MinMaxElementsValidation.class);
 
     private final SchemaAwareApplyOperation delegate;
@@ -33,12 +34,12 @@ final class MinMaxElementsValidation extends SchemaAwareApplyOperation {
 
     private MinMaxElementsValidation(final SchemaAwareApplyOperation delegate, final Integer minElements,
             final Integer maxElements) {
-        this.delegate = Preconditions.checkNotNull(delegate);
+        this.delegate = requireNonNull(delegate);
         this.minElements = minElements != null ? minElements : 0;
         this.maxElements = maxElements != null ? maxElements : Integer.MAX_VALUE;
     }
 
-    static SchemaAwareApplyOperation from(final SchemaAwareApplyOperation delegate, final DataSchemaNode schema) {
+    static ModificationApplyOperation from(final SchemaAwareApplyOperation delegate, final DataSchemaNode schema) {
         if (!(schema instanceof ElementCountConstraintAware)) {
             return delegate;
         }
@@ -52,35 +53,38 @@ final class MinMaxElementsValidation extends SchemaAwareApplyOperation {
         return new MinMaxElementsValidation(delegate, constraint.getMinElements(), constraint.getMaxElements());
     }
 
-    private void validateMinMaxElements(final ModificationPath path, final PathArgument id,
-            final NormalizedNode<?, ?> data) throws DataValidationFailedException {
-        final int children = numOfChildrenFromValue(data);
-        if (minElements > children) {
-            throw new RequiredElementCountException(path.toInstanceIdentifier(), minElements, maxElements,
-                children, "%s does not have enough elements (%s), needs at least %s", id, children, minElements);
-        }
-        if (maxElements < children) {
-            throw new RequiredElementCountException(path.toInstanceIdentifier(), minElements, maxElements,
-                children, "%s has too many elements (%s), can have at most %s", id, children, maxElements);
+    @Override
+    ModificationApplyOperation delegate() {
+        return delegate;
+    }
+
+    @Override
+    Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> storeMeta,
+            final Version version) {
+        Optional<TreeNode> ret = modification.getValidatedNode(this, storeMeta);
+        if (ret == null) {
+            // Deal with the result moving on us
+            ret = delegate.apply(modification, storeMeta, version);
+            checkChildren(modification.getIdentifier(), numOfChildrenFromTreeNode(ret));
         }
+        return ret;
     }
 
-    private void checkMinMaxElements(final ModificationPath path, final NodeModification nodeMod,
+    @Override
+    void checkApplicable(final ModificationPath path, final NodeModification modification,
             final Optional<TreeNode> current, final Version version) throws DataValidationFailedException {
-        if (!(nodeMod instanceof ModifiedNode)) {
-            LOG.debug("Could not validate {}, does not implement expected class {}", nodeMod, ModifiedNode.class);
+        delegate.checkApplicable(path, modification, current, version);
+
+        if (!(modification instanceof ModifiedNode)) {
+            LOG.debug("Could not validate {}, does not implement expected class {}", modification, ModifiedNode.class);
             return;
         }
+        final ModifiedNode modified = (ModifiedNode) modification;
 
-        final ModifiedNode modification = (ModifiedNode) nodeMod;
-
-        // We need to actually perform the operation to get deal with merge in a sane manner. We know the modification
+        // We need to actually perform the operation to deal with merge in a sane manner. We know the modification
         // is immutable, so the result of validation will probably not change.
-        final Optional<TreeNode> maybeApplied = delegate.apply(modification, current, version);
-        Verify.verify(maybeApplied.isPresent());
-
-        final TreeNode applied = maybeApplied.get();
-        validateMinMaxElements(path, modification.getIdentifier(), applied.getData());
+        final Optional<TreeNode> maybeApplied = delegate.apply(modified, current, version);
+        validateMinMaxElements(path, modified.getIdentifier(), numOfChildrenFromTreeNode(maybeApplied));
 
         // Everything passed. We now have a snapshot of the result node, it would be too bad if we just threw it out.
         // We know what the result of an apply operation is going to be *if* the following are kept unchanged:
@@ -88,107 +92,49 @@ final class MinMaxElementsValidation extends SchemaAwareApplyOperation {
         // - the schemacontext (therefore, the fact this object is associated with the modification)
         //
         // So let's stash the result. We will pick it up during apply operation.
-        modification.setValidatedNode(this, current, applied);
-    }
-
-    private static int numOfChildrenFromValue(final NormalizedNode<?, ?> value) {
-        if (value instanceof NormalizedNodeContainer) {
-            return ((NormalizedNodeContainer<?, ?, ?>) value).getValue().size();
-        } else if (value instanceof UnkeyedListNode) {
-            return ((UnkeyedListNode) value).getSize();
-        }
-
-        throw new IllegalArgumentException(String.format(
-                "Unexpected type '%s', expected types are NormalizedNodeContainer and UnkeyedListNode",
-                value.getClass()));
-    }
-
-    @Override
-    protected void checkTouchApplicable(final ModificationPath path, final NodeModification modification,
-            final Optional<TreeNode> current, final Version version) throws DataValidationFailedException {
-        delegate.checkTouchApplicable(path, modification, current, version);
-        checkMinMaxElements(path, modification, current, version);
-    }
-
-    @Override
-    protected void checkMergeApplicable(final ModificationPath path, final NodeModification modification,
-            final Optional<TreeNode> current, final Version version) throws DataValidationFailedException {
-        delegate.checkMergeApplicable(path, modification, current, version);
-        checkMinMaxElements(path, modification, current, version);
+        modified.setValidatedNode(this, current, maybeApplied);
     }
 
     @Override
-    protected void checkWriteApplicable(final ModificationPath path, final NodeModification modification,
-            final Optional<TreeNode> current, final Version version) throws DataValidationFailedException {
-        delegate.checkWriteApplicable(path, modification, current, version);
-        checkMinMaxElements(path, modification, current, version);
-    }
-
-    @Override
-    public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
-        return delegate.getChild(child);
-    }
-
-    @Override
-    protected void verifyStructure(final NormalizedNode<?, ?> modification, final boolean verifyChildren) {
+    void verifyStructure(final NormalizedNode<?, ?> modification, final boolean verifyChildren) {
         delegate.verifyStructure(modification, verifyChildren);
         if (verifyChildren) {
-            final int children = numOfChildrenFromValue(modification);
-            Preconditions.checkArgument(minElements <= children,
-                    "Node %s does not have enough elements (%s), needs at least %s", modification.getIdentifier(),
-                    children, minElements);
-            Preconditions.checkArgument(maxElements >= children,
-                    "Node %s has too many elements (%s), can have at most %s", modification.getIdentifier(), children,
-                    maxElements);
+            checkChildren(modification.getIdentifier(), numOfChildrenFromValue(modification));
         }
     }
 
-    @Override
-    protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta, final Version version) {
-        final TreeNode validated = modification.getValidatedNode(this, Optional.of(currentMeta));
-        if (validated != null) {
-            return validated;
+    private void validateMinMaxElements(final ModificationPath path, final PathArgument id, final int children)
+            throws DataValidationFailedException {
+        if (minElements > children) {
+            throw new RequiredElementCountException(path.toInstanceIdentifier(), minElements, maxElements,
+                children, "%s does not have enough elements (%s), needs at least %s", id, children, minElements);
         }
-
-        // FIXME: the result moved, make sure we enforce again
-        return delegate.applyMerge(modification, currentMeta, version);
-    }
-
-    @Override
-    protected TreeNode applyTouch(final ModifiedNode modification, final TreeNode currentMeta, final Version version) {
-        final TreeNode validated = modification.getValidatedNode(this, Optional.of(currentMeta));
-        if (validated != null) {
-            return validated;
+        if (maxElements < children) {
+            throw new RequiredElementCountException(path.toInstanceIdentifier(), minElements, maxElements,
+                children, "%s has too many elements (%s), can have at most %s", id, children, maxElements);
         }
-
-        // FIXME: the result moved, make sure we enforce again
-        return delegate.applyTouch(modification, currentMeta, version);
     }
 
-    @Override
-    protected TreeNode applyWrite(final ModifiedNode modification, final NormalizedNode<?, ?> newValue,
-            final Optional<TreeNode> currentMeta, final Version version) {
-        final TreeNode validated = modification.getValidatedNode(this, currentMeta);
-        if (validated != null) {
-            return validated;
-        }
-
-        // FIXME: the result moved, make sure we enforce again
-        return delegate.applyWrite(modification, newValue, currentMeta, version);
+    private void checkChildren(final PathArgument id, final int children) {
+        checkArgument(minElements <= children, "Node %s does not have enough elements (%s), needs at least %s", id,
+                children, minElements);
+        checkArgument(maxElements >= children, "Node %s has too many elements (%s), can have at most %s", id, children,
+                maxElements);
     }
 
-    @Override
-    protected ChildTrackingPolicy getChildPolicy() {
-        return delegate.getChildPolicy();
+    private static int numOfChildrenFromTreeNode(final Optional<TreeNode> node) {
+        return node.isPresent() ? numOfChildrenFromValue(node.get().getData()) : 0;
     }
 
-    @Override
-    void mergeIntoModifiedNode(final ModifiedNode node, final NormalizedNode<?, ?> value, final Version version) {
-        delegate.mergeIntoModifiedNode(node, value, version);
-    }
+    private static int numOfChildrenFromValue(final NormalizedNode<?, ?> value) {
+        if (value instanceof NormalizedNodeContainer) {
+            return ((NormalizedNodeContainer<?, ?, ?>) value).getValue().size();
+        } else if (value instanceof UnkeyedListNode) {
+            return ((UnkeyedListNode) value).getSize();
+        }
 
-    @Override
-    void recursivelyVerifyStructure(final NormalizedNode<?, ?> value) {
-        delegate.recursivelyVerifyStructure(value);
+        throw new IllegalArgumentException(String.format(
+                "Unexpected type '%s', expected types are NormalizedNodeContainer and UnkeyedListNode",
+                value.getClass()));
     }
 }
index 699a785bd856b9572234f6aea00bd2d42af7c74c..b4bf65fc0dbf5f38a3a25baa5d53558fd86d8ae9 100644 (file)
@@ -68,9 +68,9 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode<Modif
     private TreeNode writtenOriginal;
 
     // Internal cache for TreeNodes created as part of validation
-    private SchemaAwareApplyOperation validatedOp;
+    private ModificationApplyOperation validatedOp;
     private Optional<TreeNode> validatedCurrent;
-    private TreeNode validatedNode;
+    private Optional<TreeNode> validatedNode;
 
     private ModifiedNode(final PathArgument identifier, final Optional<TreeNode> original,
             final ChildTrackingPolicy childPolicy) {
@@ -348,13 +348,14 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode<Modif
         return new ModifiedNode(metadataTree.getIdentifier(), Optional.of(metadataTree), childPolicy);
     }
 
-    void setValidatedNode(final SchemaAwareApplyOperation op, final Optional<TreeNode> current, final TreeNode node) {
+    void setValidatedNode(final ModificationApplyOperation op, final Optional<TreeNode> current,
+            final Optional<TreeNode> node) {
         this.validatedOp = requireNonNull(op);
         this.validatedCurrent = requireNonNull(current);
         this.validatedNode = requireNonNull(node);
     }
 
-    TreeNode getValidatedNode(final SchemaAwareApplyOperation op, final Optional<TreeNode> current) {
+    Optional<TreeNode> getValidatedNode(final ModificationApplyOperation op, final Optional<TreeNode> current) {
         return op.equals(validatedOp) && current.equals(validatedCurrent) ? validatedNode : null;
     }
 }
index d50ad5a7c61b138f0d2e8ea7592f2c6e4fd086b8..43bb4bc5c68a196792de46a094e3b2c4bd0de72f 100644 (file)
@@ -82,7 +82,7 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation {
         }
     }
 
-    private static SchemaAwareApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode,
+    private static ModificationApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode,
             final DataTreeConfiguration treeConfig) {
         final List<QName> keyDefinition = schemaNode.getKeyDefinition();
         final SchemaAwareApplyOperation op;
@@ -96,7 +96,7 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation {
         return MinMaxElementsValidation.from(op, schemaNode);
     }
 
-    private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode,
+    private static ModificationApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode,
             final DataTreeConfiguration treeConfig) {
         final SchemaAwareApplyOperation op;
         if (schemaNode.isUserOrdered()) {
@@ -173,7 +173,7 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation {
      * @param current current node in TreeNode for modification to apply
      * @throws DataValidationFailedException when a data dependency conflict is detected
      */
-    protected void checkWriteApplicable(final ModificationPath path, final NodeModification modification,
+    private static void checkWriteApplicable(final ModificationPath path, final NodeModification modification,
             final Optional<TreeNode> current, final Version version) throws DataValidationFailedException {
         final Optional<TreeNode> original = modification.getOriginal();
         if (original.isPresent() && current.isPresent()) {