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/api/src/main/java/org/onosproject/app/ApplicationService.java b/core/api/src/main/java/org/onosproject/app/ApplicationService.java
index 1aaf092..bb55da9 100644
--- a/core/api/src/main/java/org/onosproject/app/ApplicationService.java
+++ b/core/api/src/main/java/org/onosproject/app/ApplicationService.java
@@ -18,13 +18,15 @@
 import org.onosproject.core.Application;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.Permission;
+import org.onosproject.event.ListenerService;
 
 import java.util.Set;
 
 /**
  * Service for inspecting inventory of network control applications.
  */
-public interface ApplicationService {
+public interface ApplicationService
+        extends ListenerService<ApplicationEvent, ApplicationListener> {
 
     /**
      * Returns the set of all installed applications.
@@ -65,18 +67,4 @@
      */
     Set<Permission> getPermissions(ApplicationId appId);
 
-    /**
-     * Adds the given listener for application lifecycle events.
-     *
-     * @param listener listener to be added
-     */
-    void addListener(ApplicationListener listener);
-
-    /**
-     * Removes the specified listener for application lifecycle events.
-     *
-     * @param listener listener to be removed
-     */
-    void removeListener(ApplicationListener listener);
-
 }
diff --git a/core/api/src/main/java/org/onosproject/cluster/ClusterService.java b/core/api/src/main/java/org/onosproject/cluster/ClusterService.java
index e708588..015a648 100644
--- a/core/api/src/main/java/org/onosproject/cluster/ClusterService.java
+++ b/core/api/src/main/java/org/onosproject/cluster/ClusterService.java
@@ -18,12 +18,14 @@
 import java.util.Set;
 
 import org.joda.time.DateTime;
+import org.onosproject.event.ListenerService;
 
 /**
  * Service for obtaining information about the individual nodes within
  * the controller cluster.
  */
-public interface ClusterService {
+public interface ClusterService
+    extends ListenerService<ClusterEvent, ClusterEventListener> {
 
     /**
      * Returns the local controller node.
@@ -63,18 +65,4 @@
      */
     DateTime getLastUpdated(NodeId nodeId);
 
-    /**
-     * Adds the specified cluster event listener.
-     *
-     * @param listener the cluster listener
-     */
-    void addListener(ClusterEventListener listener);
-
-    /**
-     * Removes the specified cluster event listener.
-     *
-     * @param listener the cluster listener
-     */
-    void removeListener(ClusterEventListener listener);
-
 }
diff --git a/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java b/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java
index 9130f4f..7d1f607 100644
--- a/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java
+++ b/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.cluster;
 
+import org.onosproject.event.ListenerService;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -27,7 +29,8 @@
  * Listeners can be added to receive notifications asynchronously for various
  * leadership contests.
  */
-public interface LeadershipService {
+public interface LeadershipService
+    extends ListenerService<LeadershipEvent, LeadershipEventListener> {
 
     /**
      * Returns the current leader for the topic.
@@ -118,17 +121,4 @@
      */
     List<NodeId> getCandidates(String path);
 
-    /**
-     * Registers a event listener to be notified of leadership events.
-     *
-     * @param listener listener that will asynchronously notified of leadership events.
-     */
-    void addListener(LeadershipEventListener listener);
-
-    /**
-     * Unregisters a event listener for leadership events.
-     *
-     * @param listener listener to be removed.
-     */
-    void removeListener(LeadershipEventListener listener);
 }
diff --git a/core/api/src/main/java/org/onosproject/event/AbstractListenerManager.java b/core/api/src/main/java/org/onosproject/event/AbstractListenerManager.java
new file mode 100644
index 0000000..cbe7421
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/event/AbstractListenerManager.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.event;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+
+/**
+ * Basis for components which need to export listener mechanism.
+ */
+@Component(componentAbstract = true)
+public abstract class AbstractListenerManager<E extends Event, L extends EventListener<E>>
+    implements ListenerService<E, L> {
+
+    protected final ListenerRegistry<E, L> listenerRegistry = new ListenerRegistry<>();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EventDeliveryService eventDispatcher;
+
+    @Override
+    public void addListener(L listener) {
+        listenerRegistry.addListener(listener);
+    }
+
+    @Override
+    public void removeListener(L listener) {
+        listenerRegistry.removeListener(listener);
+    }
+
+
+    /**
+     * Safely posts the specified event to the local event dispatcher.
+     * If there is no event dispatcher or if the event is null, this method
+     * is a noop.
+     *
+     * @param event event to be posted; may be null
+     */
+    protected void post(E event) {
+        if (event != null && eventDispatcher != null) {
+            eventDispatcher.post(event);
+        }
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java b/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java
index e6af201..ef02af06 100644
--- a/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java
+++ b/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java
@@ -28,7 +28,7 @@
  * listeners and dispatching events to them as part of event sink processing.
  */
 public class ListenerRegistry<E extends Event, L extends EventListener<E>>
-        implements EventSink<E> {
+        implements ListenerService<E, L>, EventSink<E> {
 
     private static final long LIMIT = 1_800; // ms
 
@@ -42,22 +42,13 @@
      */
     protected final Set<L> listeners = new CopyOnWriteArraySet<>();
 
-
-    /**
-     * Adds the specified listener.
-     *
-     * @param listener listener to be added
-     */
+    @Override
     public void addListener(L listener) {
         checkNotNull(listener, "Listener cannot be null");
         listeners.add(listener);
     }
 
-    /**
-     * Removes the specified listener.
-     *
-     * @param listener listener to be removed
-     */
+    @Override
     public void removeListener(L listener) {
         checkNotNull(listener, "Listener cannot be null");
         if (!listeners.remove(listener)) {
diff --git a/core/api/src/main/java/org/onosproject/event/ListenerService.java b/core/api/src/main/java/org/onosproject/event/ListenerService.java
new file mode 100644
index 0000000..a4a3631
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/event/ListenerService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.event;
+
+/**
+ * Abstraction of a service capable of asynchronously notifying listeners.
+ */
+public interface ListenerService<E extends Event, L extends EventListener<E>> {
+
+    /**
+     * Adds the specified listener.
+     *
+     * @param listener listener to be added
+     */
+    void addListener(L listener);
+
+    /**
+     * Removes the specified listener.
+     *
+     * @param listener listener to be removed
+     */
+    void removeListener(L listener);
+
+
+}
diff --git a/core/api/src/main/java/org/onosproject/mastership/MastershipService.java b/core/api/src/main/java/org/onosproject/mastership/MastershipService.java
index 79eef94..75d0eac 100644
--- a/core/api/src/main/java/org/onosproject/mastership/MastershipService.java
+++ b/core/api/src/main/java/org/onosproject/mastership/MastershipService.java
@@ -20,6 +20,7 @@
 
 import org.onosproject.cluster.NodeId;
 import org.onosproject.cluster.RoleInfo;
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 
@@ -29,7 +30,8 @@
  * determining mastership, but is not responsible for actually applying it
  * to the devices; this falls on the device service.
  */
-public interface MastershipService {
+public interface MastershipService
+    extends ListenerService<MastershipEvent, MastershipListener> {
 
     /**
      * Returns the role of the local node for the specified device, without
@@ -84,18 +86,4 @@
      */
     Set<DeviceId> getDevicesOf(NodeId nodeId);
 
-    /**
-     * Adds the specified mastership change listener.
-     *
-     * @param listener the mastership listener
-     */
-    void addListener(MastershipListener listener);
-
-    /**
-     * Removes the specified mastership change listener.
-     *
-     * @param listener the mastership listener
-     */
-    void removeListener(MastershipListener listener);
-
 }
diff --git a/core/api/src/main/java/org/onosproject/net/device/DeviceService.java b/core/api/src/main/java/org/onosproject/net/device/DeviceService.java
index ab6dba5..c59454d 100644
--- a/core/api/src/main/java/org/onosproject/net/device/DeviceService.java
+++ b/core/api/src/main/java/org/onosproject/net/device/DeviceService.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.device;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
@@ -26,7 +27,8 @@
 /**
  * Service for interacting with the inventory of infrastructure devices.
  */
-public interface DeviceService {
+public interface DeviceService
+    extends ListenerService<DeviceEvent, DeviceListener> {
 
     /**
      * Returns the number of infrastructure devices known to the system.
@@ -119,18 +121,4 @@
      */
     boolean isAvailable(DeviceId deviceId);
 
-    /**
-     * Adds the specified device listener.
-     *
-     * @param listener device listener
-     */
-    void addListener(DeviceListener listener);
-
-    /**
-     * Removes the specified device listener.
-     *
-     * @param listener device listener
-     */
-    void removeListener(DeviceListener listener);
-
 }
diff --git a/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java b/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java
index c91018e..89a2c17 100644
--- a/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java
+++ b/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.edge;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -27,7 +28,8 @@
  * is considered an edge port if it is an active port and does not have an
  * infrastructure link associated with it.
  */
-public interface EdgePortService {
+public interface EdgePortService
+        extends ListenerService<EdgePortEvent, EdgePortListener> {
 
     /**
      * Indicates whether or not the specified connection point is an edge point.
@@ -70,18 +72,4 @@
     void emitPacket(DeviceId deviceId, ByteBuffer data,
                     Optional<TrafficTreatment> treatment);
 
-    /**
-     * Adds a listener for edge port events.
-     *
-     * @param listener listener to be added
-     */
-    void addListener(EdgePortListener listener);
-
-    /**
-     * Removes the listener for edge port events.
-     *
-     * @param listener listener to be removed
-     */
-    void removeListener(EdgePortListener listener);
-
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
index 43d0f5d..e297115 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.flow;
 
 import org.onosproject.core.ApplicationId;
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.DeviceId;
 
 /**
@@ -25,7 +26,8 @@
  * of the flow rules lies with the controller and the devices hold only the
  * 'cached' copy.
  */
-public interface FlowRuleService {
+public interface FlowRuleService
+    extends ListenerService<FlowRuleEvent, FlowRuleListener> {
 
     /**
      * The topic used for obtaining globally unique ids.
@@ -102,17 +104,4 @@
      */
     void apply(FlowRuleOperations ops);
 
-    /**
-     * Adds the specified flow rule listener.
-     *
-     * @param listener flow rule listener
-     */
-    void addListener(FlowRuleListener listener);
-
-    /**
-     * Removes the specified flow rule listener.
-     *
-     * @param listener flow rule listener
-     */
-    void removeListener(FlowRuleListener listener);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/group/GroupService.java b/core/api/src/main/java/org/onosproject/net/group/GroupService.java
index cdd56c7..4163248 100644
--- a/core/api/src/main/java/org/onosproject/net/group/GroupService.java
+++ b/core/api/src/main/java/org/onosproject/net/group/GroupService.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.group;
 
 import org.onosproject.core.ApplicationId;
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.DeviceId;
 
 /**
@@ -32,7 +33,8 @@
  * where the master copy of the groups lies with the controller and
  * the devices hold only the 'cached' copy.
  */
-public interface GroupService {
+public interface GroupService
+    extends ListenerService<GroupEvent, GroupListener> {
 
     /**
      * Creates a group in the specified device with the provided buckets.
@@ -134,17 +136,4 @@
      */
     Iterable<Group> getGroups(DeviceId deviceId);
 
-    /**
-     * Adds the specified group listener.
-     *
-     * @param listener group listener
-     */
-    void addListener(GroupListener listener);
-
-    /**
-     * Removes the specified group listener.
-     *
-     * @param listener group listener
-     */
-    void removeListener(GroupListener listener);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/host/HostService.java b/core/api/src/main/java/org/onosproject/net/host/HostService.java
index 6fa52ce..a2a8291 100644
--- a/core/api/src/main/java/org/onosproject/net/host/HostService.java
+++ b/core/api/src/main/java/org/onosproject/net/host/HostService.java
@@ -17,6 +17,7 @@
 
 import java.util.Set;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
@@ -28,7 +29,8 @@
 /**
  * Service for interacting with the inventory of end-station hosts.
  */
-public interface HostService {
+public interface HostService
+    extends ListenerService<HostEvent, HostListener> {
 
     /**
      * Returns the number of end-station hosts known to the system.
@@ -137,18 +139,4 @@
      */
     Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint);
 
-    /**
-     * Adds the specified host listener.
-     *
-     * @param listener host listener
-     */
-    void addListener(HostListener listener);
-
-    /**
-     * Removes the specified host listener.
-     *
-     * @param listener host listener
-     */
-    void removeListener(HostListener listener);
-
 }
diff --git a/core/api/src/main/java/org/onosproject/net/intent/IntentService.java b/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
index ccc97d8..8533ceb 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
@@ -17,6 +17,7 @@
 
 
 import com.google.common.annotations.Beta;
+import org.onosproject.event.ListenerService;
 
 import java.util.List;
 
@@ -24,7 +25,9 @@
  * Service for application submitting or withdrawing their intents.
  */
 @Beta
-public interface IntentService {
+public interface IntentService
+    extends ListenerService<IntentEvent, IntentListener> {
+
     /**
      * Submits an intent into the system.
      * <p>
@@ -117,17 +120,4 @@
      */
     Iterable<Intent> getPending();
 
-    /**
-     * Adds the specified listener for intent events.
-     *
-     * @param listener listener to be added
-     */
-    void addListener(IntentListener listener);
-
-    /**
-     * Removes the specified listener for intent events.
-     *
-     * @param listener listener to be removed
-     */
-    void removeListener(IntentListener listener);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java b/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java
index 7c9d547..02cccca 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java
@@ -17,12 +17,14 @@
 
 import com.google.common.annotations.Beta;
 import org.onosproject.cluster.NodeId;
+import org.onosproject.event.ListenerService;
 
 /**
  * Service for interacting with the partition-to-instance assignments.
  */
 @Beta
-public interface PartitionService {
+public interface PartitionService
+    extends ListenerService<PartitionEvent, PartitionEventListener> {
 
     /**
      * Returns whether the given intent key is in a partition owned by this
@@ -43,17 +45,4 @@
 
     // TODO add API for rebalancing partitions
 
-    /**
-     * Registers a event listener to be notified of partition events.
-     *
-     * @param listener listener that will asynchronously notified of partition events.
-     */
-    void addListener(PartitionEventListener listener);
-
-    /**
-     * Unregisters a event listener for partition events.
-     *
-     * @param listener listener to be removed.
-     */
-    void removeListener(PartitionEventListener listener);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/link/LinkService.java b/core/api/src/main/java/org/onosproject/net/link/LinkService.java
index 5cae77b..c27e311 100644
--- a/core/api/src/main/java/org/onosproject/net/link/LinkService.java
+++ b/core/api/src/main/java/org/onosproject/net/link/LinkService.java
@@ -17,6 +17,7 @@
 
 import java.util.Set;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
@@ -24,7 +25,8 @@
 /**
  * Service for interacting with the inventory of infrastructure links.
  */
-public interface LinkService {
+public interface LinkService
+    extends ListenerService<LinkEvent, LinkListener> {
 
     /**
      * Returns the count of all known infrastructure links.
@@ -111,18 +113,4 @@
      */
     Link getLink(ConnectPoint src, ConnectPoint dst);
 
-    /**
-     * Adds the specified link listener.
-     *
-     * @param listener link listener
-     */
-    void addListener(LinkListener listener);
-
-    /**
-     * Removes the specified link listener.
-     *
-     * @param listener link listener
-     */
-    void removeListener(LinkListener listener);
-
 }
diff --git a/core/api/src/main/java/org/onosproject/net/provider/AbstractListenerProviderRegistry.java b/core/api/src/main/java/org/onosproject/net/provider/AbstractListenerProviderRegistry.java
new file mode 100644
index 0000000..ff67c6d
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/provider/AbstractListenerProviderRegistry.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.provider;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.event.Event;
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.event.EventListener;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.event.ListenerService;
+
+/**
+ * Basis for components which need to export listener mechanism.
+ */
+@Component(componentAbstract = true)
+public abstract class AbstractListenerProviderRegistry<E extends Event, L extends EventListener<E>,
+                                                       P extends Provider, S extends ProviderService<P>>
+        extends AbstractProviderRegistry<P, S> implements ListenerService<E, L> {
+
+    // If only Java supported mixins...
+
+    protected final ListenerRegistry<E, L> listenerRegistry = new ListenerRegistry<>();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EventDeliveryService eventDispatcher;
+
+    @Override
+    public void addListener(L listener) {
+        listenerRegistry.addListener(listener);
+    }
+
+    @Override
+    public void removeListener(L listener) {
+        listenerRegistry.removeListener(listener);
+    }
+
+
+    /**
+     * Safely posts the specified event to the local event dispatcher.
+     * If there is no event dispatcher or if the event is null, this method
+     * is a noop.
+     *
+     * @param event event to be posted; may be null
+     */
+    protected void post(E event) {
+        if (event != null && eventDispatcher != null) {
+            eventDispatcher.post(event);
+        }
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java b/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java
index 69bdf4f..6dc04df 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.resource.link;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.Link;
 import org.onosproject.net.intent.IntentId;
 import org.onosproject.net.resource.ResourceRequest;
@@ -22,7 +23,8 @@
 /**
  * Service for providing link resource allocation.
  */
-public interface LinkResourceService {
+public interface LinkResourceService
+    extends ListenerService<LinkResourceEvent, LinkResourceListener> {
 
     /**
      * Requests resources.
@@ -88,20 +90,6 @@
      * @return available resources for the target link
      */
     Iterable<ResourceRequest> getAvailableResources(Link link,
-                                          LinkResourceAllocations allocations);
-
-    /**
-     * Adds a listener for resource related events.
-     *
-     * @param listener listener to add
-     */
-    void addListener(LinkResourceListener listener);
-
-    /**
-     * Removes a listener for resource related events.
-     *
-     * @param listener listener to remove.
-     */
-    void removeListener(LinkResourceListener listener);
+                                                    LinkResourceAllocations allocations);
 
 }
diff --git a/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java b/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
index b17deb3..41eac2c 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.topology;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
@@ -25,7 +26,8 @@
 /**
  * Service for providing network topology information.
  */
-public interface TopologyService {
+public interface TopologyService
+    extends ListenerService<TopologyEvent, TopologyListener> {
 
     /**
      * Returns the current topology descriptor.
@@ -130,18 +132,4 @@
      */
     boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint);
 
-    /**
-     * Adds the specified topology listener.
-     *
-     * @param listener topology listener
-     */
-    void addListener(TopologyListener listener);
-
-    /**
-     * Removes the specified topology listener.
-     *
-     * @param listener topology listener
-     */
-    void removeListener(TopologyListener listener);
-
 }
diff --git a/core/api/src/test/java/org/onosproject/net/NetTestTools.java b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
index eccb743..18c5679 100644
--- a/core/api/src/test/java/org/onosproject/net/NetTestTools.java
+++ b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
@@ -15,22 +15,24 @@
  */
 package org.onosproject.net;
 
-import org.onosproject.TestApplicationId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.provider.ProviderId;
 import org.onlab.packet.ChassisId;
 import org.onlab.packet.IpAddress;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.net.provider.ProviderId;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
+import static org.onlab.packet.MacAddress.valueOf;
+import static org.onlab.packet.VlanId.vlanId;
 import static org.onosproject.net.DeviceId.deviceId;
 import static org.onosproject.net.HostId.hostId;
 import static org.onosproject.net.PortNumber.portNumber;
-import static org.onlab.packet.MacAddress.valueOf;
-import static org.onlab.packet.VlanId.vlanId;
 
 /**
  * Miscellaneous tools for testing core related to the network model.
@@ -98,8 +100,8 @@
      * Verifies that Annotations created by merging {@code annotations} is
      * equal to actual Annotations.
      *
-     * @param actual Annotations to check
-     * @param annotations
+     * @param actual      annotations to check
+     * @param annotations expected annotations
      */
     public static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
         DefaultAnnotations expected = DefaultAnnotations.builder().build();
@@ -112,4 +114,25 @@
         }
     }
 
+    /**
+     * Injects the given event delivery service into the specified manager
+     * component.
+     *
+     * @param manager manager component
+     * @param svc     service reference to be injected
+     */
+    public static void injectEventDispatcher(Object manager, EventDeliveryService svc) {
+        Class mc = manager.getClass();
+        for (Field f : mc.getSuperclass().getDeclaredFields()) {
+            if (f.getType().equals(EventDeliveryService.class)) {
+                try {
+                    f.setAccessible(true);
+                    f.set(manager, svc);
+                } catch (IllegalAccessException e) {
+                    throw new IllegalArgumentException("Unable to inject reference", e);
+                }
+            }
+        }
+    }
+
 }
diff --git a/core/common/pom.xml b/core/common/pom.xml
index 99ecbd0..71eadbc 100644
--- a/core/common/pom.xml
+++ b/core/common/pom.xml
@@ -49,25 +49,6 @@
             <artifactId>easymock</artifactId>
             <scope>test</scope>
         </dependency>
-
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-        </dependency>
     </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-
 </project>
diff --git a/core/common/src/main/java/org/onosproject/common/package-info.java b/core/common/src/main/java/org/onosproject/common/package-info.java
new file mode 100644
index 0000000..8cd9b8c
--- /dev/null
+++ b/core/common/src/main/java/org/onosproject/common/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Miscellaneous common facilities used for construction of various core and
+ * app subsystems.
+ */
+package org.onosproject.common;
\ No newline at end of file
diff --git a/core/net/pom.xml b/core/net/pom.xml
index e262d4a..dfd5f21 100644
--- a/core/net/pom.xml
+++ b/core/net/pom.xml
@@ -78,11 +78,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-        </dependency>
-
-        <dependency>
             <groupId>org.apache.karaf.features</groupId>
             <artifactId>org.apache.karaf.features.core</artifactId>
         </dependency>
@@ -93,13 +88,4 @@
         </dependency>
     </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-
 </project>
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);
         }
     }
 }
diff --git a/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java b/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
index 4b4bbee..1ce31ac 100644
--- a/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
@@ -41,6 +41,7 @@
 import static org.onosproject.app.ApplicationState.ACTIVE;
 import static org.onosproject.app.ApplicationState.INSTALLED;
 import static org.onosproject.app.DefaultApplicationDescriptionTest.*;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 
 /**
  * Test of the application manager implementation.
@@ -54,7 +55,7 @@
 
     @Before
     public void setUp() {
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         mgr.featuresService = new TestFeaturesService();
         mgr.store = new TestStore();
         mgr.activate();
diff --git a/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java b/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java
index 477c7c4..bf1a1ff 100644
--- a/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java
@@ -41,6 +41,7 @@
 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.net.NetTestTools.injectEventDispatcher;
 
 /**
  * Test codifying the mastership service contracts.
@@ -60,7 +61,7 @@
     public void setUp() {
         mgr = new MastershipManager();
         service = mgr;
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         mgr.clusterService = new TestClusterService();
         mgr.store = new TestSimpleMastershipStore(mgr.clusterService);
         mgr.activate();
@@ -70,7 +71,7 @@
     public void tearDown() {
         mgr.deactivate();
         mgr.clusterService = null;
-        mgr.eventDispatcher = null;
+        injectEventDispatcher(mgr, null);
         mgr.store = null;
     }
 
diff --git a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
index 7597e7c..77d3f1d 100644
--- a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
@@ -15,12 +15,7 @@
  */
 package org.onosproject.net.device.impl;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-
+import com.google.common.collect.Sets;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -30,8 +25,8 @@
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.DefaultControllerNode;
 import org.onosproject.cluster.NodeId;
-import org.onosproject.event.Event;
 import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.event.Event;
 import org.onosproject.incubator.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.mastership.MastershipServiceAdapter;
 import org.onosproject.mastership.MastershipTerm;
@@ -57,21 +52,17 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.trivial.SimpleDeviceStore;
 
-import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 import static org.onosproject.net.Device.Type.SWITCH;
 import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
-import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
-import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
-import static org.onosproject.net.device.DeviceEvent.Type.PORT_ADDED;
-import static org.onosproject.net.device.DeviceEvent.Type.PORT_REMOVED;
-import static org.onosproject.net.device.DeviceEvent.Type.PORT_UPDATED;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+import static org.onosproject.net.device.DeviceEvent.Type.*;
 
 /**
  * Test codifying the device service & device provider service contracts.
@@ -110,7 +101,7 @@
         admin = mgr;
         registry = mgr;
         mgr.store = new SimpleDeviceStore();
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         TestMastershipManager mastershipManager = new TestMastershipManager();
         mgr.mastershipService = mastershipManager;
         mgr.termService = mastershipManager;
diff --git a/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java b/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java
index 1c6349e..319412f 100644
--- a/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java
@@ -52,6 +52,7 @@
 import java.util.Set;
 
 import static org.junit.Assert.*;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 import static org.onosproject.net.device.DeviceEvent.Type.*;
 import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_ADDED;
 import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_REMOVED;
@@ -78,7 +79,7 @@
     @Before
     public void setUp() {
         mgr = new EdgeManager();
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         testTopologyManager = new TestTopologyManager(infrastructurePorts);
         mgr.topologyService = testTopologyManager;
         mgr.deviceService = new TestDeviceManager(devices);
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index db434c7..afd9a90 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -80,6 +80,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADDED;
 import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
 import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
@@ -112,7 +113,7 @@
     public void setUp() {
         mgr = new FlowRuleManager();
         mgr.store = new SimpleFlowRuleStore();
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         mgr.deviceService = new TestDeviceService();
         mgr.coreService = new TestCoreService();
         mgr.operationsService = MoreExecutors.newDirectExecutorService();
@@ -137,7 +138,7 @@
                     registry.getProviders().contains(provider.id()));
         service.removeListener(listener);
         mgr.deactivate();
-        mgr.eventDispatcher = null;
+        injectEventDispatcher(mgr, null);
         mgr.deviceService = null;
     }
 
diff --git a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
index 327296e..d2079a8 100644
--- a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -89,7 +90,7 @@
         groupService = mgr;
         mgr.deviceService = new DeviceManager();
         mgr.store = new SimpleGroupStore();
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         providerRegistry = mgr;
 
         mgr.activate();
@@ -110,7 +111,7 @@
                     providerRegistry.getProviders().contains(provider.id()));
         mgr.removeListener(listener);
         mgr.deactivate();
-        mgr.eventDispatcher = null;
+        injectEventDispatcher(mgr, null);
     }
 
     /**
diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
index 9e113f3..9f10304 100644
--- a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
 import static org.onosproject.net.host.HostEvent.Type.HOST_MOVED;
 import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
@@ -122,7 +123,7 @@
     public void setUp() {
         mgr = new HostManager();
         mgr.store = new SimpleHostStore();
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         registry = mgr;
         mgr.networkConfigService = new TestNetworkConfigService();
         mgr.activate();
@@ -143,7 +144,7 @@
 
         mgr.removeListener(listener);
         mgr.deactivate();
-        mgr.eventDispatcher = null;
+        injectEventDispatcher(mgr, null);
     }
 
     private void detect(HostId hid, MacAddress mac, VlanId vlan,
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
index ae6b0d2..4bf32f4 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -63,6 +63,7 @@
 import static org.junit.Assert.*;
 import static org.onlab.junit.TestTools.assertAfter;
 import static org.onlab.util.Tools.delay;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 import static org.onosproject.net.intent.IntentState.*;
 import static org.onosproject.net.intent.IntentTestsMocks.MockFlowRule;
 import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
@@ -226,7 +227,7 @@
         manager = new IntentManager();
         flowRuleService = new MockFlowRuleService();
         manager.store = new SimpleIntentStore();
-        manager.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(manager, new TestEventDispatcher());
         manager.trackerService = new TestIntentTracker();
         manager.flowRuleService = flowRuleService;
         manager.coreService = new TestCoreManager();
diff --git a/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java b/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
index 391b2fd..2242044 100644
--- a/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
@@ -53,6 +53,7 @@
 import static org.onosproject.net.DeviceId.deviceId;
 import static org.onosproject.net.Link.Type.DIRECT;
 import static org.onosproject.net.Link.Type.INDIRECT;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 import static org.onosproject.net.link.LinkEvent.Type.*;
 
 /**
@@ -95,7 +96,7 @@
         admin = mgr;
         registry = mgr;
         mgr.store = new SimpleLinkStore();
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         mgr.deviceService = devmgr;
         mgr.networkConfigService = new TestNetworkConfigService();
         mgr.activate();
diff --git a/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java b/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
index a54d075..022df23 100644
--- a/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
+++ b/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
@@ -100,8 +100,8 @@
         assertEquals(1, topologyChangedCounts.awaitAdvanceInterruptibly(0, 1, TimeUnit.SECONDS));
         validateSubmission();
 
-        deviceService.post(new DeviceEvent(DEVICE_ADDED, device("z"), null));
-        linkService.post(new LinkEvent(LINK_ADDED, link("z", 1, "a", 4)));
+        deviceService.postEvent(new DeviceEvent(DEVICE_ADDED, device("z"), null));
+        linkService.postEvent(new LinkEvent(LINK_ADDED, link("z", 1, "a", 4)));
         assertThat(topologyChangedCounts.awaitAdvanceInterruptibly(1, 1, TimeUnit.SECONDS),
                 is(greaterThanOrEqualTo(2)));
         // Note: posting event, to trigger topologyChanged call,
@@ -162,7 +162,7 @@
             return getDevices();
         }
 
-        void post(DeviceEvent event) {
+        void postEvent(DeviceEvent event) {
             eventDispatcher.post(event);
         }
     }
@@ -187,7 +187,7 @@
             return getLinks();
         }
 
-        void post(LinkEvent event) {
+        void postEvent(LinkEvent event) {
             eventDispatcher.post(event);
         }
     }
diff --git a/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java b/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
index 99b8fbd..f3cd28d 100644
--- a/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
@@ -73,7 +73,7 @@
         registry = mgr;
 
         mgr.store = new SimpleTopologyStore();
-        mgr.eventDispatcher = new TestEventDispatcher();
+        injectEventDispatcher(mgr, new TestEventDispatcher());
         mgr.activate();
 
         service.addListener(listener);
diff --git a/core/pom.xml b/core/pom.xml
index 84dca6e..0f7dd8c 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -57,6 +57,10 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
@@ -70,6 +74,11 @@
                 <groupId>org.onosproject</groupId>
                 <artifactId>onos-maven-plugin</artifactId>
             </plugin>
+
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/core/security/impl/pom.xml b/core/security/impl/pom.xml
index 6cbb5e7..33791c9 100644
--- a/core/security/impl/pom.xml
+++ b/core/security/impl/pom.xml
@@ -37,14 +37,6 @@
             <artifactId>org.osgi.core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onos-api</artifactId>
         </dependency>
@@ -54,14 +46,4 @@
         </dependency>
     </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-
-
 </project>
\ No newline at end of file
diff --git a/core/store/pom.xml b/core/store/pom.xml
index 5cb5fd6..59d6664 100644
--- a/core/store/pom.xml
+++ b/core/store/pom.xml
@@ -49,20 +49,6 @@
             <classifier>tests</classifier>
             <scope>test</scope>
         </dependency>
-
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-        </dependency>
     </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-
 </project>
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/config/NetworkConfigService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/config/NetworkConfigService.java
index 455ed68..5a89ccb 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/config/NetworkConfigService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/config/NetworkConfigService.java
@@ -17,6 +17,7 @@
 
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.annotations.Beta;
+import org.onosproject.event.ListenerService;
 
 import java.util.Set;
 
@@ -26,7 +27,8 @@
  * should act on or configure the network.
  */
 @Beta
-public interface NetworkConfigService {
+public interface NetworkConfigService
+    extends ListenerService<NetworkConfigEvent, NetworkConfigListener> {
 
     /**
      * Returns the set of subject classes for which configuration may be
@@ -140,17 +142,4 @@
      */
     <S, C extends Config<S>> void removeConfig(S subject, Class<C> configClass);
 
-    /**
-     * Adds the specified network config listener.
-     *
-     * @param listener network config listener
-     */
-    void addListener(NetworkConfigListener listener);
-
-    /**
-     * Removes the specified network config listener.
-     *
-     * @param listener network config listener
-     */
-    void removeListener(NetworkConfigListener listener);
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/resource/label/LabelResourceService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/resource/label/LabelResourceService.java
index 612fbc7..02052c3 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/resource/label/LabelResourceService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/resource/label/LabelResourceService.java
@@ -4,6 +4,7 @@
 import java.util.Set;
 
 import com.google.common.annotations.Beta;
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.DeviceId;
 
 import com.google.common.collect.Multimap;
@@ -12,7 +13,8 @@
  * Service for providing label resource allocation.
  */
 @Beta
-public interface LabelResourceService {
+public interface LabelResourceService
+    extends ListenerService<LabelResourceEvent, LabelResourceListener> {
 
     /**
      * Returns labels from resource pool by a specific device id.
@@ -95,17 +97,4 @@
      */
     LabelResourcePool getGlobalLabelResourcePool();
 
-    /**
-     * Adds the specified label resource listener.
-     *
-     * @param listener label resource listener
-     */
-    void addListener(LabelResourceListener listener);
-
-    /**
-     * Removes the specified label resource listener.
-     *
-     * @param listener label resource listener
-     */
-    void removeListener(LabelResourceListener listener);
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelService.java
index a495955..2a10a4c 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelService.java
@@ -19,6 +19,7 @@
 
 import com.google.common.annotations.Beta;
 import org.onosproject.core.ApplicationId;
+import org.onosproject.event.ListenerService;
 import org.onosproject.incubator.net.tunnel.Tunnel.Type;
 import org.onosproject.net.Annotations;
 import org.onosproject.net.DeviceId;
@@ -27,7 +28,8 @@
  * Service for interacting with the inventory of tunnels.
  */
 @Beta
-public interface TunnelService {
+public interface TunnelService
+    extends ListenerService<TunnelEvent, TunnelListener> {
 
     /**
      * Borrows a specific tunnel. Annotations parameter is reserved.If there
@@ -196,17 +198,4 @@
      */
     Iterable<Tunnel> getTunnels(DeviceId deviceId);
 
-    /**
-     * Adds the specified tunnel listener.
-     *
-     * @param listener tunnel listener
-     */
-    void addListener(TunnelListener listener);
-
-    /**
-     * Removes the specified tunnel listener.
-     *
-     * @param listener tunnel listener
-     */
-    void removeListener(TunnelListener listener);
 }
diff --git a/incubator/net/pom.xml b/incubator/net/pom.xml
index 718f8ab..b068899 100644
--- a/incubator/net/pom.xml
+++ b/incubator/net/pom.xml
@@ -56,6 +56,11 @@
         </dependency>
 
         <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-common</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymock</artifactId>
             <scope>test</scope>
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/NetworkConfigManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/NetworkConfigManager.java
index a73cc8e..c295feb 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/NetworkConfigManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/NetworkConfigManager.java
@@ -24,8 +24,7 @@
 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.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.incubator.net.config.Config;
 import org.onosproject.incubator.net.config.ConfigFactory;
 import org.onosproject.incubator.net.config.NetworkConfigEvent;
@@ -49,7 +48,9 @@
  */
 @Component(immediate = true)
 @Service
-public class NetworkConfigManager implements NetworkConfigRegistry, NetworkConfigService {
+public class NetworkConfigManager
+        extends AbstractListenerManager<NetworkConfigEvent, NetworkConfigListener>
+        implements NetworkConfigRegistry, NetworkConfigService {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -66,17 +67,11 @@
     private final Map<Class, SubjectFactory> subjectClassKeys = Maps.newConcurrentMap();
     private final Map<ConfigIdentifier, Class<? extends Config>> configClasses = Maps.newConcurrentMap();
 
-    private final ListenerRegistry<NetworkConfigEvent, NetworkConfigListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     private final NetworkConfigStoreDelegate storeDelegate = new InternalStoreDelegate();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigStore store;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
 
     @Activate
     public void activate() {
@@ -215,23 +210,12 @@
         store.clearConfig(subject, configClass);
     }
 
-    @Override
-    public void addListener(NetworkConfigListener listener) {
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(NetworkConfigListener listener) {
-        listenerRegistry.removeListener(listener);
-    }
-
-
     // Auxiliary store delegate to receive notification about changes in
     // the network configuration store state - by the store itself.
     private class InternalStoreDelegate implements NetworkConfigStoreDelegate {
         @Override
         public void notify(NetworkConfigEvent event) {
-            eventDispatcher.post(event);
+            post(event);
         }
     }
 
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/resource/label/impl/LabelResourceManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/resource/label/impl/LabelResourceManager.java
index 2836ea5..fecba11 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/resource/label/impl/LabelResourceManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/resource/label/impl/LabelResourceManager.java
@@ -1,26 +1,13 @@
 package org.onosproject.incubator.net.resource.label.impl;
 
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Collection;
-import java.util.Set;
-
+import com.google.common.collect.Multimap;
 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.event.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceEvent.Type;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.provider.AbstractProviderRegistry;
-import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.incubator.net.resource.label.LabelResource;
 import org.onosproject.incubator.net.resource.label.LabelResourceAdminService;
 import org.onosproject.incubator.net.resource.label.LabelResourceDelegate;
@@ -33,11 +20,21 @@
 import org.onosproject.incubator.net.resource.label.LabelResourceProviderService;
 import org.onosproject.incubator.net.resource.label.LabelResourceService;
 import org.onosproject.incubator.net.resource.label.LabelResourceStore;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceEvent.Type;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkArgument;
 
-import com.google.common.collect.Multimap;
+import java.util.Collection;
+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;
 
 /**
  * provides implementation of the label resource NB &amp; SB APIs.
@@ -46,23 +43,16 @@
 @Component(immediate = true)
 @Service
 public class LabelResourceManager
-        extends
-        AbstractProviderRegistry<LabelResourceProvider, LabelResourceProviderService>
-        implements LabelResourceService, LabelResourceAdminService,
-        LabelResourceProviderRegistry {
+        extends AbstractListenerProviderRegistry<LabelResourceEvent, LabelResourceListener,
+                                                 LabelResourceProvider, LabelResourceProviderService>
+        implements LabelResourceService, LabelResourceAdminService, LabelResourceProviderRegistry {
     private final Logger log = getLogger(getClass());
     private final LabelResourceDelegate delegate = new InternalLabelResourceDelegate();
 
-    private final ListenerRegistry<LabelResourceEvent, LabelResourceListener> listenerRegistry
-                            = new ListenerRegistry<>();
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LabelResourceStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceService deviceService;
 
     private DeviceListener deviceListener = new InternalDeviceListener();
@@ -104,9 +94,9 @@
         checkNotNull(beginLabel, "beginLabel is not null");
         checkNotNull(endLabel, "beginLabel is not null");
         checkArgument(beginLabel.labelId() >= 0 && endLabel.labelId() >= 0,
-                "The value of beginLabel and the value of endLabel must be both positive number.");
+                      "The value of beginLabel and the value of endLabel must be both positive number.");
         checkArgument(beginLabel.labelId() <= endLabel.labelId(),
-                "The value of endLabel must be greater than the value of endLabel.");
+                      "The value of endLabel must be greater than the value of endLabel.");
         return store.createGlobalPool(beginLabel, endLabel);
     }
 
@@ -180,26 +170,7 @@
         return store.getGlobalLabelResourcePool();
     }
 
-    @Override
-    public void addListener(LabelResourceListener listener) {
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(LabelResourceListener listener) {
-        listenerRegistry.removeListener(listener);
-
-    }
-
-    private void post(LabelResourceEvent event) {
-        if (event != null) {
-            eventDispatcher.post(event);
-        }
-    }
-
-    private class InternalLabelResourceDelegate
-            implements LabelResourceDelegate {
-
+    private class InternalLabelResourceDelegate implements LabelResourceDelegate {
         @Override
         public void notify(LabelResourceEvent event) {
             post(event);
@@ -208,7 +179,6 @@
     }
 
     private class InternalDeviceListener implements DeviceListener {
-
         @Override
         public void event(DeviceEvent event) {
             Device device = event.subject();
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/tunnel/impl/TunnelManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/tunnel/impl/TunnelManager.java
index bb344b7..d316388 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/tunnel/impl/TunnelManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/tunnel/impl/TunnelManager.java
@@ -15,25 +15,17 @@
  */
 package org.onosproject.incubator.net.tunnel.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
 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.event.EventDeliveryService;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.incubator.net.tunnel.DefaultTunnel;
-import org.onosproject.incubator.net.tunnel.Tunnel.Type;
 import org.onosproject.incubator.net.tunnel.Tunnel;
+import org.onosproject.incubator.net.tunnel.Tunnel.Type;
 import org.onosproject.incubator.net.tunnel.TunnelAdminService;
 import org.onosproject.incubator.net.tunnel.TunnelDescription;
 import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
@@ -51,35 +43,36 @@
 import org.onosproject.net.Annotations;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Path;
-import org.onosproject.net.provider.AbstractProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.onosproject.net.provider.ProviderId;
 import org.slf4j.Logger;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Provides implementation of the tunnel NB/SB APIs.
  */
 @Component(immediate = true, enabled = true)
 @Service
 public class TunnelManager
-        extends AbstractProviderRegistry<TunnelProvider, TunnelProviderService>
+        extends AbstractListenerProviderRegistry<TunnelEvent, TunnelListener,
+                                                 TunnelProvider, TunnelProviderService>
         implements TunnelService, TunnelAdminService, TunnelProviderRegistry {
 
     private static final String TUNNNEL_ID_NULL = "Tunnel ID cannot be null";
 
     private final Logger log = getLogger(getClass());
 
-    protected final ListenerRegistry<TunnelEvent, TunnelListener>
-            listenerRegistry = new ListenerRegistry<>();
-
     private final TunnelStoreDelegate delegate = new InternalStoreDelegate();
 
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected TunnelStore store;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
 
     @Activate
     public void activate() {
@@ -294,16 +287,6 @@
         return new InternalTunnelProviderService(provider);
     }
 
-    @Override
-    public void addListener(TunnelListener listener) {
-        listenerRegistry.addListener(listener);
-    }
-
-    @Override
-    public void removeListener(TunnelListener listener) {
-        listenerRegistry.removeListener(listener);
-    }
-
     private class InternalTunnelProviderService
             extends AbstractProviderService<TunnelProvider>
             implements TunnelProviderService {
@@ -370,7 +353,7 @@
         @Override
         public void notify(TunnelEvent event) {
             if (event != null) {
-                eventDispatcher.post(event);
+                post(event);
             }
         }
     }