Merge "Fix checkstyle if-statements must use braces in binding-generator"
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / ModifiedNode.java
index a8739a6201dcd9bb280fb0de8b06eaaf7ca7b49c..90e83ca401c213e269f8b61c0ba309c67b5775b8 100644 (file)
@@ -8,9 +8,12 @@
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
+import java.util.HashMap;
+import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+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.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNode;
@@ -33,7 +36,8 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
 
     public static final Predicate<ModifiedNode> IS_TERMINAL_PREDICATE = new Predicate<ModifiedNode>() {
         @Override
-        public boolean apply(final ModifiedNode input) {
+        public boolean apply(final @Nonnull ModifiedNode input) {
+            Preconditions.checkNotNull(input);
             switch (input.getType()) {
             case DELETE:
             case MERGE:
@@ -48,16 +52,22 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
         }
     };
 
-    private final Map<PathArgument, ModifiedNode> children = new LinkedHashMap<>();
+    private final Map<PathArgument, ModifiedNode> children;
     private final Optional<TreeNode> original;
     private final PathArgument identifier;
     private ModificationType modificationType = ModificationType.UNMODIFIED;
     private Optional<TreeNode> snapshotCache;
     private NormalizedNode<?, ?> value;
 
-    private ModifiedNode(final PathArgument identifier, final Optional<TreeNode> original) {
+    private ModifiedNode(final PathArgument identifier, final Optional<TreeNode> original, boolean isOrdered) {
         this.identifier = identifier;
         this.original = original;
+
+        if (isOrdered) {
+            children = new LinkedHashMap<>();
+        } else {
+            children = new HashMap<>();
+        }
     }
 
     /**
@@ -119,7 +129,7 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
      * @return {@link org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ModifiedNode} for specified child, with {@link #getOriginal()}
      *         containing child metadata if child was present in original data.
      */
-    public ModifiedNode modifyChild(final PathArgument child) {
+    public ModifiedNode modifyChild(final PathArgument child, boolean isOrdered) {
         clearSnapshot();
         if (modificationType == ModificationType.UNMODIFIED) {
             updateModificationType(ModificationType.SUBTREE_MODIFIED);
@@ -137,7 +147,7 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
             currentMetadata = Optional.absent();
         }
 
-        ModifiedNode newlyCreated = new ModifiedNode(child, currentMetadata);
+        ModifiedNode newlyCreated = new ModifiedNode(child, currentMetadata, isOrdered);
         children.put(child, newlyCreated);
         return newlyCreated;
     }
@@ -159,10 +169,35 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
      *
      */
     public void delete() {
+        final ModificationType newType;
+
+        switch (modificationType) {
+        case DELETE:
+        case UNMODIFIED:
+            // We need to record this delete.
+            newType = ModificationType.DELETE;
+            break;
+        case MERGE:
+        case SUBTREE_MODIFIED:
+        case WRITE:
+            /*
+             * We are canceling a previous modification. This is a bit tricky,
+             * as the original write may have just introduced the data, or it
+             * may have modified it.
+             *
+             * As documented in BUG-2470, a delete of data introduced in this
+             * transaction needs to be turned into a no-op.
+             */
+            newType = original.isPresent() ? ModificationType.DELETE : ModificationType.UNMODIFIED;
+            break;
+        default:
+            throw new IllegalStateException("Unhandled deletion of node with " + modificationType);
+        }
+
         clearSnapshot();
-        updateModificationType(ModificationType.DELETE);
         children.clear();
         this.value = null;
+        updateModificationType(newType);
     }
 
     /**
@@ -217,7 +252,7 @@ final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<Pa
                 + modificationType + ", childModification=" + children + "]";
     }
 
-    public static ModifiedNode createUnmodified(final TreeNode metadataTree) {
-        return new ModifiedNode(metadataTree.getIdentifier(), Optional.of(metadataTree));
+    public static ModifiedNode createUnmodified(final TreeNode metadataTree, boolean isOrdered) {
+        return new ModifiedNode(metadataTree.getIdentifier(), Optional.of(metadataTree), isOrdered);
     }
 }