Add registerNotificationListeners() 24/101624/2
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 24 Jun 2022 12:59:30 +0000 (14:59 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 24 Jun 2022 19:14:29 +0000 (21:14 +0200)
We have a use case where we really want to perform a bulk registration
of multiple listeners. Add the corresponding method and implement it in
DOMNotificationRouter.

JIRA: MDSAL-701
Change-Id: I57e16f4f1044a96ee06dafb003436d84ca47c829
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
dom/mdsal-dom-api/src/main/java/module-info.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMNotificationService.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMNotificationRouter.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMNotificationService.java

index 35d55a2b937035d130105608b1a306598623f9f6..de37454ad834d53d0b661c6ead5d87ff8011b748 100644 (file)
@@ -9,6 +9,7 @@ module org.opendaylight.mdsal.dom.api {
     exports org.opendaylight.mdsal.dom.api;
     exports org.opendaylight.mdsal.dom.api.query;
 
+    requires transitive com.google.common;
     requires transitive org.opendaylight.yangtools.yang.common;
     requires transitive org.opendaylight.yangtools.yang.data.api;
     requires transitive org.opendaylight.yangtools.yang.data.tree.api;
index 7d0bd53859c4d6c280929761fdfb0e2bfe171756..283215a7e52adb6f6c161a86e06027f8f8329ed7 100644 (file)
@@ -9,8 +9,10 @@ package org.opendaylight.mdsal.dom.api;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 
 /**
@@ -19,7 +21,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absol
 public interface DOMNotificationService extends DOMService {
     /**
      * Register a {@link DOMNotificationListener} to receive a set of notifications. As with other
-     * ListenerRegistration-based interfaces, registering an instance multiple times results in
+     * {@link ListenerRegistration}-based interfaces, registering an instance multiple times results in
      * notifications being delivered for each registration.
      *
      * @param listener Notification instance to register
@@ -36,7 +38,7 @@ public interface DOMNotificationService extends DOMService {
 
     /**
      * Register a {@link DOMNotificationListener} to receive a set of notifications. As with other
-     * ListenerRegistration-based interfaces, registering an instance multiple times results in
+     * {@link ListenerRegistration}-based interfaces, registering an instance multiple times results in
      * notifications being delivered for each registration.
      *
      * @param listener Notification instance to register
@@ -52,4 +54,14 @@ public interface DOMNotificationService extends DOMService {
             registerNotificationListener(@NonNull final T listener, final Absolute... types) {
         return registerNotificationListener(listener, Arrays.asList(types));
     }
+
+    /**
+     * Register a number of {@link DOMNotificationListener}s to receive some notification notifications. As with other
+     * {@link Registration}-based interfaces, registering an instance multiple times results in
+     * notifications being delivered for each registration.
+     *
+     * @param typeToListener Specification of which types to listen to with which listeners
+     * @throws NullPointerException if {@code typeToListener} is {@code null}
+     */
+    @NonNull Registration registerNotificationListeners(@NonNull Map<Absolute, DOMNotificationListener> typeToListener);
 }
index 35db4b41f59a97f5e302abfcff184fead356549a..5e739888307dd06d025c7b09fba27daa1fd47821 100644 (file)
@@ -18,7 +18,9 @@ import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -35,7 +37,9 @@ import org.opendaylight.mdsal.dom.api.DOMNotificationService;
 import org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListener;
 import org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListenerRegistry;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.concepts.AbstractRegistration;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.util.ListenerRegistry;
 import org.opendaylight.yangtools.util.concurrent.EqualityQueuedNotificationManager;
 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
@@ -73,8 +77,14 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
     }
 
     @VisibleForTesting
-    final class Reg<T extends DOMNotificationListener> extends AbstractListenerRegistration<T> {
-        private Reg(final @NonNull T listener) {
+    abstract static sealed class Reg<T extends DOMNotificationListener> extends AbstractListenerRegistration<T> {
+        Reg(final @NonNull T listener) {
+            super(listener);
+        }
+    }
+
+    private final class SingleReg<T extends DOMNotificationListener> extends Reg<T> {
+        SingleReg(final @NonNull T listener) {
             super(listener);
         }
 
@@ -84,6 +94,17 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
         }
     }
 
+    private static final class ComponentReg extends Reg<DOMNotificationListener> {
+        ComponentReg(final @NonNull DOMNotificationListener listener) {
+            super(listener);
+        }
+
+        @Override
+        protected void removeRegistration() {
+            // No-op
+        }
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(DOMNotificationRouter.class);
     private static final ListenableFuture<Void> NO_LISTENERS = FluentFutures.immediateNullFluentFuture();
 
@@ -124,13 +145,13 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
     @Override
     public synchronized <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(
             final T listener, final Collection<Absolute> types) {
-        final var reg = new Reg<>(listener);
+        final var reg = new SingleReg<>(listener);
 
         if (!types.isEmpty()) {
             final var b = ImmutableMultimap.<Absolute, Reg<?>>builder();
             b.putAll(listeners);
 
-            for (final Absolute t : types) {
+            for (var t : types) {
                 b.put(t, reg);
             }
 
@@ -140,10 +161,35 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
         return reg;
     }
 
-    private synchronized void removeRegistration(final Reg<?> reg) {
+    @Override
+    public synchronized Registration registerNotificationListeners(
+            final Map<Absolute, DOMNotificationListener> typeToListener) {
+        final var b = ImmutableMultimap.<Absolute, Reg<?>>builder();
+        b.putAll(listeners);
+
+        final var tmp = new HashMap<DOMNotificationListener, ComponentReg>();
+        for (var e : typeToListener.entrySet()) {
+            b.put(e.getKey(), tmp.computeIfAbsent(e.getValue(), ComponentReg::new));
+        }
+
+        final var regs = List.copyOf(tmp.values());
+        return new AbstractRegistration() {
+            @Override
+            protected void removeRegistration() {
+                regs.forEach(ComponentReg::close);
+                removeRegistrations(regs);
+            }
+        };
+    }
+
+    private synchronized void removeRegistration(final SingleReg<?> reg) {
         replaceListeners(ImmutableMultimap.copyOf(Multimaps.filterValues(listeners, input -> input != reg)));
     }
 
+    private synchronized void removeRegistrations(final List<ComponentReg> regs) {
+        replaceListeners(ImmutableMultimap.copyOf(Multimaps.filterValues(listeners, input -> !regs.contains(input))));
+    }
+
     /**
      * Swaps registered listeners and triggers notification update.
      *
index 079cb186cc04128d4aa46e1b6305eeb95a3b7df8..e044787b37c4cfd5b7499d69dc10e668fb779c0c 100644 (file)
@@ -9,9 +9,11 @@ package org.opendaylight.mdsal.dom.spi;
 
 import com.google.common.collect.ForwardingObject;
 import java.util.Collection;
+import java.util.Map;
 import org.opendaylight.mdsal.dom.api.DOMNotificationListener;
 import org.opendaylight.mdsal.dom.api.DOMNotificationService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 
 /**
@@ -33,4 +35,9 @@ public abstract class ForwardingDOMNotificationService extends ForwardingObject
             final Absolute... types) {
         return delegate().registerNotificationListener(listener, types);
     }
+
+    @Override
+    public Registration registerNotificationListeners(final Map<Absolute, DOMNotificationListener> typeToListener) {
+        return delegate().registerNotificationListeners(typeToListener);
+    }
 }