*/
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;
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
*
* - 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 &&
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
}
}
- 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,
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()));
}
return NO_CHANGE;
}
- Builder eventBuilder = builder(potentialScope) //
+ Builder eventBuilder = builder(DataChangeScope.BASE) //
.setBefore(beforeCont) //
.setAfter(afterCont)
.addUpdated(path, beforeCont, afterCont);
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) {
* @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" })
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);
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);
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));
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;