BUG-1120: fold GenerationalListenerMap back
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / impl / NotificationBrokerImpl.java
index fd0b263f8e51cc1028571906cb54da98b727f5f7..258ba517775a2145f3c3046ebbf08194123a0439 100644 (file)
@@ -9,6 +9,9 @@ package org.opendaylight.controller.sal.binding.impl;
 
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.concurrent.GuardedBy;
 
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
@@ -22,13 +25,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
 
 public class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(NotificationBrokerImpl.class);
 
     private final ListenerRegistry<NotificationInterestListener> interestListeners =
             ListenerRegistry.create();
-    private final GenerationalListenerMap listeners = new GenerationalListenerMap();
+    private final AtomicReference<ListenerMapGeneration> listeners = new AtomicReference<>(new ListenerMapGeneration());
     private final ExecutorService executor;
 
     public NotificationBrokerImpl(final ExecutorService executor) {
@@ -42,18 +47,44 @@ public class NotificationBrokerImpl implements NotificationProviderService, Auto
 
     @Override
     public void publish(final Notification notification, final ExecutorService service) {
-        for (NotificationListenerRegistration<?> r : listeners.listenersFor(notification)) {
+        for (NotificationListenerRegistration<?> r : listeners.get().listenersFor(notification)) {
             service.submit(new NotifyTask(r, notification));
         }
     }
 
+    @GuardedBy("this")
+    private Multimap<Class<? extends Notification>, NotificationListenerRegistration<?>> mutableListeners() {
+        return HashMultimap.create(listeners.get().getListeners());
+    }
+
     private final void addRegistrations(final NotificationListenerRegistration<?>... registrations) {
-        listeners.addRegistrations(registrations);
+        synchronized (this) {
+            final Multimap<Class<? extends Notification>, NotificationListenerRegistration<?>> newListeners =
+                    mutableListeners();
+            for (NotificationListenerRegistration<?> reg : registrations) {
+                newListeners.put(reg.getType(), reg);
+            }
+
+            listeners.set(new ListenerMapGeneration(newListeners));
+        }
+
+        // Notifications are dispatched out of lock...
         for (NotificationListenerRegistration<?> reg : registrations) {
             announceNotificationSubscription(reg.getType());
         }
     }
 
+    private synchronized void removeRegistrations(final NotificationListenerRegistration<?>... registrations) {
+        final Multimap<Class<? extends Notification>, NotificationListenerRegistration<?>> newListeners =
+                mutableListeners();
+
+        for (NotificationListenerRegistration<?> reg : registrations) {
+            newListeners.remove(reg.getType(), reg);
+        }
+
+        listeners.set(new ListenerMapGeneration(newListeners));
+    }
+
     private void announceNotificationSubscription(final Class<? extends Notification> notification) {
         for (final ListenerRegistration<NotificationInterestListener> listener : interestListeners) {
             try {
@@ -68,7 +99,8 @@ public class NotificationBrokerImpl implements NotificationProviderService, Auto
     @Override
     public ListenerRegistration<NotificationInterestListener> registerInterestListener(final NotificationInterestListener interestListener) {
         final ListenerRegistration<NotificationInterestListener> registration = this.interestListeners.register(interestListener);
-        for (final Class<? extends Notification> notification : listeners.getKnownTypes()) {
+
+        for (final Class<? extends Notification> notification : listeners.get().getKnownTypes()) {
             interestListener.onNotificationSubscribtion(notification);
         }
         return registration;
@@ -79,7 +111,7 @@ public class NotificationBrokerImpl implements NotificationProviderService, Auto
         final NotificationListenerRegistration<T> reg = new AbstractNotificationListenerRegistration<T>(notificationType, listener) {
             @Override
             protected void removeRegistration() {
-                listeners.removeRegistrations(this);
+                removeRegistrations(this);
             }
         };
 
@@ -112,7 +144,7 @@ public class NotificationBrokerImpl implements NotificationProviderService, Auto
         return new AbstractListenerRegistration<org.opendaylight.yangtools.yang.binding.NotificationListener>(listener) {
             @Override
             protected void removeRegistration() {
-                listeners.removeRegistrations(regs);
+                removeRegistrations(regs);
                 for (ListenerRegistration<?> reg : regs) {
                     reg.close();
                 }