BUG-509: Refactor listener walking 44/7244/3
authorRobert Varga <rovarga@cisco.com>
Tue, 20 May 2014 08:52:59 +0000 (10:52 +0200)
committerRobert Varga <rovarga@cisco.com>
Wed, 21 May 2014 09:42:51 +0000 (11:42 +0200)
This patch creates a proper abstraction for examining a
DataTreeCandidate for changes. This has the nice property of finishing
the hiding of all implementation details behind proper interfaces, such
that our implementation is free to do proper lifecycle as it pleases.

Also gets rid of the AutoCloseable from candidate. It can be
reintroduced in the need appears.

Change-Id: I13301548594d4ae34e929c7202661997ea5aca90
Signed-off-by: Robert Varga <rovarga@cisco.com>
12 files changed:
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidateNode.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationType.java [moved from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationType.java with 91% similarity]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AbstractDataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/SchemaAwareApplyOperation.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java

index 9e11fc7..00df658 100644 (file)
@@ -335,12 +335,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
 
         @Override
         public ListenableFuture<Void> abort() {
-            if (candidate != null) {
-                candidate.close();
-                candidate = null;
-            }
-
-            return Futures.<Void> immediateFuture(null);
+            candidate = null;
+            return Futures.immediateFuture(null);
         }
 
         @Override
@@ -360,7 +356,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                 }
             }
 
-            return Futures.<Void> immediateFuture(null);
+            return Futures.immediateFuture(null);
         }
     }
 }
index db9bb0f..b36ef3d 100644 (file)
@@ -23,11 +23,11 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataCh
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Node;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
@@ -73,9 +73,9 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     private final ListenerTree listenerRoot;
 
     public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) {
-       this.candidate = Preconditions.checkNotNull(candidate);
-       this.listenerRoot = Preconditions.checkNotNull(listenerTree);
-       }
+        this.candidate = Preconditions.checkNotNull(candidate);
+        this.listenerRoot = Preconditions.checkNotNull(listenerTree);
+    }
 
     /**
      * Resolves and creates Notification Tasks
@@ -89,9 +89,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     @Override
     public Iterable<ChangeListenerNotifyTask> call() {
         try (final Walker w = listenerRoot.getWalker()) {
-            resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()),
-                       candidate.getModificationRoot(), Optional.fromNullable(candidate.getBeforeRoot()),
-                       Optional.fromNullable(candidate.getAfterRoot()));
+            resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()), candidate.getRootNode());
             return createNotificationTasks();
         }
     }
@@ -256,29 +254,38 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @return Data Change Event of this node and all it's children
      */
     private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final NodeModification modification,
-            final Optional<StoreMetadataNode> before, final Optional<StoreMetadataNode> after) {
-        // No listeners are present in listener registration subtree
-        // no before and after state is present
-        if (!before.isPresent() && !after.isPresent()) {
+            final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode node) {
+
+        if (node.getModificationType() != ModificationType.UNMODIFIED &&
+                !node.getDataAfter().isPresent() && !node.getDataBefore().isPresent()) {
+            LOG.debug("Modification at {} has type {}, but no before- and after-data. Assuming unchanged.",
+                    path, node.getModificationType());
             return NO_CHANGE;
         }
-        switch (modification.getModificationType()) {
+
+        // no before and after state is present
+
+        switch (node.getModificationType()) {
         case SUBTREE_MODIFIED:
-            return resolveSubtreeChangeEvent(path, listeners, modification, before.get(), after.get());
+            return resolveSubtreeChangeEvent(path, listeners, node);
         case MERGE:
         case WRITE:
-            if (before.isPresent()) {
-                return resolveReplacedEvent(path, listeners, before.get().getData(), after.get().getData());
+            Preconditions.checkArgument(node.getDataAfter().isPresent(),
+                    "Modification at {} has type {} but no after-data", path, node.getModificationType());
+            if (node.getDataBefore().isPresent()) {
+                return resolveReplacedEvent(path, listeners, node.getDataBefore().get(), node.getDataAfter().get());
             } else {
-                return resolveCreateEvent(path, listeners, after.get());
+                return resolveCreateEvent(path, listeners, node.getDataAfter().get());
             }
         case DELETE:
-            return resolveDeleteEvent(path, listeners, before.get());
-        default:
+            Preconditions.checkArgument(node.getDataBefore().isPresent(),
+                    "Modification at {} has type {} but no before-data", path, node.getModificationType());
+            return resolveDeleteEvent(path, listeners, node.getDataBefore().get());
+        case UNMODIFIED:
             return NO_CHANGE;
         }
 
+        throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), path));
     }
 
     private DOMImmutableDataChangeEvent resolveReplacedEvent(final InstanceIdentifier path,
@@ -313,7 +320,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     private DOMImmutableDataChangeEvent resolveNodeContainerReplaced(final InstanceIdentifier path,
             final Collection<Node> listeners,
             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont,
-            final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
+                    final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
         final Set<PathArgument> alreadyProcessed = new HashSet<>();
         final List<DOMImmutableDataChangeEvent> childChanges = new LinkedList<>();
 
@@ -388,17 +395,17 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @return
      */
     private DOMImmutableDataChangeEvent resolveCreateEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final StoreMetadataNode afterState) {
+            final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> afterState) {
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState.getData();
+        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState;
         return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
     }
 
     private DOMImmutableDataChangeEvent resolveDeleteEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final StoreMetadataNode beforeState) {
+            final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> beforeState) {
 
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState.getData();
+        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState;
         return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
     }
 
@@ -408,7 +415,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
         DOMImmutableDataChangeEvent propagateEvent = event;
         // We have listeners for this node or it's children, so we will try
-            // to do additional processing
+        // to do additional processing
         if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
             LOG.trace("Resolving subtree recursive event for {}, type {}", path, eventFactory);
 
@@ -439,30 +446,31 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     }
 
     private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final NodeModification modification,
-            final StoreMetadataNode before, final StoreMetadataNode after) {
+            final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode modification) {
 
-        Builder one = builder(DataChangeScope.ONE).setBefore(before.getData()).setAfter(after.getData());
+        Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", path);
+        Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", path);
 
-        Builder subtree = builder(DataChangeScope.SUBTREE).setBefore(before.getData()).setAfter(after.getData());
+        Builder one = builder(DataChangeScope.ONE).
+                setBefore(modification.getDataBefore().get()).
+                setAfter(modification.getDataAfter().get());
+        Builder subtree = builder(DataChangeScope.SUBTREE).
+                setBefore(modification.getDataBefore().get()).
+                setAfter(modification.getDataAfter().get());
 
-        for (NodeModification childMod : modification.getModifications()) {
+        for (DataTreeCandidateNode childMod : modification.getChildNodes()) {
             PathArgument childId = childMod.getIdentifier();
             InstanceIdentifier childPath = append(path, childId);
             Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
 
-            Optional<StoreMetadataNode> childBefore = before.getChild(childId);
-            Optional<StoreMetadataNode> childAfter = after.getChild(childId);
-
             switch (childMod.getModificationType()) {
             case WRITE:
             case MERGE:
             case DELETE:
-                one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod, childBefore, childAfter));
+                one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod));
                 break;
             case SUBTREE_MODIFIED:
-                subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod, childBefore.get(),
-                        childAfter.get()));
+                subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod));
                 break;
             case UNMODIFIED:
                 // no-op
@@ -514,7 +522,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         }
     }
 
-       public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
+    public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
         return new ResolveDataChangeEventsTask(candidate, listenerTree);
-       }
+    }
 }
index 79ce37e..906e284 100644 (file)
@@ -7,22 +7,9 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
-public interface DataTreeCandidate extends AutoCloseable {
-       @Override
-       void close();
-
-       InstanceIdentifier getRootPath();
-
-       @Deprecated
-       NodeModification getModificationRoot();
-
-       @Deprecated
-       StoreMetadataNode getBeforeRoot();
-
-       @Deprecated
-       StoreMetadataNode getAfterRoot();
+public interface DataTreeCandidate {
+    DataTreeCandidateNode getRootNode();
+    InstanceIdentifier getRootPath();
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidateNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidateNode.java
new file mode 100644 (file)
index 0000000..b1ca45b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl.tree;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+public interface DataTreeCandidateNode {
+    PathArgument getIdentifier();
+    Iterable<DataTreeCandidateNode> getChildNodes();
+
+    ModificationType getModificationType();
+    Optional<NormalizedNode<?, ?>> getDataAfter();
+    Optional<NormalizedNode<?, ?>> getDataBefore();
+}
index b2faf79..cddda5c 100644 (file)
@@ -13,21 +13,15 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import com.google.common.base.Preconditions;
 
 abstract class AbstractDataTreeCandidate implements DataTreeCandidate {
-       private final InstanceIdentifier rootPath;
-       private final NodeModification modificationRoot;
+    private final InstanceIdentifier rootPath;
 
-       protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath, NodeModification modificationRoot) {
-               this.rootPath = Preconditions.checkNotNull(rootPath);
-               this.modificationRoot = Preconditions.checkNotNull(modificationRoot);
-       }
+    protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath) {
+        this.rootPath = Preconditions.checkNotNull(rootPath);
+    }
 
-       @Override
-       public final InstanceIdentifier getRootPath() {
-               return rootPath;
-       }
+    @Override
+    public final InstanceIdentifier getRootPath() {
+        return rootPath;
+    }
 
-       @Override
-       public final NodeModification getModificationRoot() {
-               return modificationRoot;
-       }
 }
index 5a300a0..f04e379 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFa
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -127,7 +128,7 @@ final class InMemoryDataTree implements DataTree {
         rwLock.writeLock().lock();
         try {
             Preconditions.checkState(c.getBeforeRoot() == rootNode,
-                    String.format("Store snapshot %s and transaction snapshot %s differ.", rootNode, c.getBeforeRoot()));
+                    String.format("Store tree %s and candidate base %s differ.", rootNode, c.getBeforeRoot()));
             this.rootNode = c.getAfterRoot();
         } finally {
             rwLock.writeLock().unlock();
index 93719b7..72562f0 100644 (file)
 package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
 
 final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate {
-       private final StoreMetadataNode newRoot;
-       private final StoreMetadataNode oldRoot;
-
-       InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot,
-                       final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) {
-               super(rootPath, modificationRoot);
-               this.newRoot = Preconditions.checkNotNull(newRoot);
-               this.oldRoot = Preconditions.checkNotNull(oldRoot);
-       }
-
-       @Override
-       public void close() {
-               // FIXME: abort operation here :)
-       }
-
-       @Override
-       public StoreMetadataNode getBeforeRoot() {
-               return oldRoot;
-       }
-
-       @Override
-       public StoreMetadataNode getAfterRoot() {
-               return newRoot;
-       }
+    private static abstract class AbstractNode implements DataTreeCandidateNode {
+        private final StoreMetadataNode newMeta;
+        private final StoreMetadataNode oldMeta;
+        private final NodeModification mod;
+
+        protected AbstractNode(final NodeModification mod,
+                final StoreMetadataNode oldMeta, final StoreMetadataNode newMeta) {
+            this.newMeta = newMeta;
+            this.oldMeta = oldMeta;
+            this.mod = Preconditions.checkNotNull(mod);
+        }
+
+        protected final NodeModification getMod() {
+            return mod;
+        }
+
+        protected final StoreMetadataNode getNewMeta() {
+            return newMeta;
+        }
+
+        protected final StoreMetadataNode getOldMeta() {
+            return oldMeta;
+        }
+
+        private static final StoreMetadataNode childMeta(final StoreMetadataNode parent, final PathArgument id) {
+            return parent == null ? null : parent.getChild(id).orNull();
+        }
+
+        @Override
+        public Iterable<DataTreeCandidateNode> getChildNodes() {
+            return Iterables.transform(mod.getModifications(), new Function<NodeModification, DataTreeCandidateNode>() {
+                @Override
+                public DataTreeCandidateNode apply(final NodeModification input) {
+                    final PathArgument id = input.getIdentifier();
+                    return new ChildNode(input, childMeta(oldMeta, id), childMeta(newMeta, id));
+                }
+            });
+        }
+
+        @Override
+        public ModificationType getModificationType() {
+            return mod.getModificationType();
+        }
+
+        private Optional<NormalizedNode<?, ?>> optionalData(StoreMetadataNode meta) {
+            if (meta == null) {
+                return Optional.absent();
+            }
+            return Optional.<NormalizedNode<?,?>>of(meta.getData());
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataAfter() {
+            return optionalData(newMeta);
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataBefore() {
+            return optionalData(oldMeta);
+        }
+    }
+
+    private static final class ChildNode extends AbstractNode {
+        public ChildNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+            super(mod, oldMeta, newMeta);
+        }
+
+        @Override
+        public PathArgument getIdentifier() {
+            return getMod().getIdentifier();
+        }
+    }
+
+    private static final class RootNode extends AbstractNode {
+        public RootNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+            super(mod, oldMeta, newMeta);
+        }
+
+        @Override
+        public PathArgument getIdentifier() {
+            throw new IllegalStateException("Attempted to get identifier of the root node");
+        }
+    }
+
+    private final RootNode root;
+
+    InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot,
+            final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) {
+        super(rootPath);
+        this.root = new RootNode(modificationRoot, oldRoot, newRoot);
+    }
+
+    StoreMetadataNode getAfterRoot() {
+        return root.getNewMeta();
+    }
+
+    StoreMetadataNode getBeforeRoot() {
+        return root.getOldMeta();
+    }
+
+    @Override
+    public DataTreeCandidateNode getRootNode() {
+        return root;
+    }
 }
index 18179af..f2720b5 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Map;
 
 import javax.annotation.concurrent.GuardedBy;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
@@ -30,10 +31,8 @@ import com.google.common.base.Predicate;
  *
  * This tree is lazily created and populated via {@link #modifyChild(PathArgument)}
  * and {@link StoreMetadataNode} which represents original state {@link #getOriginal()}.
- *
  */
-// FIXME: hide this class
-public class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
+final class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
 
     public static final Predicate<NodeModification> IS_TERMINAL_PREDICATE = new Predicate<NodeModification>() {
         @Override
index 1782da2..8a46748 100644 (file)
@@ -7,25 +7,52 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 
+import java.util.Collections;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
 final class NoopDataTreeCandidate extends AbstractDataTreeCandidate {
-       protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) {
-               super(rootPath, modificationRoot);
-       }
-
-       @Override
-       public void close() {
-               // NO-OP
-       }
-
-       @Override
-       public StoreMetadataNode getBeforeRoot() {
-               return null;
-       }
-
-       @Override
-       public StoreMetadataNode getAfterRoot() {
-               return null;
-       }
+    private static final DataTreeCandidateNode ROOT = new DataTreeCandidateNode() {
+        @Override
+        public ModificationType getModificationType() {
+            return ModificationType.UNMODIFIED;
+        }
+
+        @Override
+        public Iterable<DataTreeCandidateNode> getChildNodes() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public PathArgument getIdentifier() {
+            throw new IllegalStateException("Attempted to read identifier of the no-operation change");
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataAfter() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataBefore() {
+            return Optional.absent();
+        }
+    };
+
+    protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) {
+        super(rootPath);
+        Preconditions.checkArgument(modificationRoot.getModificationType() == ModificationType.UNMODIFIED);
+    }
+
+    @Override
+    public DataTreeCandidateNode getRootNode() {
+        return ROOT;
+    }
 }
index 02244d9..ca53712 100644 (file)
@@ -16,6 +16,7 @@ import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
index 8addb89..0ee0d9b 100644 (file)
@@ -24,15 +24,12 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.primitives.UnsignedLong;
 
-// FIXME: this should not be public
-public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>, StoreTreeNode<StoreMetadataNode> {
-
+class StoreMetadataNode implements Immutable, Identifiable<PathArgument>, StoreTreeNode<StoreMetadataNode> {
+    private final Map<PathArgument, StoreMetadataNode> children;
     private final UnsignedLong nodeVersion;
     private final UnsignedLong subtreeVersion;
     private final NormalizedNode<?, ?> data;
 
-    private final Map<PathArgument, StoreMetadataNode> children;
-
     /**
      *
      * @param data
@@ -42,9 +39,9 @@ public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>,
      */
     protected StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
             final UnsignedLong subtreeVersion, final Map<PathArgument, StoreMetadataNode> children) {
-        this.nodeVersion = nodeVersion;
-        this.subtreeVersion = subtreeVersion;
-        this.data = data;
+        this.nodeVersion = Preconditions.checkNotNull(nodeVersion);
+        this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
+        this.data = Preconditions.checkNotNull(data);
         this.children = Preconditions.checkNotNull(children);
     }