BUG-4295: instantiate MERGE operations lazily
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / OperationWithModification.java
index 511fc322cbd8b2b402ec50c56798fcd13b9828a2..d22854dc889b21d06e57ca11928dd74e9281badf 100644 (file)
@@ -7,33 +7,86 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
-
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
 
 final class OperationWithModification {
+    private static final Function<TreeNode, NormalizedNode<?, ?>> READ_DATA = new Function<TreeNode, NormalizedNode<?, ?>>() {
+        @Override
+        public NormalizedNode<?, ?> apply(final TreeNode input) {
+            return input.getData();
+        }
+    };
 
     private final ModifiedNode modification;
-
     private final ModificationApplyOperation applyOperation;
 
     private OperationWithModification(final ModificationApplyOperation op, final ModifiedNode mod) {
-        this.modification = mod;
-        this.applyOperation = op;
+        this.modification = Preconditions.checkNotNull(mod);
+        this.applyOperation = Preconditions.checkNotNull(op);
     }
 
-    public OperationWithModification write(final NormalizedNode<?, ?> value) {
+    void write(final NormalizedNode<?, ?> value) {
         modification.write(value);
-        applyOperation.verifyStructure(modification);
-        return this;
+        /**
+         * Fast validation of structure, full validation on written data will be run during seal.
+         */
+        applyOperation.verifyStructure(value, false);
+    }
+
+    void merge(final NormalizedNode<?, ?> data, final Version version) {
+        /*
+         * 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.
+         */
+        applyOperation.verifyStructure(data, true);
+        applyOperation.mergeIntoModifiedNode(modification, data, version);
     }
 
-    public OperationWithModification delete() {
+    void delete() {
         modification.delete();
-        return this;
+    }
+
+    /**
+     * Read a particular child. If the child has been modified and does not have a stable
+     * view, one will we instantiated with specified version.
+     *
+     * @param child
+     * @param version
+     * @return
+     */
+    Optional<NormalizedNode<?, ?>> read(final PathArgument child, final Version version) {
+        final Optional<ModifiedNode> maybeChild = modification.getChild(child);
+        if (maybeChild.isPresent()) {
+            final ModifiedNode childNode = maybeChild.get();
+
+            Optional<TreeNode> snapshot = childNode.getSnapshot();
+            if (snapshot == null) {
+                // Snapshot is not present, force instantiation
+                snapshot = applyOperation.getChild(child).get().apply(childNode, childNode.getOriginal(), version);
+            }
+
+            return snapshot.transform(READ_DATA);
+        }
+
+        Optional<TreeNode> snapshot = modification.getSnapshot();
+        if (snapshot == null) {
+            snapshot = apply(modification.getOriginal(), version);
+        }
+
+        if (snapshot.isPresent()) {
+            return snapshot.get().getChild(child).transform(READ_DATA);
+        }
+
+        return Optional.absent();
     }
 
     public ModifiedNode getModification() {
@@ -51,18 +104,5 @@ final class OperationWithModification {
     public static OperationWithModification from(final ModificationApplyOperation operation,
             final ModifiedNode modification) {
         return new OperationWithModification(operation, modification);
-
-    }
-
-    public void merge(final NormalizedNode<?, ?> data) {
-        modification.merge(data);
-        applyOperation.verifyStructure(modification);
-
-    }
-
-    public OperationWithModification forChild(final PathArgument childId) {
-        ModifiedNode childMod = modification.modifyChild(childId);
-        Optional<ModificationApplyOperation> childOp = applyOperation.getChild(childId);
-        return from(childOp.get(),childMod);
     }
 }