BUG-509: add some documentation
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / ResolveDataChangeEventsTask.java
index e74ba958915d2809b6cac4dc927ea329840652fa..b36ef3dd7c16250bfcc101ab4567be3feaaadbc4 100644 (file)
@@ -8,7 +8,7 @@
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
 import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
-import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.append;
+import static org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils.append;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -22,11 +22,12 @@ import java.util.concurrent.Callable;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 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.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.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;
@@ -38,6 +39,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -62,60 +64,17 @@ import com.google.common.collect.Multimap;
  * </ul>
  *
  */
-public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
+final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
     private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
     private static final DOMImmutableDataChangeEvent NO_CHANGE = builder(DataChangeScope.BASE).build();
 
-    private InstanceIdentifier rootPath;
-    private ListenerTree listenerRoot;
-    private NodeModification modificationRoot;
-    private Optional<StoreMetadataNode> beforeRoot;
-    private Optional<StoreMetadataNode> afterRoot;
     private final Multimap<ListenerTree.Node, DOMImmutableDataChangeEvent> events = HashMultimap.create();
+    private final DataTreeCandidate candidate;
+    private final ListenerTree listenerRoot;
 
-    protected InstanceIdentifier getRootPath() {
-        return rootPath;
-    }
-
-    protected ResolveDataChangeEventsTask setRootPath(final InstanceIdentifier rootPath) {
-        this.rootPath = rootPath;
-        return this;
-    }
-
-    protected ListenerTree getListenerRoot() {
-        return listenerRoot;
-    }
-
-    protected ResolveDataChangeEventsTask setListenerRoot(final ListenerTree listenerRoot) {
-        this.listenerRoot = listenerRoot;
-        return this;
-    }
-
-    protected NodeModification getModificationRoot() {
-        return modificationRoot;
-    }
-
-    protected ResolveDataChangeEventsTask setModificationRoot(final NodeModification modificationRoot) {
-        this.modificationRoot = modificationRoot;
-        return this;
-    }
-
-    protected Optional<StoreMetadataNode> getBeforeRoot() {
-        return beforeRoot;
-    }
-
-    protected ResolveDataChangeEventsTask setBeforeRoot(final Optional<StoreMetadataNode> beforeRoot) {
-        this.beforeRoot = beforeRoot;
-        return this;
-    }
-
-    protected Optional<StoreMetadataNode> getAfterRoot() {
-        return afterRoot;
-    }
-
-    protected ResolveDataChangeEventsTask setAfterRoot(final Optional<StoreMetadataNode> afterRoot) {
-        this.afterRoot = afterRoot;
-        return this;
+    public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) {
+        this.candidate = Preconditions.checkNotNull(candidate);
+        this.listenerRoot = Preconditions.checkNotNull(listenerTree);
     }
 
     /**
@@ -129,11 +88,8 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
      */
     @Override
     public Iterable<ChangeListenerNotifyTask> call() {
-        LOG.trace("Resolving events for {}", modificationRoot);
-
         try (final Walker w = listenerRoot.getWalker()) {
-            resolveAnyChangeEvent(rootPath, Collections.singleton(w.getRootNode()), modificationRoot, beforeRoot,
-                    afterRoot);
+            resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()), candidate.getRootNode());
             return createNotificationTasks();
         }
     }
@@ -298,41 +254,50 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
      * @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,
             final Collection<Node> listeners, final NormalizedNode<?, ?> beforeData,
             final NormalizedNode<?, ?> afterData) {
 
-        if (beforeData instanceof NormalizedNodeContainer<?, ?, ?> && !listeners.isEmpty()) {
+        if (beforeData instanceof NormalizedNodeContainer<?, ?, ?>) {
             // Node is container (contains child) and we have interested
             // listeners registered for it, that means we need to do
             // resolution of changes on children level and can not
             // shortcut resolution.
-
+            LOG.trace("Resolving subtree replace event for {} before {}, after {}",path,beforeData,afterData);
             @SuppressWarnings("unchecked")
             NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) beforeData;
             @SuppressWarnings("unchecked")
@@ -342,7 +307,7 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
             // Node is either of Leaf type (does not contain child nodes)
             // or we do not have listeners, so normal equals method is
             // sufficient for determining change.
-
+            LOG.trace("Resolving leaf replace event for {} , before {}, after {}",path,beforeData,afterData);
             DOMImmutableDataChangeEvent event = builder(DataChangeScope.BASE).setBefore(beforeData).setAfter(afterData)
                     .addUpdated(path, beforeData, afterData).build();
             addPartialTask(listeners, event);
@@ -355,7 +320,7 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
     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<>();
 
@@ -430,29 +395,30 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
      * @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());
     }
 
     private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final InstanceIdentifier path,
             final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
             final SimpleEventFactory eventFactory) {
-
         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
+        // We have listeners for this node or it's children, so we will try
+        // to do additional processing
         if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
+            LOG.trace("Resolving subtree recursive event for {}, type {}", path, eventFactory);
+
             Builder eventBuilder = builder(DataChangeScope.BASE);
             eventBuilder.merge(event);
             eventBuilder.setBefore(event.getOriginalSubtree());
@@ -464,6 +430,7 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
             NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
             for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
                 PathArgument childId = child.getIdentifier();
+                LOG.trace("Resolving event for child {}", childId);
                 Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
                 eventBuilder.merge(resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory));
             }
@@ -473,36 +440,37 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
             propagateEvent = builder(DataChangeScope.BASE).build();
         }
         if (!listeners.isEmpty()) {
-            addPartialTask(listeners, event);
+            addPartialTask(listeners, propagateEvent);
         }
         return propagateEvent;
     }
 
     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
@@ -521,9 +489,9 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
 
     private DOMImmutableDataChangeEvent addPartialTask(final Collection<ListenerTree.Node> listeners,
             final DOMImmutableDataChangeEvent event) {
-
         for (ListenerTree.Node listenerNode : listeners) {
             if (!listenerNode.getListeners().isEmpty()) {
+                LOG.trace("Adding event {} for listeners {}",event,listenerNode);
                 events.put(listenerNode, event);
             }
         }
@@ -554,7 +522,7 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
         }
     }
 
-    public static ResolveDataChangeEventsTask create() {
-        return new ResolveDataChangeEventsTask();
+    public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
+        return new ResolveDataChangeEventsTask(candidate, listenerTree);
     }
 }