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 3293a05b066edea7cc77a9e51796794063fd4c4c..d22854dc889b21d06e57ca11928dd74e9281badf 100644 (file)
@@ -7,60 +7,88 @@
  */
 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.NormalizedNodeContainer;
 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);
     }
 
     void write(final NormalizedNode<?, ?> value) {
         modification.write(value);
-        applyOperation.verifyStructure(modification);
-    }
-
-    private void recursiveMerge(final NormalizedNode<?,?> data) {
-        if (data instanceof NormalizedNodeContainer<?,?,?>) {
-            @SuppressWarnings({ "rawtypes", "unchecked" })
-            NormalizedNodeContainer<?,?,NormalizedNode<PathArgument, ?>> dataContainer = (NormalizedNodeContainer) data;
-            for (NormalizedNode<PathArgument, ?> child : dataContainer.getValue()) {
-                PathArgument childId = child.getIdentifier();
-                forChild(childId).recursiveMerge(child);
-            }
-        }
-
-        modification.merge(data);
+        /**
+         * Fast validation of structure, full validation on written data will be run during seal.
+         */
+        applyOperation.verifyStructure(value, false);
     }
 
-    void merge(final NormalizedNode<?, ?> data) {
+    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.
+         * 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(modification.asNewlyWritten(data));
-        recursiveMerge(data);
+        applyOperation.verifyStructure(data, true);
+        applyOperation.mergeIntoModifiedNode(modification, data, version);
     }
 
     void delete() {
         modification.delete();
     }
 
+    /**
+     * 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() {
         return modification;
     }
@@ -77,19 +105,4 @@ final class OperationWithModification {
             final ModifiedNode modification) {
         return new OperationWithModification(operation, modification);
     }
-
-    private OperationWithModification forChild(final PathArgument childId) {
-        ModificationApplyOperation childOp = applyOperation.getChild(childId).get();
-
-        final boolean isOrdered;
-        if (childOp instanceof SchemaAwareApplyOperation) {
-            isOrdered = ((SchemaAwareApplyOperation) childOp).isOrdered();
-        } else {
-            isOrdered = true;
-        }
-
-        ModifiedNode childMod = modification.modifyChild(childId, isOrdered);
-
-        return from(childOp,childMod);
-    }
 }