X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FResolveDataChangeEventsTask.java;h=2a163d8dbc7334c95a24481d1a1835ffa8496586;hb=da4cff5c3a5bc732fb046b563b886a7aaab67c30;hp=520bd1ba1de3d9407718db6a6df64ce128fd1509;hpb=7f0272398ce3dab7ceddd998c7bb510df3b28838;p=controller.git
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
index 520bd1ba1d..2a163d8dbc 100644
--- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
+++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
@@ -8,7 +8,6 @@
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 java.util.Collection;
import java.util.Collections;
@@ -22,11 +21,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,84 +38,29 @@ 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
*
* Computes data change events for all affected registered listeners in data
* tree.
- *
- * Prerequisites for computation is to set all parameters properly:
- *
- * - {@link #setRootPath(InstanceIdentifier)} - Root path of datastore
- *
- {@link #setListenerRoot(ListenerTree)} - Root of listener registration
- * tree, which contains listeners to be notified
- *
- {@link #setModificationRoot(NodeModification)} - Modification root, for
- * which events should be computed
- *
- {@link #setBeforeRoot(Optional)} - State of before modification occurred
- *
- {@link #setAfterRoot(Optional)} - State of after modification occurred
- *
- *
*/
-public class ResolveDataChangeEventsTask implements Callable> {
+final class ResolveDataChangeEventsTask implements Callable> {
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 beforeRoot;
- private Optional afterRoot;
private final Multimap 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 getBeforeRoot() {
- return beforeRoot;
- }
-
- protected ResolveDataChangeEventsTask setBeforeRoot(final Optional beforeRoot) {
- this.beforeRoot = beforeRoot;
- return this;
- }
-
- protected Optional getAfterRoot() {
- return afterRoot;
- }
-
- protected ResolveDataChangeEventsTask setAfterRoot(final Optional afterRoot) {
- this.afterRoot = afterRoot;
- return this;
+ public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
+ this.candidate = Preconditions.checkNotNull(candidate);
+ this.listenerRoot = Preconditions.checkNotNull(listenerTree);
}
/**
@@ -124,16 +69,13 @@ public class ResolveDataChangeEventsTask implements Callable 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,40 +240,50 @@ public class ResolveDataChangeEventsTask implements Callable listeners, final NodeModification modification,
- final Optional before, final Optional after) {
- // No listeners are present in listener registration subtree
- // no before and after state is present
- if (!before.isPresent() && !after.isPresent()) {
+ final Collection 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 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> beforeCont = (NormalizedNodeContainer, PathArgument, NormalizedNode>) beforeData;
@SuppressWarnings("unchecked")
@@ -341,7 +293,7 @@ public class ResolveDataChangeEventsTask implements Callable listeners,
final NormalizedNodeContainer, PathArgument, NormalizedNode> beforeCont,
- final NormalizedNodeContainer, PathArgument, NormalizedNode> afterCont) {
+ final NormalizedNodeContainer, PathArgument, NormalizedNode> afterCont) {
final Set alreadyProcessed = new HashSet<>();
final List childChanges = new LinkedList<>();
@@ -363,7 +315,7 @@ public class ResolveDataChangeEventsTask implements Callable beforeChild : beforeCont.getValue()) {
PathArgument childId = beforeChild.getIdentifier();
alreadyProcessed.add(childId);
- InstanceIdentifier childPath = append(path, childId);
+ InstanceIdentifier childPath = path.node(childId);
Collection childListeners = getListenerChildrenWildcarded(listeners, childId);
Optional> afterChild = afterCont.getChild(childId);
DOMImmutableDataChangeEvent childChange = resolveNodeContainerChildUpdated(childPath, childListeners,
@@ -382,7 +334,7 @@ public class ResolveDataChangeEventsTask implements Callable childListeners = getListenerChildrenWildcarded(listeners, childId);
- InstanceIdentifier childPath = append(path,childId);
+ InstanceIdentifier childPath = path.node(childId);
childChanges.add(resolveSameEventRecursivelly(childPath , childListeners, afterChild,
DOMImmutableDataChangeEvent.getCreateEventFactory()));
}
@@ -393,7 +345,8 @@ public class ResolveDataChangeEventsTask implements Callable listeners, final StoreMetadataNode afterState) {
+ final Collection listeners, final NormalizedNode, ?> afterState) {
@SuppressWarnings({ "unchecked", "rawtypes" })
- final NormalizedNode node = (NormalizedNode) afterState.getData();
+ final NormalizedNode node = (NormalizedNode) afterState;
return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
}
private DOMImmutableDataChangeEvent resolveDeleteEvent(final InstanceIdentifier path,
- final Collection listeners, final StoreMetadataNode beforeState) {
+ final Collection listeners, final NormalizedNode, ?> beforeState) {
@SuppressWarnings({ "unchecked", "rawtypes" })
- final NormalizedNode node = (NormalizedNode) beforeState.getData();
+ final NormalizedNode node = (NormalizedNode) beforeState;
return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
}
private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final InstanceIdentifier path,
final Collection listeners, final NormalizedNode node,
final SimpleEventFactory eventFactory) {
-
- DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
-
- if (!listeners.isEmpty()) {
- // We have listeners for this node or it's children, so we will try
- // to do additional processing
- if (node instanceof NormalizedNodeContainer, ?, ?>) {
- // Node has children, so we will try to resolve it's children
- // changes.
- @SuppressWarnings("unchecked")
- NormalizedNodeContainer, PathArgument, NormalizedNode> container = (NormalizedNodeContainer, PathArgument, NormalizedNode>) node;
- for (NormalizedNode child : container.getValue()) {
- PathArgument childId = child.getIdentifier();
- Collection childListeners = getListenerChildrenWildcarded(listeners, childId);
- if (!childListeners.isEmpty()) {
- resolveSameEventRecursivelly(append(path, childId), childListeners, child, 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
+ 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());
+ eventBuilder.setAfter(event.getUpdatedSubtree());
+
+ // Node has children, so we will try to resolve it's children
+ // changes.
+ @SuppressWarnings("unchecked")
+ NormalizedNodeContainer, PathArgument, NormalizedNode> container = (NormalizedNodeContainer, PathArgument, NormalizedNode>) node;
+ for (NormalizedNode child : container.getValue()) {
+ PathArgument childId = child.getIdentifier();
+ LOG.trace("Resolving event for child {}", childId);
+ Collection childListeners = getListenerChildrenWildcarded(listeners, childId);
+ eventBuilder.merge(resolveSameEventRecursivelly(path.node(childId), childListeners, child, eventFactory));
}
- addPartialTask(listeners, event);
+ propagateEvent = eventBuilder.build();
+ } else {
+ // We do not dispatch leaf events since Binding Aware components do not support them.
+ propagateEvent = builder(DataChangeScope.BASE).build();
}
- return event;
+ if (!listeners.isEmpty()) {
+ addPartialTask(listeners, propagateEvent);
+ }
+ return propagateEvent;
}
private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
- final Collection listeners, final NodeModification modification,
- final StoreMetadataNode before, final StoreMetadataNode after) {
+ final Collection 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);
+ 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);
+ InstanceIdentifier childPath = path.node(childId);
Collection childListeners = getListenerChildrenWildcarded(listeners, childId);
- Optional childBefore = before.getChild(childId);
- Optional 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
@@ -511,9 +475,9 @@ public class ResolveDataChangeEventsTask implements Callable 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);
}
}
@@ -544,7 +508,7 @@ public class ResolveDataChangeEventsTask implements Callable