Adding some base-classes to eliminate event and listener boiler-plate code throughout a number of subsystems.

Refactored all core components to take advantage of this; apps remain to be done.

Change-Id: Ib0935ba07ff81b0fa032534004ec9ac6187cbf22
diff --git a/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java b/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
index 153b024..a96d805 100644
--- a/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
+++ b/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
@@ -30,11 +30,10 @@
 import org.onosproject.app.ApplicationState;
 import org.onosproject.app.ApplicationStore;
 import org.onosproject.app.ApplicationStoreDelegate;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.core.Application;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.event.EventDeliveryService;
 import org.slf4j.Logger;
 
 import java.io.InputStream;
@@ -50,15 +49,14 @@
  */
 @Component(immediate = true)
 @Service
-public class ApplicationManager implements ApplicationService, ApplicationAdminService {
+public class ApplicationManager
+        extends AbstractListenerManager<ApplicationEvent, ApplicationListener>
+        implements ApplicationService, ApplicationAdminService {
 
     private final Logger log = getLogger(getClass());
 
     private static final String APP_ID_NULL = "Application ID cannot be null";
 
-    protected final ListenerRegistry<ApplicationEvent, ApplicationListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     private final ApplicationStoreDelegate delegate = new InternalStoreDelegate();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -67,9 +65,6 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected FeaturesService featuresService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
     private boolean initializing;
 
     @Activate
@@ -99,7 +94,6 @@
     @Override
     public ApplicationId getId(String name) {
         checkPermission(Permission.APP_READ);
-
         checkNotNull(name, "Name cannot be null");
         return store.getId(name);
     }
@@ -160,18 +154,6 @@
         store.setPermissions(appId, permissions);
     }
 
-    @Override
-    public void addListener(ApplicationListener listener) {
-        checkPermission(Permission.APP_EVENT);
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(ApplicationListener listener) {
-        checkPermission(Permission.APP_EVENT);
-        listenerRegistry.removeListener(listener);
-    }
-
     private class InternalStoreDelegate implements ApplicationStoreDelegate {
         @Override
         public void notify(ApplicationEvent event) {
@@ -199,7 +181,7 @@
                     }
 
                 }
-                eventDispatcher.post(event);
+                post(event);
 
             } catch (Exception e) {
                 log.warn("Unable to perform operation on application " + app.id().name(), e);
diff --git a/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java b/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java
index 22284b6..a823817 100644
--- a/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java
+++ b/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java
@@ -33,17 +33,16 @@
 import org.onosproject.cluster.ClusterStoreDelegate;
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.NodeId;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.event.EventDeliveryService;
 import org.slf4j.Logger;
 
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 /**
@@ -51,16 +50,15 @@
  */
 @Component(immediate = true)
 @Service
-public class ClusterManager implements ClusterService, ClusterAdminService {
+public class ClusterManager
+        extends AbstractListenerManager<ClusterEvent, ClusterEventListener>
+        implements ClusterService, ClusterAdminService {
 
     public static final String INSTANCE_ID_NULL = "Instance ID cannot be null";
     private final Logger log = getLogger(getClass());
 
     private ClusterStoreDelegate delegate = new InternalStoreDelegate();
 
-    protected final ListenerRegistry<ClusterEvent, ClusterEventListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ClusterDefinitionService clusterDefinitionService;
 
@@ -68,9 +66,6 @@
     protected ClusterStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected SystemService systemService;
 
     @Activate
@@ -150,24 +145,11 @@
         store.removeNode(nodeId);
     }
 
-    @Override
-    public void addListener(ClusterEventListener listener) {
-        checkPermission(Permission.CLUSTER_EVENT);
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(ClusterEventListener listener) {
-        checkPermission(Permission.CLUSTER_EVENT);
-        listenerRegistry.removeListener(listener);
-    }
-
     // Store delegate to re-post events emitted from the store.
     private class InternalStoreDelegate implements ClusterStoreDelegate {
         @Override
         public void notify(ClusterEvent event) {
-            checkNotNull(event, "Event cannot be null");
-            eventDispatcher.post(event);
+            post(event);
         }
     }
 }
diff --git a/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java b/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java
index 1ac073a..0ef66f4 100644
--- a/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java
+++ b/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java
@@ -19,7 +19,6 @@
 import com.codahale.metrics.Timer.Context;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.Futures;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -31,10 +30,9 @@
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.cluster.RoleInfo;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.core.MetricsHelper;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.event.EventDeliveryService;
 import org.onosproject.mastership.MastershipAdminService;
 import org.onosproject.mastership.MastershipEvent;
 import org.onosproject.mastership.MastershipListener;
@@ -62,13 +60,14 @@
 import static org.onlab.metrics.MetricsUtil.stopTimer;
 import static org.onosproject.cluster.ControllerNode.State.ACTIVE;
 import static org.onosproject.net.MastershipRole.MASTER;
-import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 @Component(immediate = true)
 @Service
 public class MastershipManager
+    extends AbstractListenerManager<MastershipEvent, MastershipListener>
     implements MastershipService, MastershipAdminService, MastershipTermService,
                MetricsHelper {
 
@@ -78,18 +77,12 @@
 
     private final Logger log = getLogger(getClass());
 
-    protected final ListenerRegistry<MastershipEvent, MastershipListener>
-    listenerRegistry = new ListenerRegistry<>();
-
     private final MastershipStoreDelegate delegate = new InternalDelegate();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected MastershipStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ClusterService clusterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -197,22 +190,6 @@
     }
 
     @Override
-    public void addListener(MastershipListener listener) {
-        checkPermission(Permission.CLUSTER_EVENT);
-
-        checkNotNull(listener);
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(MastershipListener listener) {
-        checkPermission(Permission.CLUSTER_EVENT);
-
-        checkNotNull(listener);
-        listenerRegistry.removeListener(listener);
-    }
-
-    @Override
     public MetricsService metricsService() {
         return metricsService;
     }
@@ -294,21 +271,11 @@
     }
 
 
-    // Posts the specified event to the local event dispatcher.
-    private void post(MastershipEvent event) {
-        if (event != null && eventDispatcher != null) {
-            eventDispatcher.post(event);
-        }
-    }
-
     public class InternalDelegate implements MastershipStoreDelegate {
-
         @Override
         public void notify(MastershipEvent event) {
-            log.trace("dispatching mastership event {}", event);
-            eventDispatcher.post(event);
+            post(event);
         }
-
     }
 
 }
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index 17ff85c..96b7176c 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -15,26 +15,7 @@
  */
 package org.onosproject.net.device.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.MastershipRole.MASTER;
-import static org.onosproject.net.MastershipRole.NONE;
-import static org.onosproject.net.MastershipRole.STANDBY;
-import static org.onosproject.security.AppGuard.checkPermission;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
+import com.google.common.collect.Lists;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -43,9 +24,8 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.NodeId;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.core.Permission;
-import org.onosproject.event.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.incubator.net.config.NetworkConfigEvent;
 import org.onosproject.incubator.net.config.NetworkConfigListener;
 import org.onosproject.incubator.net.config.NetworkConfigService;
@@ -78,11 +58,26 @@
 import org.onosproject.net.device.DeviceStoreDelegate;
 import org.onosproject.net.device.PortDescription;
 import org.onosproject.net.device.PortStatistics;
-import org.onosproject.net.provider.AbstractProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
-import com.google.common.collect.Lists;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.MastershipRole.*;
+import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 /**
@@ -91,7 +86,7 @@
 @Component(immediate = true)
 @Service
 public class DeviceManager
-        extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService>
+        extends AbstractListenerProviderRegistry<DeviceEvent, DeviceListener, DeviceProvider, DeviceProviderService>
         implements DeviceService, DeviceAdminService, DeviceProviderRegistry {
 
     private static final String DEVICE_ID_NULL = "Device ID cannot be null";
@@ -101,9 +96,6 @@
 
     private final Logger log = getLogger(getClass());
 
-    protected final ListenerRegistry<DeviceEvent, DeviceListener> listenerRegistry =
-            new ListenerRegistry<>();
-
     private final DeviceStoreDelegate delegate = new InternalStoreDelegate();
 
     private final MastershipListener mastershipListener = new InternalMastershipListener();
@@ -117,9 +109,6 @@
     protected DeviceStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ClusterService clusterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -135,7 +124,6 @@
     protected NetworkConfigService networkConfigService;
 
 
-
     @Activate
     public void activate() {
         backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device", "manager-background"));
@@ -146,15 +134,11 @@
         mastershipService.addListener(mastershipListener);
         networkConfigService.addListener(networkConfigListener);
 
-        backgroundService.scheduleWithFixedDelay(new Runnable() {
-
-            @Override
-            public void run() {
-                try {
-                    mastershipCheck();
-                } catch (Exception e) {
-                    log.error("Exception thrown during integrity check", e);
-                }
+        backgroundService.scheduleWithFixedDelay(() -> {
+            try {
+                mastershipCheck();
+            } catch (Exception e) {
+                log.error("Exception thrown during integrity check", e);
             }
         }, 1, 1, TimeUnit.MINUTES);
         log.info("Started");
@@ -173,28 +157,24 @@
     @Override
     public int getDeviceCount() {
         checkPermission(Permission.DEVICE_READ);
-
         return store.getDeviceCount();
     }
 
     @Override
     public Iterable<Device> getDevices() {
         checkPermission(Permission.DEVICE_READ);
-
         return store.getDevices();
     }
 
     @Override
     public Iterable<Device> getAvailableDevices() {
         checkPermission(Permission.DEVICE_READ);
-
         return store.getAvailableDevices();
     }
 
     @Override
     public Device getDevice(DeviceId deviceId) {
         checkPermission(Permission.DEVICE_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getDevice(deviceId);
     }
@@ -202,7 +182,6 @@
     @Override
     public MastershipRole getRole(DeviceId deviceId) {
         checkPermission(Permission.DEVICE_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return mastershipService.getLocalRole(deviceId);
     }
@@ -210,7 +189,6 @@
     @Override
     public List<Port> getPorts(DeviceId deviceId) {
         checkPermission(Permission.DEVICE_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getPorts(deviceId);
     }
@@ -218,7 +196,6 @@
     @Override
     public List<PortStatistics> getPortStatistics(DeviceId deviceId) {
         checkPermission(Permission.DEVICE_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getPortStatistics(deviceId);
     }
@@ -226,7 +203,6 @@
     @Override
     public Port getPort(DeviceId deviceId, PortNumber portNumber) {
         checkPermission(Permission.DEVICE_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         checkNotNull(portNumber, PORT_NUMBER_NULL);
         return store.getPort(deviceId, portNumber);
@@ -265,20 +241,6 @@
     }
 
     @Override
-    public void addListener(DeviceListener listener) {
-        checkPermission(Permission.DEVICE_EVENT);
-
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(DeviceListener listener) {
-        checkPermission(Permission.DEVICE_EVENT);
-
-        listenerRegistry.removeListener(listener);
-    }
-
-    @Override
     protected DeviceProviderService createProviderService(
             DeviceProvider provider) {
         return new InternalDeviceProviderService(provider);
@@ -322,8 +284,8 @@
         /**
          * Apply role in reaction to provider event.
          *
-         * @param deviceId  device identifier
-         * @param newRole   new role to apply to the device
+         * @param deviceId device identifier
+         * @param newRole  new role to apply to the device
          * @return true if the request was sent to provider
          */
         private boolean applyRole(DeviceId deviceId, MastershipRole newRole) {
@@ -400,7 +362,7 @@
                                                                      cfg.type(), finalSparse);
                 } else {
                     deviceDescription = new DefaultDeviceDescription(deviceDescription,
-                            deviceDescription.type(), finalSparse);
+                                                                     deviceDescription.type(), finalSparse);
                 }
             }
             return deviceDescription;
@@ -416,9 +378,9 @@
             List<Port> ports = store.getPorts(deviceId);
             List<PortDescription> descs = Lists.newArrayList();
             ports.forEach(port ->
-                descs.add(new DefaultPortDescription(port.number(),
-                                                     false, port.type(),
-                                                     port.portSpeed())));
+                                  descs.add(new DefaultPortDescription(port.number(),
+                                                                       false, port.type(),
+                                                                       port.portSpeed())));
             store.updatePorts(this.provider().id(), deviceId, descs);
             try {
                 if (mastershipService.getLocalRole(deviceId) == MASTER) {
@@ -467,7 +429,7 @@
                                 List<PortDescription> portDescriptions) {
             checkNotNull(deviceId, DEVICE_ID_NULL);
             checkNotNull(portDescriptions,
-                    "Port descriptions list cannot be null");
+                         "Port descriptions list cannot be null");
             checkValidity();
             if (!deviceClockProviderService.isTimestampAvailable(deviceId)) {
                 // Never been a master for this device
@@ -521,7 +483,7 @@
             // FIXME: implement response to this notification
 
             log.debug("got reply to a role request for {}: asked for {}, and got {}",
-                    deviceId, requested, response);
+                      deviceId, requested, response);
 
             if (requested == null && response == null) {
                 // something was off with DeviceProvider, maybe check channel too?
@@ -593,19 +555,13 @@
         }
     }
 
-    // Posts the specified event to the local event dispatcher.
-    private void post(DeviceEvent event) {
-        if (event != null && eventDispatcher != null) {
-            eventDispatcher.post(event);
-        }
-    }
-
     // Applies the specified role to the device; ignores NONE
+
     /**
      * Apply role to device and send probe if MASTER.
      *
-     * @param deviceId  device identifier
-     * @param newRole   new role to apply to the device
+     * @param deviceId device identifier
+     * @param newRole  new role to apply to the device
      * @return true if the request was sent to provider
      */
     private boolean applyRoleAndProbe(DeviceId deviceId, MastershipRole newRole) {
@@ -631,9 +587,9 @@
     /**
      * Reaasert role for specified device connected to this node.
      *
-     * @param did         device identifier
-     * @param nextRole    role to apply. If NONE is specified,
-     *        it will ask mastership service for a role and apply it.
+     * @param did      device identifier
+     * @param nextRole role to apply. If NONE is specified,
+     *                 it will ask mastership service for a role and apply it.
      */
     private void reassertRole(final DeviceId did,
                               final MastershipRole nextRole) {
@@ -650,46 +606,46 @@
         }
 
         switch (myNextRole) {
-        case MASTER:
-            final Device device = getDevice(did);
-            if ((device != null) && !isAvailable(did)) {
-                //flag the device as online. Is there a better way to do this?
-                DefaultDeviceDescription deviceDescription
-                    = new DefaultDeviceDescription(did.uri(),
-                                                   device.type(),
-                                                   device.manufacturer(),
-                                                   device.hwVersion(),
-                                                   device.swVersion(),
-                                                   device.serialNumber(),
-                                                   device.chassisId());
-                DeviceEvent devEvent =
-                        store.createOrUpdateDevice(device.providerId(), did,
-                                                   deviceDescription);
-                post(devEvent);
-            }
-            // TODO: should apply role only if there is mismatch
-            log.debug("Applying role {} to {}", myNextRole, did);
-            if (!applyRoleAndProbe(did, MASTER)) {
-                log.warn("Unsuccessful applying role {} to {}", myNextRole, did);
-                // immediately failed to apply role
-                mastershipService.relinquishMastership(did);
-                // FIXME disconnect?
-            }
-            break;
-        case STANDBY:
-            log.debug("Applying role {} to {}", myNextRole, did);
-            if (!applyRoleAndProbe(did, STANDBY)) {
-                log.warn("Unsuccessful applying role {} to {}", myNextRole, did);
-                // immediately failed to apply role
-                mastershipService.relinquishMastership(did);
-                // FIXME disconnect?
-            }
-            break;
-        case NONE:
-        default:
-            // should never reach here
-            log.error("You didn't see anything. I did not exist.");
-            break;
+            case MASTER:
+                final Device device = getDevice(did);
+                if ((device != null) && !isAvailable(did)) {
+                    //flag the device as online. Is there a better way to do this?
+                    DefaultDeviceDescription deviceDescription
+                            = new DefaultDeviceDescription(did.uri(),
+                                                           device.type(),
+                                                           device.manufacturer(),
+                                                           device.hwVersion(),
+                                                           device.swVersion(),
+                                                           device.serialNumber(),
+                                                           device.chassisId());
+                    DeviceEvent devEvent =
+                            store.createOrUpdateDevice(device.providerId(), did,
+                                                       deviceDescription);
+                    post(devEvent);
+                }
+                // TODO: should apply role only if there is mismatch
+                log.debug("Applying role {} to {}", myNextRole, did);
+                if (!applyRoleAndProbe(did, MASTER)) {
+                    log.warn("Unsuccessful applying role {} to {}", myNextRole, did);
+                    // immediately failed to apply role
+                    mastershipService.relinquishMastership(did);
+                    // FIXME disconnect?
+                }
+                break;
+            case STANDBY:
+                log.debug("Applying role {} to {}", myNextRole, did);
+                if (!applyRoleAndProbe(did, STANDBY)) {
+                    log.warn("Unsuccessful applying role {} to {}", myNextRole, did);
+                    // immediately failed to apply role
+                    mastershipService.relinquishMastership(did);
+                    // FIXME disconnect?
+                }
+                break;
+            case NONE:
+            default:
+                // should never reach here
+                log.error("You didn't see anything. I did not exist.");
+                break;
         }
     }
 
@@ -725,8 +681,8 @@
             // device is not connected to this node
             if (myNextRole != NONE) {
                 log.warn("Node was instructed to be {} role for {}, "
-                        + "but this node cannot reach the device.  "
-                        + "Relinquishing role.  ",
+                                 + "but this node cannot reach the device.  "
+                                 + "Relinquishing role.  ",
                          myNextRole, did);
                 mastershipService.relinquishMastership(did);
             }
@@ -796,13 +752,16 @@
 
     private class InternalNetworkConfigListener implements NetworkConfigListener {
         @Override
+        public boolean isRelevant(NetworkConfigEvent event) {
+            return (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)
+                    && event.configClass().equals(BasicDeviceConfig.class);
+        }
+
+        @Override
         public void event(NetworkConfigEvent event) {
-            if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
-                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
-                    event.configClass().equals(BasicDeviceConfig.class)) {
-                log.info("Detected Device network config event {}", event.type());
-                kickOutBadDevice(((DeviceId) event.subject()));
-            }
+            log.info("Detected Device network config event {}", event.type());
+            kickOutBadDevice(((DeviceId) event.subject()));
         }
     }
 
@@ -814,8 +773,6 @@
             Device badDevice = getDevice(deviceId);
             if (badDevice != null) {
                 removeDevice(deviceId);
-            } else {
-                log.info("Failed removal: Device {} does not exist", deviceId);
             }
         }
     }
diff --git a/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java b/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java
index 45e467d..e992f7a 100644
--- a/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java
+++ b/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java
@@ -26,9 +26,8 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.event.Event;
-import org.onosproject.event.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceEvent;
@@ -64,7 +63,9 @@
  */
 @Component(immediate = true)
 @Service
-public class EdgeManager implements EdgePortService {
+public class EdgeManager
+        extends AbstractListenerManager<EdgePortEvent, EdgePortListener>
+        implements EdgePortService {
 
     private final Logger log = getLogger(getClass());
 
@@ -72,15 +73,9 @@
 
     private final Map<DeviceId, Set<ConnectPoint>> connectionPoints = Maps.newConcurrentMap();
 
-    private final ListenerRegistry<EdgePortEvent, EdgePortListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     private final TopologyListener topologyListener = new InnerTopologyListener();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PacketService packetService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -147,17 +142,6 @@
         return new DefaultOutboundPacket(point.deviceId(), builder.build(), data);
     }
 
-    @Override
-    public void addListener(EdgePortListener listener) {
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(EdgePortListener listener) {
-        listenerRegistry.removeListener(listener);
-    }
-
-
     // Internal listener for topo events used to keep our edge-port cache
     // up to date.
     private class InnerTopologyListener implements TopologyListener {
@@ -234,7 +218,7 @@
                 connectionPoints.put(point.deviceId(), set);
             }
             if (set.add(point)) {
-                eventDispatcher.post(new EdgePortEvent(EDGE_PORT_ADDED, point));
+                post(new EdgePortEvent(EDGE_PORT_ADDED, point));
             }
         }
     }
@@ -247,7 +231,7 @@
                 return;
             }
             if (set.remove(point)) {
-                eventDispatcher.post(new EdgePortEvent(EDGE_PORT_REMOVED, point));
+                post(new EdgePortEvent(EDGE_PORT_REMOVED, point));
             }
             if (set.isEmpty()) {
                 connectionPoints.remove(point.deviceId());
diff --git a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
index b92067f..b35002d 100644
--- a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
@@ -32,12 +32,11 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.IdGenerator;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.event.EventDeliveryService;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
@@ -60,7 +59,6 @@
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.FlowRuleStore;
 import org.onosproject.net.flow.FlowRuleStoreDelegate;
-import org.onosproject.net.provider.AbstractProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
@@ -77,8 +75,10 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onlab.util.Tools.groupedThreads;
-import static org.slf4j.LoggerFactory.getLogger;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED;
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 /**
@@ -87,7 +87,8 @@
 @Component(immediate = true, enabled = true)
 @Service
 public class FlowRuleManager
-        extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
+        extends AbstractListenerProviderRegistry<FlowRuleEvent, FlowRuleListener,
+                                                 FlowRuleProvider, FlowRuleProviderService>
         implements FlowRuleService, FlowRuleProviderRegistry {
 
     public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
@@ -99,9 +100,6 @@
 
     private final Logger log = getLogger(getClass());
 
-    private final ListenerRegistry<FlowRuleEvent, FlowRuleListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
 
     protected ExecutorService deviceInstallers =
@@ -119,9 +117,6 @@
     protected FlowRuleStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -171,14 +166,12 @@
     @Override
     public int getFlowRuleCount() {
         checkPermission(Permission.FLOWRULE_READ);
-
         return store.getFlowRuleCount();
     }
 
     @Override
     public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
         checkPermission(Permission.FLOWRULE_READ);
-
         return store.getFlowEntries(deviceId);
     }
 
@@ -207,7 +200,6 @@
     @Override
     public void removeFlowRulesById(ApplicationId id) {
         checkPermission(Permission.FLOWRULE_WRITE);
-
         removeFlowRules(Iterables.toArray(getFlowRulesById(id), FlowRule.class));
     }
 
@@ -245,25 +237,10 @@
     @Override
     public void apply(FlowRuleOperations ops) {
         checkPermission(Permission.FLOWRULE_WRITE);
-
         operationsService.submit(new FlowOperationsProcessor(ops));
     }
 
     @Override
-    public void addListener(FlowRuleListener listener) {
-        checkPermission(Permission.FLOWRULE_EVENT);
-
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(FlowRuleListener listener) {
-        checkPermission(Permission.FLOWRULE_EVENT);
-
-        listenerRegistry.removeListener(listener);
-    }
-
-    @Override
     protected FlowRuleProviderService createProviderService(
             FlowRuleProvider provider) {
         return new InternalFlowRuleProviderService(provider);
@@ -408,13 +385,6 @@
             return false;
         }
 
-        // Posts the specified event to the local event dispatcher.
-        private void post(FlowRuleEvent event) {
-            if (event != null) {
-                eventDispatcher.post(event);
-            }
-        }
-
         @Override
         public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries) {
             Set<FlowEntry> storedRules = Sets.newHashSet(store.getFlowEntries(deviceId));
@@ -473,16 +443,12 @@
                             switch (op.operator()) {
 
                                 case ADD:
-                                    eventDispatcher.post(
-                                            new FlowRuleEvent(
-                                                    FlowRuleEvent.Type.RULE_ADD_REQUESTED,
-                                                    op.target()));
+                                    post(new FlowRuleEvent(RULE_ADD_REQUESTED,
+                                                           op.target()));
                                     break;
                                 case REMOVE:
-                                    eventDispatcher.post(
-                                            new FlowRuleEvent(
-                                                    FlowRuleEvent.Type.RULE_REMOVE_REQUESTED,
-                                                    op.target()));
+                                    post(new FlowRuleEvent(RULE_REMOVE_REQUESTED,
+                                                           op.target()));
                                     break;
                                 case MODIFY:
                                     //TODO: do something here when the time comes.
diff --git a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
index 352059a..6c43f24 100644
--- a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
+++ b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
@@ -15,21 +15,15 @@
  */
 package org.onosproject.net.group.impl;
 
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Collection;
-import java.util.Collections;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.Permission;
-import org.onosproject.event.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
@@ -49,11 +43,14 @@
 import org.onosproject.net.group.GroupStore;
 import org.onosproject.net.group.GroupStore.UpdateType;
 import org.onosproject.net.group.GroupStoreDelegate;
-import org.onosproject.net.provider.AbstractProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
+import java.util.Collection;
+import java.util.Collections;
+
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 /**
@@ -62,13 +59,12 @@
 @Component(immediate = true)
 @Service
 public class GroupManager
-        extends AbstractProviderRegistry<GroupProvider, GroupProviderService>
+        extends AbstractListenerProviderRegistry<GroupEvent, GroupListener,
+        GroupProvider, GroupProviderService>
         implements GroupService, GroupProviderRegistry {
 
     private final Logger log = getLogger(getClass());
 
-    private final ListenerRegistry<GroupEvent, GroupListener>
-                listenerRegistry = new ListenerRegistry<>();
     private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate();
     private final DeviceListener deviceListener = new InternalDeviceListener();
 
@@ -78,9 +74,6 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceService deviceService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
     @Activate
     public void activate() {
         store.setDelegate(delegate);
@@ -100,34 +93,29 @@
      * Create a group in the specified device with the provided parameters.
      *
      * @param groupDesc group creation parameters
-     *
      */
     @Override
     public void addGroup(GroupDescription groupDesc) {
         checkPermission(Permission.GROUP_WRITE);
-
-        log.trace("In addGroup API");
         store.storeGroupDescription(groupDesc);
     }
 
     /**
      * Return a group object associated to an application cookie.
-     *
+     * <p>
      * NOTE1: The presence of group object in the system does not
      * guarantee that the "group" is actually created in device.
      * GROUP_ADDED notification would confirm the creation of
      * this group in data plane.
      *
-     * @param deviceId device identifier
+     * @param deviceId  device identifier
      * @param appCookie application cookie to be used for lookup
      * @return group associated with the application cookie or
-     *               NULL if Group is not found for the provided cookie
+     * NULL if Group is not found for the provided cookie
      */
     @Override
     public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
         checkPermission(Permission.GROUP_READ);
-
-        log.trace("In getGroup API");
         return store.getGroup(deviceId, appCookie);
     }
 
@@ -137,21 +125,19 @@
      * GROUP_UPDATE_FAILED notifications would be provided along with
      * cookie depending on the result of the operation on the device.
      *
-     * @param deviceId device identifier
+     * @param deviceId  device identifier
      * @param oldCookie cookie to be used to retrieve the existing group
-     * @param buckets immutable list of group bucket to be added
+     * @param buckets   immutable list of group bucket to be added
      * @param newCookie immutable cookie to be used post update operation
-     * @param appId Application Id
+     * @param appId     Application Id
      */
     @Override
     public void addBucketsToGroup(DeviceId deviceId,
-                           GroupKey oldCookie,
-                           GroupBuckets buckets,
-                           GroupKey newCookie,
-                           ApplicationId appId) {
+                                  GroupKey oldCookie,
+                                  GroupBuckets buckets,
+                                  GroupKey newCookie,
+                                  ApplicationId appId) {
         checkPermission(Permission.GROUP_WRITE);
-
-        log.trace("In addBucketsToGroup API");
         store.updateGroupDescription(deviceId,
                                      oldCookie,
                                      UpdateType.ADD,
@@ -165,21 +151,19 @@
      * GROUP_UPDATE_FAILED notifications would be provided along with
      * cookie depending on the result of the operation on the device.
      *
-     * @param deviceId device identifier
+     * @param deviceId  device identifier
      * @param oldCookie cookie to be used to retrieve the existing group
-     * @param buckets immutable list of group bucket to be removed
+     * @param buckets   immutable list of group bucket to be removed
      * @param newCookie immutable cookie to be used post update operation
-     * @param appId Application Id
+     * @param appId     Application Id
      */
     @Override
     public void removeBucketsFromGroup(DeviceId deviceId,
-                                GroupKey oldCookie,
-                                GroupBuckets buckets,
-                                GroupKey newCookie,
-                                ApplicationId appId) {
+                                       GroupKey oldCookie,
+                                       GroupBuckets buckets,
+                                       GroupKey newCookie,
+                                       ApplicationId appId) {
         checkPermission(Permission.GROUP_WRITE);
-
-        log.trace("In removeBucketsFromGroup API");
         store.updateGroupDescription(deviceId,
                                      oldCookie,
                                      UpdateType.REMOVE,
@@ -193,17 +177,15 @@
      * provided along with cookie depending on the result of the
      * operation on the device.
      *
-     * @param deviceId device identifier
+     * @param deviceId  device identifier
      * @param appCookie application cookie to be used for lookup
-     * @param appId Application Id
+     * @param appId     Application Id
      */
     @Override
     public void removeGroup(DeviceId deviceId,
                             GroupKey appCookie,
                             ApplicationId appId) {
         checkPermission(Permission.GROUP_WRITE);
-
-        log.trace("In removeGroup API");
         store.deleteGroupDescription(deviceId, appCookie);
     }
 
@@ -212,52 +194,22 @@
      * as seen by current controller instance.
      *
      * @param deviceId device identifier
-     * @param appId application id
+     * @param appId    application id
      * @return collection of immutable group objects created by the application
      */
     @Override
     public Iterable<Group> getGroups(DeviceId deviceId,
                                      ApplicationId appId) {
         checkPermission(Permission.GROUP_READ);
-
-        log.trace("In getGroups API");
         return store.getGroups(deviceId);
     }
 
     @Override
     public Iterable<Group> getGroups(DeviceId deviceId) {
         checkPermission(Permission.GROUP_READ);
-
-        log.trace("In getGroups API");
         return store.getGroups(deviceId);
     }
 
-    /**
-     * Adds the specified group listener.
-     *
-     * @param listener group listener
-     */
-    @Override
-    public void addListener(GroupListener listener) {
-        checkPermission(Permission.GROUP_EVENT);
-
-        log.trace("In addListener API");
-        listenerRegistry.addListener(listener);
-    }
-
-    /**
-     * Removes the specified group listener.
-     *
-     * @param listener group listener
-     */
-    @Override
-    public void removeListener(GroupListener listener) {
-        checkPermission(Permission.GROUP_EVENT);
-
-        log.trace("In removeListener API");
-        listenerRegistry.removeListener(listener);
-    }
-
     @Override
     protected GroupProviderService createProviderService(GroupProvider provider) {
         return new InternalGroupProviderService(provider);
@@ -271,52 +223,52 @@
                     getProvider(group.deviceId());
             GroupOperations groupOps = null;
             switch (event.type()) {
-            case GROUP_ADD_REQUESTED:
-                log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
-                          group.id(), group.deviceId());
-                GroupOperation groupAddOp = GroupOperation.
-                        createAddGroupOperation(group.id(),
-                                                group.type(),
-                                                group.buckets());
-                groupOps = new GroupOperations(
-                        Collections.singletonList(groupAddOp));
-                groupProvider.performGroupOperation(group.deviceId(), groupOps);
-                break;
+                case GROUP_ADD_REQUESTED:
+                    log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
+                              group.id(), group.deviceId());
+                    GroupOperation groupAddOp = GroupOperation.
+                            createAddGroupOperation(group.id(),
+                                                    group.type(),
+                                                    group.buckets());
+                    groupOps = new GroupOperations(
+                            Collections.singletonList(groupAddOp));
+                    groupProvider.performGroupOperation(group.deviceId(), groupOps);
+                    break;
 
-            case GROUP_UPDATE_REQUESTED:
-                log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
-                          group.id(), group.deviceId());
-                GroupOperation groupModifyOp = GroupOperation.
-                        createModifyGroupOperation(group.id(),
-                                                group.type(),
-                                                group.buckets());
-                groupOps = new GroupOperations(
-                        Collections.singletonList(groupModifyOp));
-                groupProvider.performGroupOperation(group.deviceId(), groupOps);
-                break;
+                case GROUP_UPDATE_REQUESTED:
+                    log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
+                              group.id(), group.deviceId());
+                    GroupOperation groupModifyOp = GroupOperation.
+                            createModifyGroupOperation(group.id(),
+                                                       group.type(),
+                                                       group.buckets());
+                    groupOps = new GroupOperations(
+                            Collections.singletonList(groupModifyOp));
+                    groupProvider.performGroupOperation(group.deviceId(), groupOps);
+                    break;
 
-            case GROUP_REMOVE_REQUESTED:
-                log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
-                          group.id(), group.deviceId());
-                GroupOperation groupDeleteOp = GroupOperation.
-                        createDeleteGroupOperation(group.id(),
-                                                group.type());
-                groupOps = new GroupOperations(
-                        Collections.singletonList(groupDeleteOp));
-                groupProvider.performGroupOperation(group.deviceId(), groupOps);
-                break;
+                case GROUP_REMOVE_REQUESTED:
+                    log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
+                              group.id(), group.deviceId());
+                    GroupOperation groupDeleteOp = GroupOperation.
+                            createDeleteGroupOperation(group.id(),
+                                                       group.type());
+                    groupOps = new GroupOperations(
+                            Collections.singletonList(groupDeleteOp));
+                    groupProvider.performGroupOperation(group.deviceId(), groupOps);
+                    break;
 
-            case GROUP_ADDED:
-            case GROUP_UPDATED:
-            case GROUP_REMOVED:
-            case GROUP_ADD_FAILED:
-            case GROUP_UPDATE_FAILED:
-            case GROUP_REMOVE_FAILED:
-                eventDispatcher.post(event);
-                break;
+                case GROUP_ADDED:
+                case GROUP_UPDATED:
+                case GROUP_REMOVED:
+                case GROUP_ADD_FAILED:
+                case GROUP_UPDATE_FAILED:
+                case GROUP_REMOVE_FAILED:
+                    post(event);
+                    break;
 
-            default:
-                break;
+                default:
+                    break;
             }
         }
     }
@@ -330,16 +282,14 @@
         }
 
         @Override
-        public void groupOperationFailed(DeviceId deviceId,
-                                         GroupOperation operation) {
+        public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
             store.groupOperationFailed(deviceId, operation);
         }
 
         @Override
         public void pushGroupMetrics(DeviceId deviceId,
                                      Collection<Group> groupEntries) {
-            log.trace("Received group metrics from device {}",
-                    deviceId);
+            log.trace("Received group metrics from device {}", deviceId);
             checkValidity();
             store.pushGroupMetrics(deviceId, groupEntries);
         }
@@ -350,21 +300,17 @@
         @Override
         public void event(DeviceEvent event) {
             switch (event.type()) {
-            case DEVICE_REMOVED:
-            case DEVICE_AVAILABILITY_CHANGED:
-                if (!deviceService.isAvailable(event.subject().id())) {
-                    log.debug("GroupService DeviceListener: Received event {}."
-                            + "Device is no more available."
-                            + "Clearing device {} initial "
-                            + "AUDIT completed status",
-                            event.type(),
-                            event.subject().id());
-                    store.deviceInitialAuditCompleted(event.subject().id(), false);
-                }
-                break;
+                case DEVICE_REMOVED:
+                case DEVICE_AVAILABILITY_CHANGED:
+                    if (!deviceService.isAvailable(event.subject().id())) {
+                        log.debug("Device {} became un available; clearing initial audit status",
+                                  event.type(), event.subject().id());
+                        store.deviceInitialAuditCompleted(event.subject().id(), false);
+                    }
+                    break;
 
-            default:
-                break;
+                default:
+                    break;
             }
         }
     }
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index d36db84..73ac9c5 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -24,9 +24,8 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.core.Permission;
-import org.onosproject.event.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.incubator.net.config.NetworkConfigEvent;
 import org.onosproject.incubator.net.config.NetworkConfigListener;
 import org.onosproject.incubator.net.config.NetworkConfigService;
@@ -51,7 +50,6 @@
 import org.onosproject.net.host.HostStoreDelegate;
 import org.onosproject.net.host.PortAddresses;
 import org.onosproject.net.packet.PacketService;
-import org.onosproject.net.provider.AbstractProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
@@ -59,9 +57,8 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
-
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Provides basic implementation of the host SB &amp; NB APIs.
@@ -69,14 +66,12 @@
 @Component(immediate = true)
 @Service
 public class HostManager
-        extends AbstractProviderRegistry<HostProvider, HostProviderService>
+        extends AbstractListenerProviderRegistry<HostEvent, HostListener, HostProvider, HostProviderService>
         implements HostService, HostAdminService, HostProviderRegistry {
 
-    public static final String HOST_ID_NULL = "Host ID cannot be null";
     private final Logger log = getLogger(getClass());
 
-    private final ListenerRegistry<HostEvent, HostListener>
-            listenerRegistry = new ListenerRegistry<>();
+    public static final String HOST_ID_NULL = "Host ID cannot be null";
 
     private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
 
@@ -86,9 +81,6 @@
     protected HostStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -101,12 +93,12 @@
 
     @Activate
     public void activate() {
-        log.info("Started");
         store.setDelegate(delegate);
         eventDispatcher.addSink(HostEvent.class, listenerRegistry);
         networkConfigService.addListener(networkConfigListener);
-        monitor = new HostMonitor(deviceService,  packetService, this);
+        monitor = new HostMonitor(deviceService, packetService, this);
         monitor.start();
+        log.info("Started");
     }
 
     @Deactivate
@@ -120,28 +112,24 @@
     @Override
     protected HostProviderService createProviderService(HostProvider provider) {
         monitor.registerHostProvider(provider);
-
         return new InternalHostProviderService(provider);
     }
 
     @Override
     public int getHostCount() {
         checkPermission(Permission.HOST_READ);
-
         return store.getHostCount();
     }
 
     @Override
     public Iterable<Host> getHosts() {
         checkPermission(Permission.HOST_READ);
-
         return store.getHosts();
     }
 
     @Override
     public Host getHost(HostId hostId) {
         checkPermission(Permission.HOST_READ);
-
         checkNotNull(hostId, HOST_ID_NULL);
         return store.getHost(hostId);
     }
@@ -149,14 +137,12 @@
     @Override
     public Set<Host> getHostsByVlan(VlanId vlanId) {
         checkPermission(Permission.HOST_READ);
-
         return store.getHosts(vlanId);
     }
 
     @Override
     public Set<Host> getHostsByMac(MacAddress mac) {
         checkPermission(Permission.HOST_READ);
-
         checkNotNull(mac, "MAC address cannot be null");
         return store.getHosts(mac);
     }
@@ -164,7 +150,6 @@
     @Override
     public Set<Host> getHostsByIp(IpAddress ip) {
         checkPermission(Permission.HOST_READ);
-
         checkNotNull(ip, "IP address cannot be null");
         return store.getHosts(ip);
     }
@@ -172,7 +157,6 @@
     @Override
     public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
         checkPermission(Permission.HOST_READ);
-
         checkNotNull(connectPoint, "Connection point cannot be null");
         return store.getConnectedHosts(connectPoint);
     }
@@ -180,7 +164,6 @@
     @Override
     public Set<Host> getConnectedHosts(DeviceId deviceId) {
         checkPermission(Permission.HOST_READ);
-
         checkNotNull(deviceId, "Device ID cannot be null");
         return store.getConnectedHosts(deviceId);
     }
@@ -188,34 +171,18 @@
     @Override
     public void startMonitoringIp(IpAddress ip) {
         checkPermission(Permission.HOST_EVENT);
-
         monitor.addMonitoringFor(ip);
     }
 
     @Override
     public void stopMonitoringIp(IpAddress ip) {
         checkPermission(Permission.HOST_EVENT);
-
         monitor.stopMonitoring(ip);
     }
 
     @Override
     public void requestMac(IpAddress ip) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void addListener(HostListener listener) {
-        checkPermission(Permission.HOST_EVENT);
-
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(HostListener listener) {
-        checkPermission(Permission.HOST_EVENT);
-
-        listenerRegistry.removeListener(listener);
+        // FIXME!!!! Auto-generated method stub
     }
 
     @Override
@@ -245,14 +212,12 @@
     @Override
     public Set<PortAddresses> getAddressBindings() {
         checkPermission(Permission.HOST_READ);
-
         return store.getAddressBindings();
     }
 
     @Override
     public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
         checkPermission(Permission.HOST_READ);
-
         return store.getAddressBindingsForPort(connectPoint);
     }
 
@@ -326,13 +291,6 @@
         return DefaultAnnotations.union(originalAnnotations, newAnnotations);
     }
 
-    // Posts the specified event to the local event dispatcher.
-    private void post(HostEvent event) {
-        if (event != null) {
-            eventDispatcher.post(event);
-        }
-    }
-
     // Store delegate to re-post events emitted from the store.
     private class InternalStoreDelegate implements HostStoreDelegate {
         @Override
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index a6e6dec..ded3924 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -22,11 +22,10 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.IdGenerator;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.event.EventDeliveryService;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.FlowRuleOperations;
 import org.onosproject.net.flow.FlowRuleOperationsContext;
@@ -65,9 +64,8 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.intent.IntentState.*;
 import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
-import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
-
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * An implementation of intent service.
@@ -75,7 +73,9 @@
 @Component(immediate = true)
 @Service
 public class IntentManager
+        extends AbstractListenerManager<IntentEvent, IntentListener>
         implements IntentService, IntentExtensionService {
+
     private static final Logger log = getLogger(IntentManager.class);
 
     public static final String INTENT_NULL = "Intent cannot be null";
@@ -86,9 +86,6 @@
     private static final EnumSet<IntentState> RECOMPILE
             = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
 
-    private final ListenerRegistry<IntentEvent, IntentListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
 
@@ -99,12 +96,8 @@
     protected ObjectiveTrackerService trackerService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected FlowRuleService flowRuleService;
 
-
     private ExecutorService batchExecutor;
     private ExecutorService workerExecutor;
 
@@ -143,7 +136,6 @@
     @Override
     public void submit(Intent intent) {
         checkPermission(Permission.INTENT_WRITE);
-
         checkNotNull(intent, INTENT_NULL);
         IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
         store.addPending(data);
@@ -152,7 +144,6 @@
     @Override
     public void withdraw(Intent intent) {
         checkPermission(Permission.INTENT_WRITE);
-
         checkNotNull(intent, INTENT_NULL);
         IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
         store.addPending(data);
@@ -161,7 +152,6 @@
     @Override
     public void purge(Intent intent) {
         checkPermission(Permission.INTENT_WRITE);
-
         checkNotNull(intent, INTENT_NULL);
         IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
         store.addPending(data);
@@ -170,14 +160,12 @@
     @Override
     public Intent getIntent(Key key) {
         checkPermission(Permission.INTENT_READ);
-
         return store.getIntent(key);
     }
 
     @Override
     public Iterable<Intent> getIntents() {
         checkPermission(Permission.INTENT_READ);
-
         return store.getIntents();
     }
 
@@ -190,14 +178,12 @@
     @Override
     public long getIntentCount() {
         checkPermission(Permission.INTENT_READ);
-
         return store.getIntentCount();
     }
 
     @Override
     public IntentState getIntentState(Key intentKey) {
         checkPermission(Permission.INTENT_READ);
-
         checkNotNull(intentKey, INTENT_ID_NULL);
         return store.getIntentState(intentKey);
     }
@@ -205,7 +191,6 @@
     @Override
     public List<Intent> getInstallableIntents(Key intentKey) {
         checkPermission(Permission.INTENT_READ);
-
         checkNotNull(intentKey, INTENT_ID_NULL);
         return store.getInstallableIntents(intentKey);
     }
@@ -213,25 +198,10 @@
     @Override
     public boolean isLocal(Key intentKey) {
         checkPermission(Permission.INTENT_READ);
-
         return store.isMaster(intentKey);
     }
 
     @Override
-    public void addListener(IntentListener listener) {
-        checkPermission(Permission.INTENT_EVENT);
-
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(IntentListener listener) {
-        checkPermission(Permission.INTENT_EVENT);
-
-        listenerRegistry.removeListener(listener);
-    }
-
-    @Override
     public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
         compilerRegistry.registerCompiler(cls, compiler);
     }
@@ -257,7 +227,7 @@
     private class InternalStoreDelegate implements IntentStoreDelegate {
         @Override
         public void notify(IntentEvent event) {
-            eventDispatcher.post(event);
+            post(event);
         }
 
         @Override
diff --git a/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java b/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java
index e6fa300..b1316f6 100644
--- a/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java
+++ b/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java
@@ -24,9 +24,8 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.core.Permission;
-import org.onosproject.event.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.incubator.net.config.NetworkConfigEvent;
 import org.onosproject.incubator.net.config.NetworkConfigListener;
 import org.onosproject.incubator.net.config.NetworkConfigService;
@@ -53,7 +52,6 @@
 import org.onosproject.net.link.LinkService;
 import org.onosproject.net.link.LinkStore;
 import org.onosproject.net.link.LinkStoreDelegate;
-import org.onosproject.net.provider.AbstractProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
@@ -63,8 +61,8 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static org.onosproject.net.LinkKey.linkKey;
-import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 /**
@@ -73,7 +71,7 @@
 @Component(immediate = true)
 @Service
 public class LinkManager
-        extends AbstractProviderRegistry<LinkProvider, LinkProviderService>
+        extends AbstractListenerProviderRegistry<LinkEvent, LinkListener, LinkProvider, LinkProviderService>
         implements LinkService, LinkAdminService, LinkProviderRegistry {
 
     private static final String DEVICE_ID_NULL = "Device ID cannot be null";
@@ -82,9 +80,6 @@
 
     private final Logger log = getLogger(getClass());
 
-    protected final ListenerRegistry<LinkEvent, LinkListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     private final LinkStoreDelegate delegate = new InternalStoreDelegate();
 
     private final DeviceListener deviceListener = new InternalDeviceListener();
@@ -98,9 +93,6 @@
     protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigService networkConfigService;
 
     @Activate
@@ -124,21 +116,18 @@
     @Override
     public int getLinkCount() {
         checkPermission(Permission.LINK_READ);
-
         return store.getLinkCount();
     }
 
     @Override
     public Iterable<Link> getLinks() {
         checkPermission(Permission.LINK_READ);
-
         return store.getLinks();
     }
 
     @Override
     public Iterable<Link> getActiveLinks() {
         checkPermission(Permission.LINK_READ);
-
         return FluentIterable.from(getLinks())
                 .filter(new Predicate<Link>() {
 
@@ -152,7 +141,6 @@
     @Override
     public Set<Link> getDeviceLinks(DeviceId deviceId) {
         checkPermission(Permission.LINK_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return Sets.union(store.getDeviceEgressLinks(deviceId),
                           store.getDeviceIngressLinks(deviceId));
@@ -161,7 +149,6 @@
     @Override
     public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
         checkPermission(Permission.LINK_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getDeviceEgressLinks(deviceId);
     }
@@ -169,7 +156,6 @@
     @Override
     public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
         checkPermission(Permission.LINK_READ);
-
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getDeviceIngressLinks(deviceId);
     }
@@ -177,7 +163,6 @@
     @Override
     public Set<Link> getLinks(ConnectPoint connectPoint) {
         checkPermission(Permission.LINK_READ);
-
         checkNotNull(connectPoint, CONNECT_POINT_NULL);
         return Sets.union(store.getEgressLinks(connectPoint),
                           store.getIngressLinks(connectPoint));
@@ -186,7 +171,6 @@
     @Override
     public Set<Link> getEgressLinks(ConnectPoint connectPoint) {
         checkPermission(Permission.LINK_READ);
-
         checkNotNull(connectPoint, CONNECT_POINT_NULL);
         return store.getEgressLinks(connectPoint);
     }
@@ -194,7 +178,6 @@
     @Override
     public Set<Link> getIngressLinks(ConnectPoint connectPoint) {
         checkPermission(Permission.LINK_READ);
-
         checkNotNull(connectPoint, CONNECT_POINT_NULL);
         return store.getIngressLinks(connectPoint);
     }
@@ -202,7 +185,6 @@
     @Override
     public Link getLink(ConnectPoint src, ConnectPoint dst) {
         checkPermission(Permission.LINK_READ);
-
         checkNotNull(src, CONNECT_POINT_NULL);
         checkNotNull(dst, CONNECT_POINT_NULL);
         return store.getLink(src, dst);
@@ -228,18 +210,6 @@
         post(store.removeLink(src, dst));
     }
 
-    @Override
-    public void addListener(LinkListener listener) {
-        checkPermission(Permission.LINK_EVENT);
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(LinkListener listener) {
-        checkPermission(Permission.LINK_EVENT);
-        listenerRegistry.removeListener(listener);
-    }
-
     // Auxiliary interceptor for device remove events to prune links that
     // are associated with the removed device or its port.
     private class InternalDeviceListener implements DeviceListener {
@@ -376,13 +346,6 @@
         }
     }
 
-    // Posts the specified event to the local event dispatcher.
-    private void post(LinkEvent event) {
-        if (event != null) {
-            eventDispatcher.post(event);
-        }
-    }
-
     // Store delegate to re-post events emitted from the store.
     private class InternalStoreDelegate implements LinkStoreDelegate {
         @Override
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
index 9da155c..5762c0a 100644
--- a/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
@@ -22,11 +22,13 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.event.EventDeliveryService;
 import org.onosproject.net.Link;
 import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.resource.ResourceAllocation;
+import org.onosproject.net.resource.ResourceRequest;
+import org.onosproject.net.resource.ResourceType;
 import org.onosproject.net.resource.link.BandwidthResourceAllocation;
 import org.onosproject.net.resource.link.BandwidthResourceRequest;
 import org.onosproject.net.resource.link.DefaultLinkResourceAllocations;
@@ -43,9 +45,6 @@
 import org.onosproject.net.resource.link.MplsLabel;
 import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
 import org.onosproject.net.resource.link.MplsLabelResourceRequest;
-import org.onosproject.net.resource.ResourceAllocation;
-import org.onosproject.net.resource.ResourceRequest;
-import org.onosproject.net.resource.ResourceType;
 import org.slf4j.Logger;
 
 import java.util.Collections;
@@ -57,8 +56,8 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 /**
@@ -66,19 +65,15 @@
  */
 @Component(immediate = true)
 @Service
-public class LinkResourceManager implements LinkResourceService {
+public class LinkResourceManager
+        extends AbstractListenerManager<LinkResourceEvent, LinkResourceListener>
+        implements LinkResourceService {
 
     private final Logger log = getLogger(getClass());
 
-    protected final ListenerRegistry<LinkResourceEvent, LinkResourceListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private LinkResourceStore store;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
     @Activate
     public void activate() {
         eventDispatcher.addSink(LinkResourceEvent.class, listenerRegistry);
@@ -87,6 +82,7 @@
 
     @Deactivate
     public void deactivate() {
+        eventDispatcher.removeSink(LinkResourceEvent.class);
         log.info("Stopped");
     }
 
@@ -218,7 +214,6 @@
     @Override
     public void releaseResources(LinkResourceAllocations allocations) {
         checkPermission(Permission.LINK_WRITE);
-
         final LinkResourceEvent event = store.releaseResources(allocations);
         if (event != null) {
             post(event);
@@ -229,7 +224,6 @@
     public LinkResourceAllocations updateResources(LinkResourceRequest req,
             LinkResourceAllocations oldAllocations) {
         checkPermission(Permission.LINK_WRITE);
-
         releaseResources(oldAllocations);
          return requestResources(req);
     }
@@ -237,21 +231,18 @@
     @Override
     public Iterable<LinkResourceAllocations> getAllocations() {
         checkPermission(Permission.LINK_READ);
-
         return store.getAllocations();
     }
 
     @Override
     public Iterable<LinkResourceAllocations> getAllocations(Link link) {
         checkPermission(Permission.LINK_READ);
-
         return store.getAllocations(link);
     }
 
     @Override
     public LinkResourceAllocations getAllocations(IntentId intentId) {
         checkPermission(Permission.LINK_READ);
-
         return store.getAllocations(intentId);
     }
 
@@ -291,29 +282,6 @@
         return result;
     }
 
-    @Override
-    public void addListener(LinkResourceListener listener) {
-        checkPermission(Permission.LINK_EVENT);
-
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(LinkResourceListener listener) {
-        checkPermission(Permission.LINK_EVENT);
-
-        listenerRegistry.removeListener(listener);
-    }
-
-    /**
-     * Posts the specified event to the local event dispatcher.
-     */
-    private void post(LinkResourceEvent event) {
-        if (event != null) {
-            eventDispatcher.post(event);
-        }
-    }
-
     /**
      * Store delegate to re-post events emitted from the store.
      */
diff --git a/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java b/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
index 718d75d..0a0db62 100644
--- a/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
+++ b/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
@@ -21,15 +21,13 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.event.Event;
-import org.onosproject.event.EventDeliveryService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
 import org.onosproject.net.Path;
-import org.onosproject.net.provider.AbstractProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.onosproject.net.topology.ClusterId;
 import org.onosproject.net.topology.GraphDescription;
@@ -51,8 +49,8 @@
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Provides basic implementation of the topology SB &amp; NB APIs.
@@ -60,7 +58,8 @@
 @Component(immediate = true)
 @Service
 public class TopologyManager
-        extends AbstractProviderRegistry<TopologyProvider, TopologyProviderService>
+        extends AbstractListenerProviderRegistry<TopologyEvent, TopologyListener,
+                                                 TopologyProvider, TopologyProviderService>
         implements TopologyService, TopologyProviderRegistry {
 
     public static final String TOPOLOGY_NULL = "Topology cannot be null";
@@ -71,18 +70,11 @@
 
     private final Logger log = getLogger(getClass());
 
-    private final ListenerRegistry<TopologyEvent, TopologyListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     private TopologyStoreDelegate delegate = new InternalStoreDelegate();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected TopologyStore store;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-
     @Activate
     public void activate() {
         store.setDelegate(delegate);
@@ -100,14 +92,12 @@
     @Override
     public Topology currentTopology() {
         checkPermission(Permission.TOPOLOGY_READ);
-
         return store.currentTopology();
     }
 
     @Override
     public boolean isLatest(Topology topology) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         return store.isLatest(topology);
     }
@@ -115,7 +105,6 @@
     @Override
     public Set<TopologyCluster> getClusters(Topology topology) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         return store.getClusters(topology);
     }
@@ -123,7 +112,6 @@
     @Override
     public TopologyCluster getCluster(Topology topology, ClusterId clusterId) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         checkNotNull(topology, CLUSTER_ID_NULL);
         return store.getCluster(topology, clusterId);
@@ -132,7 +120,6 @@
     @Override
     public Set<DeviceId> getClusterDevices(Topology topology, TopologyCluster cluster) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         checkNotNull(topology, CLUSTER_NULL);
         return store.getClusterDevices(topology, cluster);
@@ -141,7 +128,6 @@
     @Override
     public Set<Link> getClusterLinks(Topology topology, TopologyCluster cluster) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         checkNotNull(topology, CLUSTER_NULL);
         return store.getClusterLinks(topology, cluster);
@@ -150,7 +136,6 @@
     @Override
     public TopologyGraph getGraph(Topology topology) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         return store.getGraph(topology);
     }
@@ -158,7 +143,6 @@
     @Override
     public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         checkNotNull(src, DEVICE_ID_NULL);
         checkNotNull(dst, DEVICE_ID_NULL);
@@ -179,7 +163,6 @@
     @Override
     public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         checkNotNull(connectPoint, CONNECTION_POINT_NULL);
         return store.isInfrastructure(topology, connectPoint);
@@ -188,26 +171,11 @@
     @Override
     public boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint) {
         checkPermission(Permission.TOPOLOGY_READ);
-
         checkNotNull(topology, TOPOLOGY_NULL);
         checkNotNull(connectPoint, CONNECTION_POINT_NULL);
         return store.isBroadcastPoint(topology, connectPoint);
     }
 
-    @Override
-    public void addListener(TopologyListener listener) {
-        checkPermission(Permission.TOPOLOGY_EVENT);
-
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(TopologyListener listener) {
-        checkPermission(Permission.TOPOLOGY_EVENT);
-
-        listenerRegistry.removeListener(listener);
-    }
-
     // Personalized host provider service issued to the supplied provider.
     @Override
     protected TopologyProviderService createProviderService(TopologyProvider provider) {
@@ -231,7 +199,7 @@
                                                        topoDescription, reasons);
             if (event != null) {
                 log.info("Topology {} changed", event.subject());
-                eventDispatcher.post(event);
+                post(event);
             }
         }
     }
@@ -240,7 +208,7 @@
     private class InternalStoreDelegate implements TopologyStoreDelegate {
         @Override
         public void notify(TopologyEvent event) {
-            eventDispatcher.post(event);
+            post(event);
         }
     }
 }