Publish SnapshotBacked transactions
[controller.git] / opendaylight / md-sal / sal-inmemory-datastore / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / ResolveDataChangeEventsTask.java
index 14d565c1d0b51253bad32a5182eb330ab860e94d..07a9fb7a88a7c5c37a3f748d84c7659e825dc9d5 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
@@ -14,10 +15,10 @@ import com.google.common.collect.Multimap;
 import java.util.Collection;
 import java.util.Map.Entry;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeSnapshot;
 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.ListenerWalker;
 import org.opendaylight.yangtools.util.concurrent.NotificationManager;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -34,7 +35,8 @@ import org.slf4j.LoggerFactory;
  * Computes data change events for all affected registered listeners in data
  * tree.
  */
-final class ResolveDataChangeEventsTask {
+@Beta
+public final class ResolveDataChangeEventsTask {
     private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
 
     private final DataTreeCandidate candidate;
@@ -42,7 +44,7 @@ final class ResolveDataChangeEventsTask {
 
     private Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> collectedEvents;
 
-    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
+    private ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
         this.candidate = Preconditions.checkNotNull(candidate);
         this.listenerRoot = Preconditions.checkNotNull(listenerTree);
     }
@@ -51,7 +53,7 @@ final class ResolveDataChangeEventsTask {
      * Resolves and submits notification tasks to the specified manager.
      */
     public synchronized void resolve(final NotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> manager) {
-        try (final ListenerWalker w = listenerRoot.getWalker()) {
+        try (final RegistrationTreeSnapshot<DataChangeListenerRegistration<?>> w = listenerRoot.takeSnapshot()) {
             // Defensive: reset internal state
             collectedEvents = ArrayListMultimap.create();
 
@@ -101,43 +103,46 @@ final class ResolveDataChangeEventsTask {
      * @return True if the subtree changed, false otherwise
      */
     private boolean resolveAnyChangeEvent(final ResolveDataChangeState state, final DataTreeCandidateNode node) {
-        if (node.getModificationType() != ModificationType.UNMODIFIED &&
-                !node.getDataAfter().isPresent() && !node.getDataBefore().isPresent()) {
+        final Optional<NormalizedNode<?, ?>> maybeBefore = node.getDataBefore();
+        final Optional<NormalizedNode<?, ?>> maybeAfter = node.getDataAfter();
+        final ModificationType type = node.getModificationType();
+
+        if (type != ModificationType.UNMODIFIED && !maybeAfter.isPresent() && !maybeBefore.isPresent()) {
             LOG.debug("Modification at {} has type {}, but no before- and after-data. Assuming unchanged.",
-                    state.getPath(), node.getModificationType());
+                    state.getPath(), type);
             return false;
         }
 
         // no before and after state is present
 
-        switch (node.getModificationType()) {
+        switch (type) {
         case SUBTREE_MODIFIED:
             return resolveSubtreeChangeEvent(state, node);
         case MERGE:
         case WRITE:
-            Preconditions.checkArgument(node.getDataAfter().isPresent(),
-                    "Modification at {} has type {} but no after-data", state.getPath(), node.getModificationType());
-            if (!node.getDataBefore().isPresent()) {
+            Preconditions.checkArgument(maybeAfter.isPresent(),
+                    "Modification at {} has type {} but no after-data", state.getPath(), type);
+            if (!maybeBefore.isPresent()) {
                 @SuppressWarnings({ "unchecked", "rawtypes" })
-                final NormalizedNode<PathArgument, ?> afterNode = (NormalizedNode)node.getDataAfter().get();
+                final NormalizedNode<PathArgument, ?> afterNode = (NormalizedNode)maybeAfter.get();
                 resolveSameEventRecursivelly(state, afterNode, DOMImmutableDataChangeEvent.getCreateEventFactory());
                 return true;
             }
 
-            return resolveReplacedEvent(state, node.getDataBefore().get(), node.getDataAfter().get());
+            return resolveReplacedEvent(state, maybeBefore.get(), maybeAfter.get());
         case DELETE:
-            Preconditions.checkArgument(node.getDataBefore().isPresent(),
-                    "Modification at {} has type {} but no before-data", state.getPath(), node.getModificationType());
+            Preconditions.checkArgument(maybeBefore.isPresent(),
+                    "Modification at {} has type {} but no before-data", state.getPath(), type);
 
             @SuppressWarnings({ "unchecked", "rawtypes" })
-            final NormalizedNode<PathArgument, ?> beforeNode = (NormalizedNode)node.getDataBefore().get();
+            final NormalizedNode<PathArgument, ?> beforeNode = (NormalizedNode)maybeBefore.get();
             resolveSameEventRecursivelly(state, beforeNode, DOMImmutableDataChangeEvent.getRemoveEventFactory());
             return true;
         case UNMODIFIED:
             return false;
         }
 
-        throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), state.getPath()));
+        throw new IllegalStateException(String.format("Unhandled node state %s at %s", type, state.getPath()));
     }
 
     private boolean resolveReplacedEvent(final ResolveDataChangeState state,
@@ -257,8 +262,11 @@ final class ResolveDataChangeEventsTask {
     }
 
     private boolean resolveSubtreeChangeEvent(final ResolveDataChangeState state, final DataTreeCandidateNode modification) {
-        Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", state.getPath());
-        Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", state.getPath());
+        final Optional<NormalizedNode<?, ?>> maybeBefore = modification.getDataBefore();
+        final Optional<NormalizedNode<?, ?>> maybeAfter = modification.getDataAfter();
+
+        Preconditions.checkArgument(maybeBefore.isPresent(), "Subtree change with before-data not present at path %s", state.getPath());
+        Preconditions.checkArgument(maybeAfter.isPresent(), "Subtree change with after-data not present at path %s", state.getPath());
 
         if (!state.needsProcessing()) {
             LOG.trace("Not processing modified subtree {}", state.getPath());
@@ -288,8 +296,8 @@ final class ResolveDataChangeEventsTask {
             }
         }
 
-        final NormalizedNode<?, ?> before = modification.getDataBefore().get();
-        final NormalizedNode<?, ?> after = modification.getDataAfter().get();
+        final NormalizedNode<?, ?> before = maybeBefore.get();
+        final NormalizedNode<?, ?> after = maybeAfter.get();
 
         if (scope != null) {
             DOMImmutableDataChangeEvent one = DOMImmutableDataChangeEvent.builder(scope).addUpdated(state.getPath(), before, after).build();