X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FResolveDataChangeEventsTask.java;h=b36ef3dd7c16250bfcc101ab4567be3feaaadbc4;hp=befeaf4e1e808c672c1417d3a467fb373727c324;hb=617941ac35b64881556f7311a8a296f4b60b2935;hpb=72a2f458d328d443e2a5479ac147c1242a41a70f 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 befeaf4e1e..b36ef3dd7c 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 @@ -1,7 +1,14 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ 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; @@ -15,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; @@ -31,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; @@ -55,60 +64,17 @@ import com.google.common.collect.Multimap; * * */ -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(DataTreeCandidate candidate, ListenerTree listenerTree) { + this.candidate = Preconditions.checkNotNull(candidate); + this.listenerRoot = Preconditions.checkNotNull(listenerTree); } /** @@ -122,11 +88,8 @@ 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(); } } @@ -291,40 +254,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> beforeCont = (NormalizedNodeContainer>) beforeData; @SuppressWarnings("unchecked") @@ -334,7 +307,7 @@ public class ResolveDataChangeEventsTask implements Callable listeners, final NormalizedNodeContainer> beforeCont, - final NormalizedNodeContainer> afterCont) { + final NormalizedNodeContainer> afterCont) { final Set alreadyProcessed = new HashSet<>(); final List childChanges = new LinkedList<>(); @@ -386,7 +359,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> container = (NormalizedNodeContainer>) 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> container = (NormalizedNodeContainer>) 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(append(path, 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); 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 @@ -504,9 +489,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); } } @@ -537,7 +522,7 @@ public class ResolveDataChangeEventsTask implements Callable