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 9e11fc70fc066164585709200dee863c95d1600f..00df6580effda8da33e80a648653935049010c47 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 db9bb0fef29fda971f08982d5d0f0e67353ec630..b36ef3dd7c16250bfcc101ab4567be3feaaadbc4 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 79ce37e15621870fc4818cf6755875257dc978fa..906e2844291fc502bae2a2534fe71bf1cb1d02a6 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();
+}
@@ -5,7 +5,7 @@
  * 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.data;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
 public enum ModificationType {
 
index b2faf7956555f5fe2580b7d57294c829c8f914f4..cddda5ccc5fc3cbc2b488d871398d61e9209703a 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 5a300a071d927e442e706c337cb8eb0dc6540d39..f04e379dd95824dd965c0ac8c5c998d9f0dafd83 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 93719b7f531c76c948594d49003fddc3d8aa3ff3..72562f0a72bd218518a6a2cc0441c1f66af9e4be 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 18179afd50af0ca4d92dd45fa7bf32c0ce601d67..f2720b57aebe7267a7ed377a89dc4cf12322aa45 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 1782da2835df6be2f13c0c5d9b76dfc4ea357aa2..8a467484141bf9631cd05b26ae09b85f1943d6fd 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 02244d9f98fa47ba261d6da7f4965a52009c5f4c..ca5371297dc43a2baa3e877f73028efc245ec555 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 8addb89bd1ae2180959ba458b2d0762f998d7f21..0ee0d9b32c990685c8169eb0430d35d64dacc2e0 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);
     }