Merge "Fix config-manager activator"
[controller.git] / opendaylight / md-sal / sal-inmemory-datastore / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / ResolveDataChangeEventsTask.java
index 71a3534c811448d6f941f6166e145021db0653d7..3ddf0b60faf07323f7f26cb4d7488851015ef688 100644 (file)
@@ -7,23 +7,34 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
+
 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;
 import com.google.common.collect.Multimap;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+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.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.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+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.NormalizedNodeContainer;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
@@ -32,17 +43,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
-
 /**
  * Resolve Data Change Events based on modifications and listeners
  *
@@ -238,7 +238,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      *            - After state of current node
      * @return Data Change Event of this node and all it's children
      */
-    private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final YangInstanceIdentifier path,
             final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode node) {
 
         if (node.getModificationType() != ModificationType.UNMODIFIED &&
@@ -273,10 +273,15 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), path));
     }
 
-    private DOMImmutableDataChangeEvent resolveReplacedEvent(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveReplacedEvent(final YangInstanceIdentifier path,
             final Collection<Node> listeners, final NormalizedNode<?, ?> beforeData,
             final NormalizedNode<?, ?> afterData) {
 
+        // FIXME: BUG-1493: check the listeners to prune unneeded changes:
+        //                  for subtrees, we have to do all
+        //                  for one, we need to expand children
+        //                  for base, we just report replacement
+
         if (beforeData instanceof NormalizedNodeContainer<?, ?, ?>) {
             // Node is container (contains child) and we have interested
             // listeners registered for it, that means we need to do
@@ -301,19 +306,17 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         }
     }
 
-    private DOMImmutableDataChangeEvent resolveNodeContainerReplaced(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveNodeContainerReplaced(final YangInstanceIdentifier path,
             final Collection<Node> listeners,
             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont,
                     final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
-        final Set<PathArgument> alreadyProcessed = new HashSet<>();
         final List<DOMImmutableDataChangeEvent> childChanges = new LinkedList<>();
 
-        DataChangeScope potentialScope = DataChangeScope.BASE;
         // We look at all children from before and compare it with after state.
         for (NormalizedNode<PathArgument, ?> beforeChild : beforeCont.getValue()) {
-            PathArgument childId = beforeChild.getIdentifier();
-            alreadyProcessed.add(childId);
-            InstanceIdentifier childPath = path.node(childId);
+            final PathArgument childId = beforeChild.getIdentifier();
+
+            YangInstanceIdentifier childPath = path.node(childId);
             Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
             Optional<NormalizedNode<PathArgument, ?>> afterChild = afterCont.getChild(childId);
             DOMImmutableDataChangeEvent childChange = resolveNodeContainerChildUpdated(childPath, childListeners,
@@ -322,17 +325,19 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
             if (childChange != NO_CHANGE) {
                 childChanges.add(childChange);
             }
-
         }
 
         for (NormalizedNode<PathArgument, ?> afterChild : afterCont.getValue()) {
-            PathArgument childId = afterChild.getIdentifier();
-            if (!alreadyProcessed.contains(childId)) {
-                // We did not processed that child already
-                // and it was not present in previous loop, that means it is
-                // created.
+            final PathArgument childId = afterChild.getIdentifier();
+
+            /*
+             * We have already iterated of the before-children, so have already
+             * emitted modify/delete events. This means the child has been
+             * created.
+             */
+            if (!beforeCont.getChild(childId).isPresent()) {
                 Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
-                InstanceIdentifier childPath = path.node(childId);
+                YangInstanceIdentifier childPath = path.node(childId);
                 childChanges.add(resolveSameEventRecursivelly(childPath , childListeners, afterChild,
                         DOMImmutableDataChangeEvent.getCreateEventFactory()));
             }
@@ -341,7 +346,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
             return NO_CHANGE;
         }
 
-        Builder eventBuilder = builder(potentialScope) //
+        Builder eventBuilder = builder(DataChangeScope.BASE) //
                 .setBefore(beforeCont) //
                 .setAfter(afterCont)
                 .addUpdated(path, beforeCont, afterCont);
@@ -354,7 +359,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         return replaceEvent;
     }
 
-    private DOMImmutableDataChangeEvent resolveNodeContainerChildUpdated(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveNodeContainerChildUpdated(final YangInstanceIdentifier path,
             final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> before,
             final Optional<NormalizedNode<PathArgument, ?>> after) {
 
@@ -378,14 +383,14 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @param afterState
      * @return
      */
-    private DOMImmutableDataChangeEvent resolveCreateEvent(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveCreateEvent(final YangInstanceIdentifier path,
             final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> afterState) {
         @SuppressWarnings({ "unchecked", "rawtypes" })
         final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState;
         return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
     }
 
-    private DOMImmutableDataChangeEvent resolveDeleteEvent(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveDeleteEvent(final YangInstanceIdentifier path,
             final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> beforeState) {
 
         @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -393,7 +398,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
     }
 
-    private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final YangInstanceIdentifier path,
             final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
             final SimpleEventFactory eventFactory) {
         final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
@@ -426,7 +431,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         return propagateEvent;
     }
 
-    private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
+    private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final YangInstanceIdentifier path,
             final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode modification) {
 
         Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", path);
@@ -438,17 +443,19 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         Builder subtree = builder(DataChangeScope.SUBTREE).
                 setBefore(modification.getDataBefore().get()).
                 setAfter(modification.getDataAfter().get());
-
+        boolean oneModified = false;
         for (DataTreeCandidateNode childMod : modification.getChildNodes()) {
             PathArgument childId = childMod.getIdentifier();
-            InstanceIdentifier childPath = path.node(childId);
+            YangInstanceIdentifier childPath = path.node(childId);
             Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
 
+
             switch (childMod.getModificationType()) {
             case WRITE:
             case MERGE:
             case DELETE:
                 one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod));
+                oneModified = true;
                 break;
             case SUBTREE_MODIFIED:
                 subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod));
@@ -458,11 +465,20 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
                 break;
             }
         }
-        DOMImmutableDataChangeEvent oneChangeEvent = one.build();
-        subtree.merge(oneChangeEvent);
+        final DOMImmutableDataChangeEvent oneChangeEvent;
+        if(oneModified) {
+            one.addUpdated(path, modification.getDataBefore().get(), modification.getDataAfter().get());
+            oneChangeEvent = one.build();
+            subtree.merge(oneChangeEvent);
+        } else {
+            oneChangeEvent = null;
+            subtree.addUpdated(path, modification.getDataBefore().get(), modification.getDataAfter().get());
+        }
         DOMImmutableDataChangeEvent subtreeEvent = subtree.build();
         if (!listeners.isEmpty()) {
-            addPartialTask(listeners, oneChangeEvent);
+            if(oneChangeEvent != null) {
+                addPartialTask(listeners, oneChangeEvent);
+            }
             addPartialTask(listeners, subtreeEvent);
         }
         return subtreeEvent;