BUG-4295: instantiate MERGE operations lazily
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / RootModificationApplyOperation.java
index fd3b73473aa01eb34804be16fc18b76f5a55d236..6fc704c053c32bb38212673580bbb88948955bba 100644 (file)
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import com.google.common.base.Optional;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+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.DataValidationFailedException;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
 
-import com.google.common.base.Optional;
-
-public abstract class RootModificationApplyOperation implements ModificationApplyOperation {
+/**
+ * Represents a {@link ModificationApplyOperation} which is rooted at conceptual
+ * top of data tree.
+ *
+ * <p>
+ * This implementation differs from other implementations in this package that
+ * is not immutable, but may be upgraded to newer state if available by
+ * explicitly invoking {@link #upgradeIfPossible()} and also serves as factory
+ * for deriving snapshot {@link RootModificationApplyOperation} which will not
+ * be affected by upgrade of original one.
+ *
+ * <p>
+ * There are two variations of this {@link ModificationApplyOperation}:
+ * <ul>
+ * <li>
+ * <b>Upgradable</b> - operation may be upgraded to different backing
+ * implementation by invoking {@link #upgradeIfPossible()}.</li>
+ * <li><b>Not Upgradable</b> - operation is immutable, invocation of
+ * {@link #upgradeIfPossible()} is no-op and method {@link #snapshot()} returns
+ * pointer on same object.
+ *
+ * <h3>Upgradable Root Modification Operation</h3>
+ *
+ * Upgradable Root Modification Operation may be created using:
+ * <ul>
+ * <li> {@link #from(ModificationApplyOperation)} with other upgradable root
+ * modification as an argument
+ * <li>using factory {@link LatestOperationHolder} which instantiates Upgradable
+ * Root Modification Operations and provides an option to set latest
+ * implementation.
+ * </ul>
+ * <p>
+ * Upgradable root operation is never upgraded to latest operation
+ * automatically, but client code must explicitly invoke
+ * {@link #upgradeIfPossible()} to get latest implementation.
+ *
+ * Note: This is helpful for implementing
+ * {@link org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification}
+ * which may be derived from
+ * {@link org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree} before
+ * update of schema and user actually writes data after schema update. During
+ * update user did not invoked any operation.
+ *
+ */
+abstract class RootModificationApplyOperation extends ModificationApplyOperation {
 
     @Override
-    public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+    public final Optional<ModificationApplyOperation> getChild(final PathArgument child) {
         return getDelegate().getChild(child);
     }
 
     @Override
-    public final void checkApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current)
+    final void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current)
             throws DataValidationFailedException {
         getDelegate().checkApplicable(path, modification, current);
     }
 
     @Override
-    public final Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> currentMeta, final Version version) {
+    final Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> currentMeta,
+            final Version version) {
         return getDelegate().apply(modification, currentMeta, version);
     }
 
     @Override
-    public boolean equals(final Object obj) {
+    public final boolean equals(final Object obj) {
         return getDelegate().equals(obj);
     }
 
     @Override
-    public int hashCode() {
+    public final int hashCode() {
         return getDelegate().hashCode();
     }
 
     @Override
-    public String toString() {
+    public final String toString() {
         return getDelegate().toString();
     }
 
     @Override
-    public void verifyStructure(final ModifiedNode modification) throws IllegalArgumentException {
-        getDelegate().verifyStructure(modification);
+    final void verifyStructure(final NormalizedNode<?, ?> modification, final boolean verifyChildren)
+            throws IllegalArgumentException {
+        getDelegate().verifyStructure(modification, verifyChildren);
     }
 
-    abstract ModificationApplyOperation getDelegate();
-
-    public abstract RootModificationApplyOperation snapshot();
-
-    public abstract void upgradeIfPossible();
-
-
-
-    public static RootModificationApplyOperation from(final ModificationApplyOperation resolver) {
-        if(resolver instanceof RootModificationApplyOperation) {
-            return ((RootModificationApplyOperation) resolver).snapshot();
-        }
-        return new NotUpgradable(resolver);
+    @Override
+    void recursivelyVerifyStructure(NormalizedNode<?, ?> value) {
+        getDelegate().recursivelyVerifyStructure(value);
     }
 
-    private static final class Upgradable extends RootModificationApplyOperation {
-
-        private final LatestOperationHolder holder;
-        private ModificationApplyOperation delegate;
-
-
-        public Upgradable(final LatestOperationHolder holder, final ModificationApplyOperation delegate) {
-            this.holder = holder;
-            this.delegate = delegate;
-
-        }
-
-        @Override
-        public void upgradeIfPossible() {
-            ModificationApplyOperation holderCurrent = holder.getCurrent();
-            if(holderCurrent != delegate) {
-                // FIXME: Allow update only if there is addition of models, not removals.
-                delegate = holderCurrent;
-            }
-
-        }
-
-        @Override
-        ModificationApplyOperation getDelegate() {
-            return delegate;
-        }
-
-        @Override
-        public RootModificationApplyOperation snapshot() {
-            return new Upgradable(holder,getDelegate());
-        }
-
+    @Override
+    final ChildTrackingPolicy getChildPolicy() {
+        return getDelegate().getChildPolicy();
     }
 
-    private static final class NotUpgradable extends RootModificationApplyOperation {
-
-        private final ModificationApplyOperation delegate;
-
-        public NotUpgradable(final ModificationApplyOperation delegate) {
-            this.delegate = delegate;
-        }
-
-        @Override
-        public ModificationApplyOperation getDelegate() {
-            return delegate;
-        }
-
-        @Override
-        public void upgradeIfPossible() {
-            // Intentional noop
-        }
-
-        @Override
-        public RootModificationApplyOperation snapshot() {
-            return this;
-        }
+    @Override
+    final void mergeIntoModifiedNode(final ModifiedNode node, final NormalizedNode<?, ?> value, final Version version) {
+        getDelegate().mergeIntoModifiedNode(node, value, version);
     }
 
-    public static class LatestOperationHolder {
-
-        private ModificationApplyOperation current = new AlwaysFailOperation();
-
-        public ModificationApplyOperation getCurrent() {
-            return current;
-        }
-
-        public void setCurrent(final ModificationApplyOperation newApplyOper) {
-            current = newApplyOper;
-        }
+    /**
+     * Return the underlying delegate.
+     *
+     * @return Underlying delegate.
+     */
+    abstract ModificationApplyOperation getDelegate();
 
-        public RootModificationApplyOperation newSnapshot() {
-            return new Upgradable(this,current);
+    /**
+     * Creates a snapshot from this modification, which may have separate
+     * upgrade lifecycle and is not affected by upgrades
+     * <p>
+     * Newly created snapshot uses backing implementation of this modi
+     *
+     * @return Derived {@link RootModificationApplyOperation} with separate
+     *         upgrade lifecycle.
+     */
+    abstract RootModificationApplyOperation snapshot();
+
+    /**
+     * Upgrades backing implementation to latest available, if possible.
+     * <p>
+     * Latest implementation of {@link RootModificationApplyOperation} is
+     * managed by {@link LatestOperationHolder} which was used to construct this
+     * operation and latest operation is updated by
+     * {@link LatestOperationHolder#setCurrent(ModificationApplyOperation)}.
+     */
+    abstract void upgradeIfPossible();
+
+    static RootModificationApplyOperation from(final ModificationApplyOperation resolver) {
+        if (resolver instanceof RootModificationApplyOperation) {
+            return ((RootModificationApplyOperation) resolver).snapshot();
         }
-
+        return new NotUpgradableModificationApplyOperation(resolver);
     }
 }