Merge "BUG 932 - Swagger HTTP POST contains incorrect object"
[controller.git] / opendaylight / md-sal / sal-inmemory-datastore / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / ResolveDataChangeEventsTask.java
index ff64cd64c412d57b12da080468f188d457948c6b..d8feaa71f6ac104132f14c0659677f566ee530c5 100644 (file)
@@ -9,21 +9,30 @@ 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.HashSet;
 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.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 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.util.concurrent.NotificationManager;
 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;
@@ -37,13 +46,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
 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;
-import com.google.common.collect.Multimap;
-
 /**
  * Resolve Data Change Events based on modifications and listeners
  *
@@ -58,9 +60,15 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     private final DataTreeCandidate candidate;
     private final ListenerTree listenerRoot;
 
-    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
+    @SuppressWarnings("rawtypes")
+    private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
+
+    @SuppressWarnings("rawtypes")
+    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree,
+            final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr) {
         this.candidate = Preconditions.checkNotNull(candidate);
         this.listenerRoot = Preconditions.checkNotNull(listenerTree);
+        this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
     }
 
     /**
@@ -121,7 +129,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @param listeners
      * @param entries
      */
-    private static void addNotificationTask(final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder,
+    private void addNotificationTask(final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder,
             final ListenerTree.Node listeners, final Collection<DOMImmutableDataChangeEvent> entries) {
 
         if (!entries.isEmpty()) {
@@ -142,7 +150,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @param listeners
      * @param event
      */
-    private static void addNotificationTaskByScope(
+    private void addNotificationTaskByScope(
             final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final ListenerTree.Node listeners,
             final DOMImmutableDataChangeEvent event) {
         DataChangeScope eventScope = event.getScope();
@@ -151,11 +159,11 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
             List<DataChangeListenerRegistration<?>> listenerSet = Collections
                     .<DataChangeListenerRegistration<?>> singletonList(listenerReg);
             if (eventScope == DataChangeScope.BASE) {
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event));
+                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
             } else if (eventScope == DataChangeScope.ONE && listenerScope != DataChangeScope.BASE) {
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event));
+                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
             } else if (eventScope == DataChangeScope.SUBTREE && listenerScope == DataChangeScope.SUBTREE) {
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event));
+                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
             }
         }
     }
@@ -173,7 +181,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @param listeners
      * @param entries
      */
-    private static void addNotificationTasksAndMergeEvents(
+    private void addNotificationTasksAndMergeEvents(
             final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final ListenerTree.Node listeners,
             final Collection<DOMImmutableDataChangeEvent> entries) {
 
@@ -211,14 +219,14 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         }
     }
 
-    private static void addNotificationTaskExclusively(
+    private void addNotificationTaskExclusively(
             final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final Node listeners,
             final DOMImmutableDataChangeEvent event) {
         for (DataChangeListenerRegistration<?> listener : listeners.getListeners()) {
             if (listener.getScope() == event.getScope()) {
                 Set<DataChangeListenerRegistration<?>> listenerSet = Collections
                         .<DataChangeListenerRegistration<?>> singleton(listener);
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event));
+                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
             }
         }
     }
@@ -278,6 +286,11 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
             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
@@ -306,14 +319,12 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
             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);
+            final PathArgument childId = beforeChild.getIdentifier();
+
             YangInstanceIdentifier childPath = path.node(childId);
             Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
             Optional<NormalizedNode<PathArgument, ?>> afterChild = afterCont.getChild(childId);
@@ -323,15 +334,17 @@ 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);
                 YangInstanceIdentifier childPath = path.node(childId);
                 childChanges.add(resolveSameEventRecursivelly(childPath , childListeners, afterChild,
@@ -342,7 +355,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);
@@ -515,7 +528,10 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         }
     }
 
-    public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
-        return new ResolveDataChangeEventsTask(candidate, listenerTree);
+    @SuppressWarnings("rawtypes")
+    public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate,
+            final ListenerTree listenerTree,
+            final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
+        return new ResolveDataChangeEventsTask(candidate, listenerTree, notificationMgr);
     }
 }