+/*
+ * 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;
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.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.data.NodeModification;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode;
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.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;
* </ul>
*
*/
-public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
+final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
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<StoreMetadataNode> beforeRoot;
- private Optional<StoreMetadataNode> afterRoot;
private final Multimap<ListenerTree.Node, DOMImmutableDataChangeEvent> 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<StoreMetadataNode> getBeforeRoot() {
- return beforeRoot;
- }
-
- protected ResolveDataChangeEventsTask setBeforeRoot(final Optional<StoreMetadataNode> beforeRoot) {
- this.beforeRoot = beforeRoot;
- return this;
- }
-
- protected Optional<StoreMetadataNode> getAfterRoot() {
- return afterRoot;
- }
-
- protected ResolveDataChangeEventsTask setAfterRoot(final Optional<StoreMetadataNode> afterRoot) {
- this.afterRoot = afterRoot;
- return this;
- }
+ public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) {
+ this.candidate = Preconditions.checkNotNull(candidate);
+ this.listenerRoot = Preconditions.checkNotNull(listenerTree);
+ }
/**
* Resolves and creates Notification Tasks
*/
@Override
public Iterable<ChangeListenerNotifyTask> 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.getModificationRoot(), Optional.fromNullable(candidate.getBeforeRoot()),
+ Optional.fromNullable(candidate.getAfterRoot()));
return createNotificationTasks();
}
}
switch (modification.getModificationType()) {
case SUBTREE_MODIFIED:
return resolveSubtreeChangeEvent(path, listeners, modification, before.get(), after.get());
+ case MERGE:
case WRITE:
if (before.isPresent()) {
return resolveReplacedEvent(path, listeners, before.get().getData(), after.get().getData());
final Collection<Node> 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<PathArgument, ?>> beforeCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) beforeData;
@SuppressWarnings("unchecked")
// Node is either of Leaf type (does not contain child nodes)
// or we do not have listeners, so normal equals method is
// sufficient for determining change.
-
+ LOG.trace("Resolving leaf replace event for {} , before {}, after {}",path,beforeData,afterData);
DOMImmutableDataChangeEvent event = builder(DataChangeScope.BASE).setBefore(beforeData).setAfter(afterData)
.addUpdated(path, beforeData, afterData).build();
addPartialTask(listeners, event);
Builder eventBuilder = builder(potentialScope) //
.setBefore(beforeCont) //
- .setAfter(afterCont);
+ .setAfter(afterCont)
+ .addUpdated(path, beforeCont, afterCont);
for (DOMImmutableDataChangeEvent childChange : childChanges) {
eventBuilder.merge(childChange);
}
private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final InstanceIdentifier path,
final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
final SimpleEventFactory 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);
- DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
+ Builder eventBuilder = builder(DataChangeScope.BASE);
+ eventBuilder.merge(event);
+ eventBuilder.setBefore(event.getOriginalSubtree());
+ eventBuilder.setAfter(event.getUpdatedSubtree());
- 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<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
- for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
- PathArgument childId = child.getIdentifier();
- Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- if (!childListeners.isEmpty()) {
- resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory);
- }
- }
+ // Node has children, so we will try to resolve it's children
+ // changes.
+ @SuppressWarnings("unchecked")
+ NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
+ for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
+ PathArgument childId = child.getIdentifier();
+ LOG.trace("Resolving event for child {}", childId);
+ Collection<Node> 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,
Builder one = builder(DataChangeScope.ONE).setBefore(before.getData()).setAfter(after.getData());
- Builder subtree = builder(DataChangeScope.SUBTREE);
+ Builder subtree = builder(DataChangeScope.SUBTREE).setBefore(before.getData()).setAfter(after.getData());
for (NodeModification childMod : modification.getModifications()) {
PathArgument childId = childMod.getIdentifier();
switch (childMod.getModificationType()) {
case WRITE:
+ case MERGE:
case DELETE:
one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod, childBefore, childAfter));
break;
private DOMImmutableDataChangeEvent addPartialTask(final Collection<ListenerTree.Node> 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);
}
}
}
}
- public static ResolveDataChangeEventsTask create() {
- return new ResolveDataChangeEventsTask();
- }
+ public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
+ return new ResolveDataChangeEventsTask(candidate, listenerTree);
+ }
}