Bug 5968: Mandatory leaf enforcement does not work in some cases
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / ModifiedNode.java
index 26261bdfba9a0913622a73dfc7f28550cd5b32ca..e1757a0a7441a450d7e35bb73147eff0f03effc9 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.base.Predicate;
 import java.util.Collection;
 import java.util.Map;
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 import javax.annotation.concurrent.NotThreadSafe;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -38,11 +37,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
  */
 @NotThreadSafe
 final class ModifiedNode extends NodeModification implements StoreTreeNode<ModifiedNode> {
-    static final Predicate<ModifiedNode> IS_TERMINAL_PREDICATE = new Predicate<ModifiedNode>() {
-        @Override
-        public boolean apply(@Nullable final ModifiedNode input) {
-            Preconditions.checkNotNull(input);
-            switch (input.getOperation()) {
+    static final Predicate<ModifiedNode> IS_TERMINAL_PREDICATE = input -> {
+        Preconditions.checkNotNull(input);
+        switch (input.getOperation()) {
             case DELETE:
             case MERGE:
             case WRITE:
@@ -50,10 +47,9 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode<Modif
             case TOUCH:
             case NONE:
                 return false;
-            }
-
-            throw new IllegalArgumentException(String.format("Unhandled modification type %s", input.getOperation()));
         }
+
+        throw new IllegalArgumentException(String.format("Unhandled modification type %s", input.getOperation()));
     };
 
     private final Map<PathArgument, ModifiedNode> children;
@@ -119,7 +115,7 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode<Modif
     }
 
     private Optional<TreeNode> metadataFromSnapshot(@Nonnull final PathArgument child) {
-        return original.isPresent() ? original.get().getChild(child) : Optional.<TreeNode>absent();
+        return original.isPresent() ? original.get().getChild(child) : Optional.absent();
     }
 
     private Optional<TreeNode> metadataFromData(@Nonnull final PathArgument child, final Version modVersion) {
@@ -279,6 +275,7 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode<Modif
                 if (children.isEmpty()) {
                     updateOperationType(LogicalOperation.NONE);
                 }
+
                 break;
             case WRITE:
                 // A WRITE can collapse all of its children
@@ -289,6 +286,18 @@ final class ModifiedNode extends NodeModification implements StoreTreeNode<Modif
 
                 schema.verifyStructure(value, true);
                 break;
+            /*
+             * Perform full validation in case of merge operation. This validation is performed during sealing of
+             * a ModifiedNode when we run InMemoryDataTreeModification.ready() just as it is in case of write operation
+             * above.
+             *
+             * Some parts of this validation may also be re-done during InMemoryDataTree.prepare() in case when we
+             * merge or write a MapEntry directly (e.g. Bug5968MergeTest.mergeValidMapEntryTest()), however in other
+             * cases full validation is performed only once just here.
+             */
+            case MERGE:
+                schema.verifyStructure(schema.apply(this, getOriginal(), version).get().getData(), true);
+                break;
             default:
                 break;
         }