Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/apps/foo/pom.xml b/apps/foo/pom.xml
new file mode 100644
index 0000000..b86d2e9
--- /dev/null
+++ b/apps/foo/pom.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onlab.onos</groupId>
+        <artifactId>onos-apps</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-foo</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>ONOS application for miscellaneous experiments</description>
+
+</project>
diff --git a/apps/foo/src/main/java/org/onlab/onos/foo/FooComponent.java b/apps/foo/src/main/java/org/onlab/onos/foo/FooComponent.java
new file mode 100644
index 0000000..b9251dd
--- /dev/null
+++ b/apps/foo/src/main/java/org/onlab/onos/foo/FooComponent.java
@@ -0,0 +1,48 @@
+package org.onlab.onos.foo;
+
+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.onlab.onos.cluster.ClusterEvent;
+import org.onlab.onos.cluster.ClusterEventListener;
+import org.onlab.onos.cluster.ClusterService;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Playground app component.
+ */
+@Component(immediate = true)
+public class FooComponent {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterService clusterService;
+
+    private ClusterEventListener clusterListener = new InnerClusterListener();
+
+    @Activate
+    public void activate() {
+        clusterService.addListener(clusterListener);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        clusterService.removeListener(clusterListener);
+        log.info("Stopped");
+    }
+
+    private class InnerClusterListener implements ClusterEventListener {
+        @Override
+        public void event(ClusterEvent event) {
+            log.info("WOOOOT! {}", event);
+        }
+    }
+}
+
+
diff --git a/apps/pom.xml b/apps/pom.xml
index 078a92d..de9faa7 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -19,6 +19,7 @@
     <modules>
         <module>tvue</module>
         <module>fwd</module>
+        <module>foo</module>
     </modules>
 
     <properties>
diff --git a/core/api/src/main/java/org/onlab/onos/cluster/ClusterStore.java b/core/api/src/main/java/org/onlab/onos/cluster/ClusterStore.java
index 4579190..ea5bbd3 100644
--- a/core/api/src/main/java/org/onlab/onos/cluster/ClusterStore.java
+++ b/core/api/src/main/java/org/onlab/onos/cluster/ClusterStore.java
@@ -1,11 +1,13 @@
 package org.onlab.onos.cluster;
 
+import org.onlab.onos.store.Store;
+
 import java.util.Set;
 
 /**
  * Manages inventory of controller cluster nodes; not intended for direct use.
  */
-public interface ClusterStore {
+public interface ClusterStore extends Store<ClusterEvent, ClusterStoreDelegate> {
 
     /**
      * Returns the local controller node.
diff --git a/core/api/src/main/java/org/onlab/onos/cluster/ClusterStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/cluster/ClusterStoreDelegate.java
new file mode 100644
index 0000000..b247c27
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/cluster/ClusterStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.cluster;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Cluster store delegate abstraction.
+ */
+public interface ClusterStoreDelegate extends StoreDelegate<ClusterEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java b/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java
index b3dc696..08fa57b 100644
--- a/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java
+++ b/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java
@@ -4,12 +4,13 @@
 
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
+import org.onlab.onos.store.Store;
 
 /**
  * Manages inventory of mastership roles for devices, across controller
  * instances; not intended for direct use.
  */
-public interface MastershipStore {
+public interface MastershipStore extends Store<MastershipEvent, MastershipStoreDelegate> {
 
     // three things to map: NodeId, DeviceId, MastershipRole
 
diff --git a/core/api/src/main/java/org/onlab/onos/cluster/MastershipStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/cluster/MastershipStoreDelegate.java
new file mode 100644
index 0000000..b4d923c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/cluster/MastershipStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.cluster;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Mastership store delegate abstraction.
+ */
+public interface MastershipStoreDelegate extends StoreDelegate<MastershipEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/device/DeviceProviderService.java b/core/api/src/main/java/org/onlab/onos/net/device/DeviceProviderService.java
index 5401646..7f28374 100644
--- a/core/api/src/main/java/org/onlab/onos/net/device/DeviceProviderService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/device/DeviceProviderService.java
@@ -1,6 +1,7 @@
 package org.onlab.onos.net.device;
 
 import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.MastershipRole;
 import org.onlab.onos.net.provider.ProviderService;
 
 import java.util.List;
@@ -45,4 +46,13 @@
      */
     void portStatusChanged(DeviceId deviceId, PortDescription portDescription);
 
+    /**
+     * Notifies the core about the providers inability to assert the specified
+     * mastership role on the device.
+     *
+     * @param deviceId identity of the device
+     * @param role mastership role being asserted
+     */
+    void unableToAssertRole(DeviceId deviceId, MastershipRole role);
+
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
index ef111e9..c84aac8 100644
--- a/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
@@ -5,13 +5,14 @@
 import org.onlab.onos.net.Port;
 import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
 
 import java.util.List;
 
 /**
  * Manages inventory of infrastructure devices; not intended for direct use.
  */
-public interface DeviceStore {
+public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> {
 
     /**
      * Returns the number of devices known to the system.
diff --git a/core/api/src/main/java/org/onlab/onos/net/device/DeviceStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStoreDelegate.java
new file mode 100644
index 0000000..4ab8486
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.device;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Infrastructure device store delegate abstraction.
+ */
+public interface DeviceStoreDelegate extends StoreDelegate<DeviceEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
index f00b595..bfd05f2 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
@@ -1,11 +1,12 @@
 package org.onlab.onos.net.flow;
 
 import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.store.Store;
 
 /**
  * Manages inventory of flow rules; not intended for direct use.
  */
-public interface FlowRuleStore {
+public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegate> {
 
     /**
      * Returns the flow entries associated with a device.
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java
new file mode 100644
index 0000000..119712b
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.flow;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Flow rule store delegate abstraction.
+ */
+public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java b/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java
index e70bbf2..3f1cb23 100644
--- a/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java
@@ -1,20 +1,21 @@
 package org.onlab.onos.net.host;
 
-import java.util.Set;
-
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.Host;
 import org.onlab.onos.net.HostId;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 
+import java.util.Set;
+
 /**
  * Manages inventory of end-station hosts; not intended for direct use.
  */
-public interface HostStore {
+public interface HostStore extends Store<HostEvent, HostStoreDelegate> {
 
     /**
      * Creates a new host or updates the existing one based on the specified
@@ -133,7 +134,7 @@
      * Returns the address bindings for a particular connection point.
      *
      * @param connectPoint the connection point to return address information
-     * for
+     *                     for
      * @return address information for the connection point
      */
     PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint);
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/HostStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/host/HostStoreDelegate.java
new file mode 100644
index 0000000..999b28f
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/host/HostStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.host;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Infrastructure link store delegate abstraction.
+ */
+public interface HostStoreDelegate extends StoreDelegate<HostEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java b/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java
index dbe4877..0197417 100644
--- a/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java
@@ -4,13 +4,14 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
 
 import java.util.Set;
 
 /**
  * Manages inventory of infrastructure links; not intended for direct use.
  */
-public interface LinkStore {
+public interface LinkStore extends Store<LinkEvent, LinkStoreDelegate> {
 
     /**
      * Returns the number of links in the store.
diff --git a/core/api/src/main/java/org/onlab/onos/net/link/LinkStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/link/LinkStoreDelegate.java
new file mode 100644
index 0000000..ec747c4
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/link/LinkStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.link;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Infrastructure link store delegate abstraction.
+ */
+public interface LinkStoreDelegate extends StoreDelegate<LinkEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java
index adc6145..1945f4c 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java
@@ -6,6 +6,7 @@
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.Path;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
 
 import java.util.List;
 import java.util.Set;
@@ -13,7 +14,7 @@
 /**
  * Manages inventory of topology snapshots; not intended for direct use.
  */
-public interface TopologyStore {
+public interface TopologyStore extends Store<TopologyEvent, TopologyStoreDelegate> {
 
     /**
      * Returns the current topology snapshot.
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStoreDelegate.java
new file mode 100644
index 0000000..2a19a0c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.topology;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Topology store delegate abstraction.
+ */
+public interface TopologyStoreDelegate extends StoreDelegate<TopologyEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java b/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java
new file mode 100644
index 0000000..5d76e0f
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java
@@ -0,0 +1,44 @@
+package org.onlab.onos.store;
+
+import org.onlab.onos.event.Event;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Base implementation of a store.
+ */
+public class AbstractStore<E extends Event, D extends StoreDelegate<E>>
+        implements Store<E, D> {
+
+    protected D delegate;
+
+    @Override
+    public void setDelegate(D delegate) {
+        checkState(this.delegate == null || this.delegate == delegate,
+                   "Store delegate already set");
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void unsetDelegate(D delegate) {
+        if (this.delegate == delegate) {
+            this.delegate = null;
+        }
+    }
+
+    @Override
+    public boolean hasDelegate() {
+        return delegate != null;
+    }
+
+    /**
+     * Notifies the delegate with the specified event.
+     *
+     * @param event event to delegate
+     */
+    protected void notifyDelegate(E event) {
+        if (delegate != null) {
+            delegate.notify(event);
+        }
+    }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/store/Store.java b/core/api/src/main/java/org/onlab/onos/store/Store.java
new file mode 100644
index 0000000..28bc08e
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/Store.java
@@ -0,0 +1,36 @@
+package org.onlab.onos.store;
+
+import org.onlab.onos.event.Event;
+
+/**
+ * Abstraction of a entity capable of storing and/or distributing information
+ * across a cluster.
+ */
+public interface Store<E extends Event, D extends StoreDelegate<E>> {
+
+    /**
+     * Sets the delegate on the store.
+     *
+     * @param delegate new store delegate
+     * @throws java.lang.IllegalStateException if a delegate is already
+     *                                         currently set on the store and is a different one that
+     */
+    void setDelegate(D delegate);
+
+    /**
+     * Withdraws the delegate from the store.
+     *
+     * @param delegate store delegate to withdraw
+     * @throws java.lang.IllegalArgumentException if the delegate is not
+     *                                            currently set on the store
+     */
+    void unsetDelegate(D delegate);
+
+    /**
+     * Indicates whether the store has a delegate.
+     *
+     * @return true if delegate is set
+     */
+    boolean hasDelegate();
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/store/StoreDelegate.java b/core/api/src/main/java/org/onlab/onos/store/StoreDelegate.java
new file mode 100644
index 0000000..e2c5cd3
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/StoreDelegate.java
@@ -0,0 +1,13 @@
+package org.onlab.onos.store;
+
+import org.onlab.onos.event.Event;
+
+/**
+ * Entity associated with a store and capable of receiving notifications of
+ * events within the store.
+ */
+public interface StoreDelegate<E extends Event> {
+
+    void notify(E event);
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/store/package-info.java b/core/api/src/main/java/org/onlab/onos/store/package-info.java
new file mode 100644
index 0000000..7e767f0
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Abstractions for creating and interacting with distributed stores.
+ */
+package org.onlab.onos.store;
\ No newline at end of file
diff --git a/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java b/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java
index aa21283..9913ad0 100644
--- a/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java
+++ b/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java
@@ -11,6 +11,7 @@
 import org.onlab.onos.cluster.ClusterEventListener;
 import org.onlab.onos.cluster.ClusterService;
 import org.onlab.onos.cluster.ClusterStore;
+import org.onlab.onos.cluster.ClusterStoreDelegate;
 import org.onlab.onos.cluster.ControllerNode;
 import org.onlab.onos.cluster.NodeId;
 import org.onlab.onos.event.AbstractListenerRegistry;
@@ -32,6 +33,8 @@
     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 AbstractListenerRegistry<ClusterEvent, ClusterEventListener>
             listenerRegistry = new AbstractListenerRegistry<>();
 
@@ -43,12 +46,14 @@
 
     @Activate
     public void activate() {
+        store.setDelegate(delegate);
         eventDispatcher.addSink(ClusterEvent.class, listenerRegistry);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        store.unsetDelegate(delegate);
         eventDispatcher.removeSink(ClusterEvent.class);
         log.info("Stopped");
     }
@@ -90,4 +95,13 @@
     public void removeListener(ClusterEventListener listener) {
         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);
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
index 2f61925..3dfce00 100644
--- a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
@@ -26,6 +26,7 @@
 import org.onlab.onos.net.device.DeviceProviderService;
 import org.onlab.onos.net.device.DeviceService;
 import org.onlab.onos.net.device.DeviceStore;
+import org.onlab.onos.net.device.DeviceStoreDelegate;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.AbstractProviderRegistry;
 import org.onlab.onos.net.provider.AbstractProviderService;
@@ -33,8 +34,8 @@
 
 import java.util.List;
 
-import static org.onlab.onos.net.device.DeviceEvent.Type.*;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_MASTERSHIP_CHANGED;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -57,7 +58,9 @@
     protected final AbstractListenerRegistry<DeviceEvent, DeviceListener>
             listenerRegistry = new AbstractListenerRegistry<>();
 
-    private final MastershipListener mastershipListener = new InnerMastershipListener();
+    private DeviceStoreDelegate delegate = new InternalStoreDelegate();
+
+    private final MastershipListener mastershipListener = new InternalMastershipListener();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceStore store;
@@ -73,6 +76,7 @@
 
     @Activate
     public void activate() {
+        store.setDelegate(delegate);
         eventDispatcher.addSink(DeviceEvent.class, listenerRegistry);
         mastershipService.addListener(mastershipListener);
         log.info("Started");
@@ -80,6 +84,7 @@
 
     @Deactivate
     public void deactivate() {
+        store.unsetDelegate(delegate);
         mastershipService.removeListener(mastershipListener);
         eventDispatcher.removeSink(DeviceEvent.class);
         log.info("Stopped");
@@ -224,6 +229,11 @@
                 post(event);
             }
         }
+
+        @Override
+        public void unableToAssertRole(DeviceId deviceId, MastershipRole role) {
+            // FIXME: implement response to this notification
+        }
     }
 
     // Posts the specified event to the local event dispatcher.
@@ -234,7 +244,7 @@
     }
 
     // Intercepts mastership events
-    private class InnerMastershipListener implements MastershipListener {
+    private class InternalMastershipListener implements MastershipListener {
         @Override
         public void event(MastershipEvent event) {
             // FIXME: for now we're taking action only on becoming master
@@ -243,4 +253,12 @@
             }
         }
     }
+
+    // Store delegate to re-post events emitted from the store.
+    private class InternalStoreDelegate implements DeviceStoreDelegate {
+        @Override
+        public void notify(DeviceEvent event) {
+            post(event);
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
index b3481c1..bed4ee6 100644
--- a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
@@ -1,11 +1,6 @@
 package org.onlab.onos.net.flow.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Iterator;
-import java.util.List;
-
+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;
@@ -27,11 +22,16 @@
 import org.onlab.onos.net.flow.FlowRuleProviderService;
 import org.onlab.onos.net.flow.FlowRuleService;
 import org.onlab.onos.net.flow.FlowRuleStore;
+import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
 import org.onlab.onos.net.provider.AbstractProviderRegistry;
 import org.onlab.onos.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
-import com.google.common.collect.Lists;
+import java.util.Iterator;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Provides implementation of the flow NB &amp; SB APIs.
@@ -48,6 +48,8 @@
     private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
     listenerRegistry = new AbstractListenerRegistry<>();
 
+    private FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected FlowRuleStore store;
 
@@ -59,12 +61,14 @@
 
     @Activate
     public void activate() {
+        store.setDelegate(delegate);
         eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        store.unsetDelegate(delegate);
         eventDispatcher.removeSink(FlowRuleEvent.class);
         log.info("Stopped");
     }
@@ -196,4 +200,11 @@
         }
     }
 
+    // Store delegate to re-post events emitted from the store.
+    private class InternalStoreDelegate implements FlowRuleStoreDelegate {
+        @Override
+        public void notify(FlowRuleEvent event) {
+            eventDispatcher.post(event);
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
index 9b8ecf7..e3f53fe 100644
--- a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
@@ -1,10 +1,5 @@
 package org.onlab.onos.net.host.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
-
-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;
@@ -26,6 +21,7 @@
 import org.onlab.onos.net.host.HostProviderService;
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.host.HostStore;
+import org.onlab.onos.net.host.HostStoreDelegate;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.provider.AbstractProviderRegistry;
 import org.onlab.onos.net.provider.AbstractProviderService;
@@ -35,6 +31,11 @@
 import org.onlab.packet.VlanId;
 import org.slf4j.Logger;
 
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Provides basic implementation of the host SB &amp; NB APIs.
  */
@@ -50,6 +51,8 @@
     private final AbstractListenerRegistry<HostEvent, HostListener>
             listenerRegistry = new AbstractListenerRegistry<>();
 
+    private HostStoreDelegate delegate = new InternalStoreDelegate();
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostStore store;
 
@@ -59,12 +62,14 @@
 
     @Activate
     public void activate() {
+        store.setDelegate(delegate);
         eventDispatcher.addSink(HostEvent.class, listenerRegistry);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        store.unsetDelegate(delegate);
         eventDispatcher.removeSink(HostEvent.class);
         log.info("Stopped");
     }
@@ -219,4 +224,11 @@
         }
     }
 
+    // Store delegate to re-post events emitted from the store.
+    private class InternalStoreDelegate implements HostStoreDelegate {
+        @Override
+        public void notify(HostEvent event) {
+            post(event);
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java b/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java
index 9ac5e80..493580d 100644
--- a/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java
@@ -28,6 +28,7 @@
 import org.onlab.onos.net.link.LinkProviderService;
 import org.onlab.onos.net.link.LinkService;
 import org.onlab.onos.net.link.LinkStore;
+import org.onlab.onos.net.link.LinkStoreDelegate;
 import org.onlab.onos.net.provider.AbstractProviderRegistry;
 import org.onlab.onos.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
@@ -52,7 +53,9 @@
     protected final AbstractListenerRegistry<LinkEvent, LinkListener>
             listenerRegistry = new AbstractListenerRegistry<>();
 
-    private final DeviceListener deviceListener = new InnerDeviceListener();
+    private LinkStoreDelegate delegate = new InternalStoreDelegate();
+
+    private final DeviceListener deviceListener = new InternalDeviceListener();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LinkStore store;
@@ -65,6 +68,7 @@
 
     @Activate
     public void activate() {
+        store.setDelegate(delegate);
         eventDispatcher.addSink(LinkEvent.class, listenerRegistry);
         deviceService.addListener(deviceListener);
         log.info("Started");
@@ -72,6 +76,7 @@
 
     @Deactivate
     public void deactivate() {
+        store.unsetDelegate(delegate);
         eventDispatcher.removeSink(LinkEvent.class);
         deviceService.removeListener(deviceListener);
         log.info("Stopped");
@@ -154,7 +159,7 @@
 
     // Auxiliary interceptor for device remove events to prune links that
     // are associated with the removed device or its port.
-    private class InnerDeviceListener implements DeviceListener {
+    private class InternalDeviceListener implements DeviceListener {
         @Override
         public void event(DeviceEvent event) {
             if (event.type() == DeviceEvent.Type.DEVICE_REMOVED) {
@@ -236,4 +241,11 @@
         }
     }
 
+    // Store delegate to re-post events emitted from the store.
+    private class InternalStoreDelegate implements LinkStoreDelegate {
+        @Override
+        public void notify(LinkEvent event) {
+            post(event);
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java b/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java
index 57e9fb7..4846944 100644
--- a/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java
@@ -28,6 +28,7 @@
 import org.onlab.onos.net.topology.TopologyProviderService;
 import org.onlab.onos.net.topology.TopologyService;
 import org.onlab.onos.net.topology.TopologyStore;
+import org.onlab.onos.net.topology.TopologyStoreDelegate;
 import org.slf4j.Logger;
 
 import java.util.List;
@@ -56,6 +57,8 @@
     private final AbstractListenerRegistry<TopologyEvent, TopologyListener>
             listenerRegistry = new AbstractListenerRegistry<>();
 
+    private TopologyStoreDelegate delegate = new InternalStoreDelegate();
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected TopologyStore store;
 
@@ -65,12 +68,14 @@
 
     @Activate
     public void activate() {
+        store.setDelegate(delegate);
         eventDispatcher.addSink(TopologyEvent.class, listenerRegistry);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        store.unsetDelegate(delegate);
         eventDispatcher.removeSink(TopologyEvent.class);
         log.info("Stopped");
     }
@@ -188,4 +193,11 @@
         }
     }
 
+    // Store delegate to re-post events emitted from the store.
+    private class InternalStoreDelegate implements TopologyStoreDelegate {
+        @Override
+        public void notify(TopologyEvent event) {
+            eventDispatcher.post(event);
+        }
+    }
 }
diff --git a/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java
index 0aa9c0e..b7362b9 100644
--- a/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java
@@ -30,7 +30,7 @@
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.AbstractProvider;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.StoreService;
+import org.onlab.onos.store.common.StoreService;
 import org.onlab.onos.store.device.impl.DistributedDeviceStore;
 import org.onlab.onos.store.impl.StoreManager;
 
diff --git a/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedClusterStore.java b/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedClusterStore.java
index 77a28f5..004f807 100644
--- a/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedClusterStore.java
+++ b/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedClusterStore.java
@@ -12,7 +12,9 @@
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.cluster.ClusterEvent;
 import org.onlab.onos.cluster.ClusterStore;
+import org.onlab.onos.cluster.ClusterStoreDelegate;
 import org.onlab.onos.cluster.ControllerNode;
 import org.onlab.onos.cluster.DefaultControllerNode;
 import org.onlab.onos.cluster.NodeId;
@@ -26,6 +28,8 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 import static com.google.common.cache.CacheBuilder.newBuilder;
+import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_ACTIVATED;
+import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_DEACTIVATED;
 import static org.onlab.onos.cluster.ControllerNode.State;
 
 /**
@@ -33,14 +37,15 @@
  */
 @Component(immediate = true)
 @Service
-public class DistributedClusterStore extends AbstractDistributedStore
+public class DistributedClusterStore
+        extends AbstractDistributedStore<ClusterEvent, ClusterStoreDelegate>
         implements ClusterStore {
 
     private IMap<byte[], byte[]> rawNodes;
     private LoadingCache<NodeId, Optional<DefaultControllerNode>> nodes;
 
     private String listenerId;
-    private final MembershipListener listener = new InnerMembershipListener();
+    private final MembershipListener listener = new InternalMembershipListener();
     private final Map<NodeId, State> states = new ConcurrentHashMap<>();
 
     @Activate
@@ -106,11 +111,12 @@
     }
 
     // Adds a new node based on the specified member
-    private synchronized void addMember(Member member) {
+    private synchronized ControllerNode addMember(Member member) {
         DefaultControllerNode node = node(member);
         rawNodes.put(serialize(node.id()), serialize(node));
         nodes.put(node.id(), Optional.of(node));
         states.put(node.id(), State.ACTIVE);
+        return node;
     }
 
     // Creates a controller node descriptor from the Hazelcast member.
@@ -125,18 +131,20 @@
     }
 
     // Interceptor for membership events.
-    private class InnerMembershipListener implements MembershipListener {
+    private class InternalMembershipListener implements MembershipListener {
         @Override
         public void memberAdded(MembershipEvent membershipEvent) {
             log.info("Member {} added", membershipEvent.getMember());
-            addMember(membershipEvent.getMember());
+            ControllerNode node = addMember(membershipEvent.getMember());
+            notifyDelegate(new ClusterEvent(INSTANCE_ACTIVATED, node));
         }
 
         @Override
         public void memberRemoved(MembershipEvent membershipEvent) {
             log.info("Member {} removed", membershipEvent.getMember());
-            states.put(new NodeId(memberAddress(membershipEvent.getMember()).toString()),
-                       State.INACTIVE);
+            NodeId nodeId = new NodeId(memberAddress(membershipEvent.getMember()).toString());
+            states.put(nodeId, State.INACTIVE);
+            notifyDelegate(new ClusterEvent(INSTANCE_DEACTIVATED, getNode(nodeId)));
         }
 
         @Override
diff --git a/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java b/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java
index c15d6aa..10c116b 100644
--- a/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java
+++ b/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java
@@ -13,6 +13,7 @@
 import org.onlab.onos.cluster.ClusterService;
 import org.onlab.onos.cluster.MastershipEvent;
 import org.onlab.onos.cluster.MastershipStore;
+import org.onlab.onos.cluster.MastershipStoreDelegate;
 import org.onlab.onos.cluster.NodeId;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
@@ -31,7 +32,8 @@
  */
 @Component(immediate = true)
 @Service
-public class DistributedMastershipStore extends AbstractDistributedStore
+public class DistributedMastershipStore
+        extends AbstractDistributedStore<MastershipEvent, MastershipStoreDelegate>
         implements MastershipStore {
 
     private IMap<byte[], byte[]> rawMasters;
diff --git a/core/store/src/main/java/org/onlab/onos/store/StoreService.java b/core/store/src/main/java/org/onlab/onos/store/common/StoreService.java
similarity index 95%
rename from core/store/src/main/java/org/onlab/onos/store/StoreService.java
rename to core/store/src/main/java/org/onlab/onos/store/common/StoreService.java
index b10cb7e..490183f 100644
--- a/core/store/src/main/java/org/onlab/onos/store/StoreService.java
+++ b/core/store/src/main/java/org/onlab/onos/store/common/StoreService.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.store;
+package org.onlab.onos.store.common;
 
 import com.hazelcast.core.HazelcastInstance;
 
diff --git a/core/store/src/main/java/org/onlab/onos/store/package-info.java b/core/store/src/main/java/org/onlab/onos/store/common/package-info.java
similarity index 73%
rename from core/store/src/main/java/org/onlab/onos/store/package-info.java
rename to core/store/src/main/java/org/onlab/onos/store/common/package-info.java
index bea7fb0..cf19812 100644
--- a/core/store/src/main/java/org/onlab/onos/store/package-info.java
+++ b/core/store/src/main/java/org/onlab/onos/store/common/package-info.java
@@ -2,4 +2,4 @@
  * Common abstractions and facilities for implementing distributed store
  * using Hazelcast.
  */
-package org.onlab.onos.store;
+package org.onlab.onos.store.common;
diff --git a/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java b/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java
index 631c6aa..52e8ed0 100644
--- a/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java
+++ b/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java
@@ -21,6 +21,7 @@
 import org.onlab.onos.net.device.DeviceDescription;
 import org.onlab.onos.net.device.DeviceEvent;
 import org.onlab.onos.net.device.DeviceStore;
+import org.onlab.onos.net.device.DeviceStoreDelegate;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.store.impl.AbsentInvalidatingLoadingCache;
@@ -48,7 +49,8 @@
  */
 @Component(immediate = true)
 @Service
-public class DistributedDeviceStore extends AbstractDistributedStore
+public class DistributedDeviceStore
+        extends AbstractDistributedStore<DeviceEvent, DeviceStoreDelegate>
         implements DeviceStore {
 
     private final Logger log = getLogger(getClass());
diff --git a/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java b/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java
index e11dda3..bca585d 100644
--- a/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java
+++ b/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java
@@ -10,7 +10,10 @@
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.onos.store.StoreService;
+import org.onlab.onos.event.Event;
+import org.onlab.onos.store.AbstractStore;
+import org.onlab.onos.store.StoreDelegate;
+import org.onlab.onos.store.common.StoreService;
 import org.slf4j.Logger;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -20,7 +23,8 @@
  * Abstraction of a distributed store based on Hazelcast.
  */
 @Component(componentAbstract = true)
-public abstract class AbstractDistributedStore {
+public abstract class AbstractDistributedStore<E extends Event, D extends StoreDelegate<E>>
+            extends AbstractStore<E, D> {
 
     protected final Logger log = getLogger(getClass());
 
diff --git a/core/store/src/main/java/org/onlab/onos/store/impl/OptionalCacheLoader.java b/core/store/src/main/java/org/onlab/onos/store/impl/OptionalCacheLoader.java
index 47a42ee..dddd128 100644
--- a/core/store/src/main/java/org/onlab/onos/store/impl/OptionalCacheLoader.java
+++ b/core/store/src/main/java/org/onlab/onos/store/impl/OptionalCacheLoader.java
@@ -2,7 +2,7 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import org.onlab.onos.store.StoreService;
+import org.onlab.onos.store.common.StoreService;
 
 import com.google.common.base.Optional;
 import com.google.common.cache.CacheLoader;
diff --git a/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java b/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java
index 82472b7..77463fd 100644
--- a/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java
+++ b/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java
@@ -21,7 +21,7 @@
 import org.onlab.onos.net.Port;
 import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.StoreService;
+import org.onlab.onos.store.common.StoreService;
 import org.onlab.onos.store.serializers.DefaultPortSerializer;
 import org.onlab.onos.store.serializers.DeviceIdSerializer;
 import org.onlab.onos.store.serializers.IpPrefixSerializer;
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleClusterStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleClusterStore.java
index c782530..d348d2f 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleClusterStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleClusterStore.java
@@ -5,10 +5,13 @@
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.cluster.ClusterEvent;
 import org.onlab.onos.cluster.ClusterStore;
+import org.onlab.onos.cluster.ClusterStoreDelegate;
 import org.onlab.onos.cluster.ControllerNode;
 import org.onlab.onos.cluster.DefaultControllerNode;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.store.AbstractStore;
 import org.onlab.packet.IpPrefix;
 import org.slf4j.Logger;
 
@@ -22,7 +25,9 @@
  */
 @Component(immediate = true)
 @Service
-public class SimpleClusterStore implements ClusterStore {
+public class SimpleClusterStore
+        extends AbstractStore<ClusterEvent, ClusterStoreDelegate>
+        implements ClusterStore {
 
     public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
 
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
index 78d6a4c..9b78798 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
@@ -15,8 +15,10 @@
 import org.onlab.onos.net.device.DeviceDescription;
 import org.onlab.onos.net.device.DeviceEvent;
 import org.onlab.onos.net.device.DeviceStore;
+import org.onlab.onos.net.device.DeviceStoreDelegate;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.AbstractStore;
 import org.slf4j.Logger;
 
 import java.util.ArrayList;
@@ -40,7 +42,9 @@
  */
 @Component(immediate = true)
 @Service
-public class SimpleDeviceStore implements DeviceStore {
+public class SimpleDeviceStore
+        extends AbstractStore<DeviceEvent, DeviceStoreDelegate>
+        implements DeviceStore {
 
     private final Logger log = getLogger(getClass());
 
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
index fbfd0ee..9681f3b 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
@@ -13,6 +13,8 @@
 import org.onlab.onos.net.flow.FlowRuleEvent;
 import org.onlab.onos.net.flow.FlowRuleEvent.Type;
 import org.onlab.onos.net.flow.FlowRuleStore;
+import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
+import org.onlab.onos.store.AbstractStore;
 import org.slf4j.Logger;
 
 import com.google.common.collect.ArrayListMultimap;
@@ -24,7 +26,9 @@
  */
 @Component(immediate = true)
 @Service
-public class SimpleFlowRuleStore implements FlowRuleStore {
+public class SimpleFlowRuleStore
+        extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate>
+        implements FlowRuleStore {
 
     private final Logger log = getLogger(getClass());
 
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java
index bcd84df..be609a8 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java
@@ -24,8 +24,10 @@
 import org.onlab.onos.net.host.HostDescription;
 import org.onlab.onos.net.host.HostEvent;
 import org.onlab.onos.net.host.HostStore;
+import org.onlab.onos.net.host.HostStoreDelegate;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.AbstractStore;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -41,7 +43,9 @@
  */
 @Component(immediate = true)
 @Service
-public class SimpleHostStore implements HostStore {
+public class SimpleHostStore
+        extends AbstractStore<HostEvent, HostStoreDelegate>
+        implements HostStore {
 
     private final Logger log = getLogger(getClass());
 
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
index 5c99682..ccb2bfb 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
@@ -14,7 +14,9 @@
 import org.onlab.onos.net.link.LinkDescription;
 import org.onlab.onos.net.link.LinkEvent;
 import org.onlab.onos.net.link.LinkStore;
+import org.onlab.onos.net.link.LinkStoreDelegate;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.AbstractStore;
 import org.slf4j.Logger;
 
 import java.util.Collections;
@@ -35,7 +37,9 @@
  */
 @Component(immediate = true)
 @Service
-public class SimpleLinkStore implements LinkStore {
+public class SimpleLinkStore
+        extends AbstractStore<LinkEvent, LinkStoreDelegate>
+        implements LinkStore {
 
     private final Logger log = getLogger(getClass());
 
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java
index 829f140..da691fe 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java
@@ -17,9 +17,11 @@
 import org.onlab.onos.cluster.DefaultControllerNode;
 import org.onlab.onos.cluster.MastershipEvent;
 import org.onlab.onos.cluster.MastershipStore;
+import org.onlab.onos.cluster.MastershipStoreDelegate;
 import org.onlab.onos.cluster.NodeId;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
+import org.onlab.onos.store.AbstractStore;
 import org.onlab.packet.IpPrefix;
 import org.slf4j.Logger;
 
@@ -31,7 +33,9 @@
  */
 @Component(immediate = true)
 @Service
-public class SimpleMastershipStore implements MastershipStore {
+public class SimpleMastershipStore
+        extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
+        implements MastershipStore {
 
     private final Logger log = getLogger(getClass());
 
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
index 5d9c8de..32cc1f7 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
@@ -18,6 +18,8 @@
 import org.onlab.onos.net.topology.TopologyEvent;
 import org.onlab.onos.net.topology.TopologyGraph;
 import org.onlab.onos.net.topology.TopologyStore;
+import org.onlab.onos.net.topology.TopologyStoreDelegate;
+import org.onlab.onos.store.AbstractStore;
 import org.slf4j.Logger;
 
 import java.util.List;
@@ -31,7 +33,9 @@
  */
 @Component(immediate = true)
 @Service
-public class SimpleTopologyStore implements TopologyStore {
+public class SimpleTopologyStore
+        extends AbstractStore<TopologyEvent, TopologyStoreDelegate>
+        implements TopologyStore {
 
     private final Logger log = getLogger(getClass());
 
diff --git a/features/features.xml b/features/features.xml
index 7333d89..475e35b 100644
--- a/features/features.xml
+++ b/features/features.xml
@@ -97,11 +97,17 @@
         <feature>onos-thirdparty-web</feature>
         <bundle>mvn:org.onlab.onos/onos-app-tvue/1.0.0-SNAPSHOT</bundle>
     </feature>
-    
+
     <feature name="onos-app-fwd" version="1.0.0"
              description="ONOS sample forwarding application">
         <feature>onos-api</feature>
         <bundle>mvn:org.onlab.onos/onos-app-fwd/1.0.0-SNAPSHOT</bundle>
     </feature>
 
+    <feature name="onos-app-foo" version="1.0.0"
+             description="ONOS sample playground application">
+        <feature>onos-api</feature>
+        <bundle>mvn:org.onlab.onos/onos-app-foo/1.0.0-SNAPSHOT</bundle>
+    </feature>
+
 </features>
diff --git a/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java
index c25ba8d..cd55ded 100644
--- a/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java
+++ b/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -20,6 +20,7 @@
 import org.onlab.onos.net.DefaultDevice;
 import org.onlab.onos.net.Device;
 import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.MastershipRole;
 import org.onlab.onos.net.device.DeviceDescription;
 import org.onlab.onos.net.device.DeviceProvider;
 import org.onlab.onos.net.device.DeviceProviderRegistry;
@@ -181,6 +182,11 @@
                 descr = portDescription;
             }
 
+            @Override
+            public void unableToAssertRole(DeviceId deviceId, MastershipRole role) {
+                // FIXME: add fixture core when tests are done on this
+            }
+
         }
     }
 
diff --git a/tools/build/onos-package b/tools/build/onos-package
index 01b14fe..cf751c7 100755
--- a/tools/build/onos-package
+++ b/tools/build/onos-package
@@ -51,7 +51,7 @@
     $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg 
 
 # Patch the Apache Karaf distribution file to load ONOS features
-perl -pi.old -e 's|^(featuresBoot=.*)|\1,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd|' \
+perl -pi.old -e 's|^(featuresBoot=.*)|\1,webconsole,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd,onos-app-foo|' \
     $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg
 
 # Patch the Apache Karaf distribution with ONOS branding bundle