Deprecate Clustered(DOM)DataTreeChangeListener
[mdsal.git] / dom / mdsal-dom-spi / src / main / java / org / opendaylight / mdsal / dom / spi / store / AbstractDOMStoreTreeChangePublisher.java
index 8bc0499f6bd1a7aca8bf1fd094baec752f06e4b5..0b38025b2a030d056bae3dba3037eb66b6811d3f 100644 (file)
@@ -7,26 +7,22 @@
  */
 package org.opendaylight.mdsal.dom.spi.store;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
-import org.opendaylight.mdsal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
 import org.opendaylight.mdsal.dom.spi.AbstractRegistrationTree;
-import org.opendaylight.mdsal.dom.spi.RegistrationTreeNode;
-import org.opendaylight.mdsal.dom.spi.RegistrationTreeSnapshot;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.tree.api.ModificationType;
+import org.opendaylight.yangtools.yang.data.tree.spi.DataTreeCandidates;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,32 +30,73 @@ import org.slf4j.LoggerFactory;
  * Abstract base class for {@link DOMStoreTreeChangePublisher} implementations.
  */
 public abstract class AbstractDOMStoreTreeChangePublisher
-    extends AbstractRegistrationTree<AbstractDOMDataTreeChangeListenerRegistration<?>>
+        extends AbstractRegistrationTree<AbstractDOMStoreTreeChangePublisher.RegImpl>
         implements DOMStoreTreeChangePublisher {
+    /**
+     * A handle to a registered {@link DOMDataTreeChangeListener}. Implementations of this interface are guaranteed to
+     * use identity-based equality.
+     */
+    @NonNullByDefault
+    protected sealed interface Reg permits RegImpl {
+        /**
+         * Return the underlying listener.
+         *
+         * @return the underlying listener
+         */
+        DOMDataTreeChangeListener listener();
+
+        /**
+         * Check if this handle has not been closed yet.
+         *
+         * @return {@code true} if this handle is still open
+         */
+        boolean notClosed();
+    }
+
+    /**
+     * Registration handle for a {@link DOMDataTreeChangeListener}. This class is exposed to subclasses only as a
+     * convenience, so they can use its identity-based equality while at the same time having access to the listener.
+     *
+     * <p>
+     * Implementations must not invoke {@link #close()} nor should otherwise interact with the registration.
+     */
+    @NonNullByDefault
+    final class RegImpl extends AbstractObjectRegistration<DOMDataTreeChangeListener> implements Reg {
+        private RegImpl(final DOMDataTreeChangeListener instance) {
+            super(instance);
+        }
+
+        @Override
+        public DOMDataTreeChangeListener listener() {
+            return getInstance();
+        }
+
+        @Override
+        protected void removeRegistration() {
+            registrationRemoved(this);
+        }
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(AbstractDOMStoreTreeChangePublisher.class);
 
     /**
      * Callback for subclass to notify a specified registration of a list of candidates. This method is guaranteed
      * to be only called from within {@link #processCandidateTree(DataTreeCandidate)}.
+     *
      * @param registration the registration to notify
      * @param changes the list of DataTreeCandidate changes
      */
-    protected abstract void notifyListener(@NonNull AbstractDOMDataTreeChangeListenerRegistration<?> registration,
-            @NonNull Collection<DataTreeCandidate> changes);
+    protected abstract void notifyListener(@NonNull Reg registration, @NonNull List<DataTreeCandidate> changes);
 
     /**
-     * Callback notifying the subclass that the specified registration is being
-     * closed and it's user no longer
-     * wishes to receive notifications. This notification is invoked while
-     * the {@link org.opendaylight.yangtools.concepts.ListenerRegistration#close()}
-     * method is executing. Subclasses can use this callback to properly
-     * remove any delayed notifications pending
-     * towards the registration.
+     * Callback notifying the subclass that the specified registration is being closed and it's user no longer wishes to
+     * receive notifications. This notification is invoked while the
+     * {@link org.opendaylight.yangtools.concepts.Registration#close()} method is executing. Subclasses can use this
+     * callback to properly remove any delayed notifications pending towards the registration.
      *
      * @param registration Registration which is being closed
      */
-    protected abstract void registrationRemoved(
-            @NonNull AbstractDOMDataTreeChangeListenerRegistration<?> registration);
+    protected abstract void registrationRemoved(@NonNull Reg registration);
 
     /**
      * Process a candidate tree with respect to registered listeners.
@@ -68,21 +105,18 @@ public abstract class AbstractDOMStoreTreeChangePublisher
      * @return true if at least one listener was notified or false.
      */
     protected final boolean processCandidateTree(final @NonNull DataTreeCandidate candidate) {
-        final DataTreeCandidateNode node = candidate.getRootNode();
-        if (node.getModificationType() == ModificationType.UNMODIFIED) {
+        final var node = candidate.getRootNode();
+        if (node.modificationType() == ModificationType.UNMODIFIED) {
             LOG.debug("Skipping unmodified candidate {}", candidate);
             return false;
         }
 
-        try (RegistrationTreeSnapshot<AbstractDOMDataTreeChangeListenerRegistration<?>> snapshot
-                = takeSnapshot()) {
-            final List<PathArgument> toLookup = ImmutableList.copyOf(candidate.getRootPath().getPathArguments());
-            final Multimap<AbstractDOMDataTreeChangeListenerRegistration<?>, DataTreeCandidate> listenerChanges =
-                    Multimaps.newListMultimap(new IdentityHashMap<>(), ArrayList::new);
+        try (var snapshot = takeSnapshot()) {
+            final var toLookup = List.copyOf(candidate.getRootPath().getPathArguments());
+            final var listenerChanges = new IdentityHashMap<Reg, List<DataTreeCandidate>>();
             lookupAndNotify(toLookup, 0, snapshot.getRootNode(), candidate, listenerChanges);
 
-            for (Map.Entry<AbstractDOMDataTreeChangeListenerRegistration<?>, Collection<DataTreeCandidate>> entry:
-                    listenerChanges.asMap().entrySet()) {
+            for (var entry : listenerChanges.entrySet()) {
                 notifyListener(entry.getKey(), entry.getValue());
             }
 
@@ -91,23 +125,13 @@ public abstract class AbstractDOMStoreTreeChangePublisher
     }
 
     @Override
-    public <L extends DOMDataTreeChangeListener> AbstractDOMDataTreeChangeListenerRegistration<L>
-        registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
+    public final Registration registerTreeChangeListener(final YangInstanceIdentifier treeId,
+            final DOMDataTreeChangeListener listener) {
         // Take the write lock
         takeLock();
         try {
-            final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node =
-                    findNodeFor(treeId.getPathArguments());
-            final AbstractDOMDataTreeChangeListenerRegistration<L> reg =
-                    new AbstractDOMDataTreeChangeListenerRegistration<L>(listener) {
-                @Override
-                protected void removeRegistration() {
-                    AbstractDOMStoreTreeChangePublisher.this.removeRegistration(node, this);
-                    registrationRemoved(this);
-                }
-            };
-
-            addRegistration(node, reg);
+            final var reg = new RegImpl(listener);
+            addRegistration(findNodeFor(treeId.getPathArguments()), reg);
             return reg;
         } finally {
             // Always release the lock
@@ -115,66 +139,63 @@ public abstract class AbstractDOMStoreTreeChangePublisher
         }
     }
 
-    private void lookupAndNotify(final List<PathArgument> args,
-            final int offset, final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node,
-            final DataTreeCandidate candidate,
-            final Multimap<AbstractDOMDataTreeChangeListenerRegistration<?>, DataTreeCandidate> listenerChanges) {
-        if (args.size() != offset) {
-            final PathArgument arg = args.get(offset);
-
-            final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> exactChild
-                = node.getExactChild(arg);
-            if (exactChild != null) {
-                lookupAndNotify(args, offset + 1, exactChild, candidate, listenerChanges);
-            }
+    /**
+     * {@inheritDoc}
+     *
+     * <p>
+     * This implementation calls {@link #registerTreeChangeListener(YangInstanceIdentifier, DOMDataTreeChangeListener)},
+     * override if necessary.
+     */
+    @Override
+    @Deprecated(since = "13.0.0", forRemoval = true)
+    public Registration registerLegacyTreeChangeListener(final YangInstanceIdentifier treeId,
+            final DOMDataTreeChangeListener listener) {
+        return registerTreeChangeListener(treeId, listener);
+    }
 
-            for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> c :
-                    node.getInexactChildren(arg)) {
-                lookupAndNotify(args, offset + 1, c, candidate, listenerChanges);
-            }
-        } else {
+    private void lookupAndNotify(final List<PathArgument> args, final int offset, final Node<RegImpl> node,
+            final DataTreeCandidate candidate, final Map<Reg, List<DataTreeCandidate>> listenerChanges) {
+        if (args.size() == offset) {
             notifyNode(candidate.getRootPath(), node, candidate.getRootNode(), listenerChanges);
+            return;
+        }
+
+        final var arg = args.get(offset);
+        final var exactChild = node.getExactChild(arg);
+        if (exactChild != null) {
+            lookupAndNotify(args, offset + 1, exactChild, candidate, listenerChanges);
+        }
+        for (var child : node.getInexactChildren(arg)) {
+            lookupAndNotify(args, offset + 1, child, candidate, listenerChanges);
         }
     }
 
-    private void notifyNode(final YangInstanceIdentifier path,
-            final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regNode,
-            final DataTreeCandidateNode candNode,
-            final Multimap<AbstractDOMDataTreeChangeListenerRegistration<?>, DataTreeCandidate> listenerChanges) {
-        if (candNode.getModificationType() == ModificationType.UNMODIFIED) {
+    private void notifyNode(final YangInstanceIdentifier path, final Node<RegImpl> regNode,
+            final DataTreeCandidateNode candNode, final Map<Reg, List<DataTreeCandidate>> listenerChanges) {
+        if (candNode.modificationType() == ModificationType.UNMODIFIED) {
             LOG.debug("Skipping unmodified candidate {}", path);
             return;
         }
 
-        final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> regs = regNode.getRegistrations();
+        final var regs = regNode.getRegistrations();
         if (!regs.isEmpty()) {
-            addToListenerChanges(regs, path, candNode, listenerChanges);
+            final var dataTreeCandidate = DataTreeCandidates.newDataTreeCandidate(path, candNode);
+            for (var reg : regs) {
+                listenerChanges.computeIfAbsent(reg, ignored -> new ArrayList<>()).add(dataTreeCandidate);
+            }
         }
 
-        for (DataTreeCandidateNode candChild : candNode.getChildNodes()) {
-            if (candChild.getModificationType() != ModificationType.UNMODIFIED) {
-                final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regChild =
-                        regNode.getExactChild(candChild.getIdentifier());
+        for (var candChild : candNode.childNodes()) {
+            if (candChild.modificationType() != ModificationType.UNMODIFIED) {
+                final var regChild = regNode.getExactChild(candChild.name());
                 if (regChild != null) {
-                    notifyNode(path.node(candChild.getIdentifier()), regChild, candChild, listenerChanges);
+                    notifyNode(path.node(candChild.name()), regChild, candChild, listenerChanges);
                 }
 
-                for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> rc :
-                    regNode.getInexactChildren(candChild.getIdentifier())) {
-                    notifyNode(path.node(candChild.getIdentifier()), rc, candChild, listenerChanges);
+                for (var rc : regNode.getInexactChildren(candChild.name())) {
+                    notifyNode(path.node(candChild.name()), rc, candChild, listenerChanges);
                 }
             }
         }
     }
-
-    private static void addToListenerChanges(
-            final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> registrations,
-            final YangInstanceIdentifier path, final DataTreeCandidateNode node,
-            final Multimap<AbstractDOMDataTreeChangeListenerRegistration<?>, DataTreeCandidate> listenerChanges) {
-        final DataTreeCandidate dataTreeCandidate = DataTreeCandidates.newDataTreeCandidate(path, node);
-
-        for (AbstractDOMDataTreeChangeListenerRegistration<?> reg : registrations) {
-            listenerChanges.put(reg, dataTreeCandidate);
-        }
-    }
 }