Added notion of a general Store abstraction and wired it up in ClusterStore.
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/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/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/store/AbstractStore.java b/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java
new file mode 100644
index 0000000..efd0d03
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java
@@ -0,0 +1,33 @@
+package org.onlab.onos.store;
+
+import org.onlab.onos.event.Event;
+
+/**
+ * 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) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public D getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * 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..9eaef66
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/Store.java
@@ -0,0 +1,25 @@
+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
+ */
+ void setDelegate(D delegate);
+
+ /**
+ * Get the current store delegate.
+ *
+ * @return store delegate
+ */
+ D getDelegate();
+
+}
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..d0cc949 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,6 +46,7 @@
@Activate
public void activate() {
+ store.setDelegate(delegate);
eventDispatcher.addSink(ClusterEvent.class, listenerRegistry);
log.info("Started");
}
@@ -90,4 +94,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/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 92d6880..2a7f67a 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");