tom

Added notion of a general Store abstraction and wired it up in ClusterStore.

Showing 24 changed files with 232 additions and 20 deletions
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5 + <modelVersion>4.0.0</modelVersion>
6 +
7 + <parent>
8 + <groupId>org.onlab.onos</groupId>
9 + <artifactId>onos-apps</artifactId>
10 + <version>1.0.0-SNAPSHOT</version>
11 + <relativePath>../pom.xml</relativePath>
12 + </parent>
13 +
14 + <artifactId>onos-app-foo</artifactId>
15 + <packaging>bundle</packaging>
16 +
17 + <description>ONOS application for miscellaneous experiments</description>
18 +
19 +</project>
1 +package org.onlab.onos.foo;
2 +
3 +import org.apache.felix.scr.annotations.Activate;
4 +import org.apache.felix.scr.annotations.Component;
5 +import org.apache.felix.scr.annotations.Deactivate;
6 +import org.apache.felix.scr.annotations.Reference;
7 +import org.apache.felix.scr.annotations.ReferenceCardinality;
8 +import org.onlab.onos.cluster.ClusterEvent;
9 +import org.onlab.onos.cluster.ClusterEventListener;
10 +import org.onlab.onos.cluster.ClusterService;
11 +import org.slf4j.Logger;
12 +
13 +import static org.slf4j.LoggerFactory.getLogger;
14 +
15 +/**
16 + * Playground app component.
17 + */
18 +@Component(immediate = true)
19 +public class FooComponent {
20 +
21 + private final Logger log = getLogger(getClass());
22 +
23 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
24 + protected ClusterService clusterService;
25 +
26 + private ClusterEventListener clusterListener = new InnerClusterListener();
27 +
28 + @Activate
29 + public void activate() {
30 + clusterService.addListener(clusterListener);
31 + log.info("Started");
32 + }
33 +
34 + @Deactivate
35 + public void deactivate() {
36 + clusterService.removeListener(clusterListener);
37 + log.info("Stopped");
38 + }
39 +
40 + private class InnerClusterListener implements ClusterEventListener {
41 + @Override
42 + public void event(ClusterEvent event) {
43 + log.info("WOOOOT! {}", event);
44 + }
45 + }
46 +}
47 +
48 +
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
19 <modules> 19 <modules>
20 <module>tvue</module> 20 <module>tvue</module>
21 <module>fwd</module> 21 <module>fwd</module>
22 + <module>foo</module>
22 </modules> 23 </modules>
23 24
24 <properties> 25 <properties>
......
1 package org.onlab.onos.cluster; 1 package org.onlab.onos.cluster;
2 2
3 +import org.onlab.onos.store.Store;
4 +
3 import java.util.Set; 5 import java.util.Set;
4 6
5 /** 7 /**
6 * Manages inventory of controller cluster nodes; not intended for direct use. 8 * Manages inventory of controller cluster nodes; not intended for direct use.
7 */ 9 */
8 -public interface ClusterStore { 10 +public interface ClusterStore extends Store<ClusterEvent, ClusterStoreDelegate> {
9 11
10 /** 12 /**
11 * Returns the local controller node. 13 * Returns the local controller node.
......
1 +package org.onlab.onos.cluster;
2 +
3 +import org.onlab.onos.store.StoreDelegate;
4 +
5 +/**
6 + * Cluster store delegate abstraction.
7 + */
8 +public interface ClusterStoreDelegate extends StoreDelegate<ClusterEvent> {
9 +}
1 +package org.onlab.onos.cluster;
2 +
3 +import org.onlab.onos.store.StoreDelegate;
4 +
5 +/**
6 + * Mastership store delegate abstraction.
7 + */
8 +public interface MastershipStoreDelegate extends StoreDelegate<MastershipEvent> {
9 +}
1 +package org.onlab.onos.net.device;
2 +
3 +import org.onlab.onos.store.StoreDelegate;
4 +
5 +/**
6 + * Infrastructure device store delegate abstraction.
7 + */
8 +public interface DeviceStoreDelegate extends StoreDelegate<DeviceEvent> {
9 +}
1 +package org.onlab.onos.store;
2 +
3 +import org.onlab.onos.event.Event;
4 +
5 +/**
6 + * Base implementation of a store.
7 + */
8 +public class AbstractStore<E extends Event, D extends StoreDelegate<E>>
9 + implements Store<E, D> {
10 +
11 + protected D delegate;
12 +
13 + @Override
14 + public void setDelegate(D delegate) {
15 + this.delegate = delegate;
16 + }
17 +
18 + @Override
19 + public D getDelegate() {
20 + return delegate;
21 + }
22 +
23 + /**
24 + * Notifies the delegate with the specified event.
25 + *
26 + * @param event event to delegate
27 + */
28 + protected void notifyDelegate(E event) {
29 + if (delegate != null) {
30 + delegate.notify(event);
31 + }
32 + }
33 +}
1 +package org.onlab.onos.store;
2 +
3 +import org.onlab.onos.event.Event;
4 +
5 +/**
6 + * Abstraction of a entity capable of storing and/or distributing information
7 + * across a cluster.
8 + */
9 +public interface Store<E extends Event, D extends StoreDelegate<E>> {
10 +
11 + /**
12 + * Sets the delegate on the store.
13 + *
14 + * @param delegate new store delegate
15 + */
16 + void setDelegate(D delegate);
17 +
18 + /**
19 + * Get the current store delegate.
20 + *
21 + * @return store delegate
22 + */
23 + D getDelegate();
24 +
25 +}
1 +package org.onlab.onos.store;
2 +
3 +import org.onlab.onos.event.Event;
4 +
5 +/**
6 + * Entity associated with a store and capable of receiving notifications of
7 + * events within the store.
8 + */
9 +public interface StoreDelegate<E extends Event> {
10 +
11 + void notify(E event);
12 +
13 +}
1 +/**
2 + * Abstractions for creating and interacting with distributed stores.
3 + */
4 +package org.onlab.onos.store;
...\ No newline at end of file ...\ No newline at end of file
...@@ -11,6 +11,7 @@ import org.onlab.onos.cluster.ClusterEvent; ...@@ -11,6 +11,7 @@ import org.onlab.onos.cluster.ClusterEvent;
11 import org.onlab.onos.cluster.ClusterEventListener; 11 import org.onlab.onos.cluster.ClusterEventListener;
12 import org.onlab.onos.cluster.ClusterService; 12 import org.onlab.onos.cluster.ClusterService;
13 import org.onlab.onos.cluster.ClusterStore; 13 import org.onlab.onos.cluster.ClusterStore;
14 +import org.onlab.onos.cluster.ClusterStoreDelegate;
14 import org.onlab.onos.cluster.ControllerNode; 15 import org.onlab.onos.cluster.ControllerNode;
15 import org.onlab.onos.cluster.NodeId; 16 import org.onlab.onos.cluster.NodeId;
16 import org.onlab.onos.event.AbstractListenerRegistry; 17 import org.onlab.onos.event.AbstractListenerRegistry;
...@@ -32,6 +33,8 @@ public class ClusterManager implements ClusterService, ClusterAdminService { ...@@ -32,6 +33,8 @@ public class ClusterManager implements ClusterService, ClusterAdminService {
32 public static final String INSTANCE_ID_NULL = "Instance ID cannot be null"; 33 public static final String INSTANCE_ID_NULL = "Instance ID cannot be null";
33 private final Logger log = getLogger(getClass()); 34 private final Logger log = getLogger(getClass());
34 35
36 + private ClusterStoreDelegate delegate = new InternalStoreDelegate();
37 +
35 protected final AbstractListenerRegistry<ClusterEvent, ClusterEventListener> 38 protected final AbstractListenerRegistry<ClusterEvent, ClusterEventListener>
36 listenerRegistry = new AbstractListenerRegistry<>(); 39 listenerRegistry = new AbstractListenerRegistry<>();
37 40
...@@ -43,6 +46,7 @@ public class ClusterManager implements ClusterService, ClusterAdminService { ...@@ -43,6 +46,7 @@ public class ClusterManager implements ClusterService, ClusterAdminService {
43 46
44 @Activate 47 @Activate
45 public void activate() { 48 public void activate() {
49 + store.setDelegate(delegate);
46 eventDispatcher.addSink(ClusterEvent.class, listenerRegistry); 50 eventDispatcher.addSink(ClusterEvent.class, listenerRegistry);
47 log.info("Started"); 51 log.info("Started");
48 } 52 }
...@@ -90,4 +94,13 @@ public class ClusterManager implements ClusterService, ClusterAdminService { ...@@ -90,4 +94,13 @@ public class ClusterManager implements ClusterService, ClusterAdminService {
90 public void removeListener(ClusterEventListener listener) { 94 public void removeListener(ClusterEventListener listener) {
91 listenerRegistry.removeListener(listener); 95 listenerRegistry.removeListener(listener);
92 } 96 }
97 +
98 + // Store delegate to re-post events emitted from the store.
99 + private class InternalStoreDelegate implements ClusterStoreDelegate {
100 + @Override
101 + public void notify(ClusterEvent event) {
102 + checkNotNull(event, "Event cannot be null");
103 + eventDispatcher.post(event);
104 + }
105 + }
93 } 106 }
......
...@@ -30,7 +30,7 @@ import org.onlab.onos.net.device.DeviceService; ...@@ -30,7 +30,7 @@ import org.onlab.onos.net.device.DeviceService;
30 import org.onlab.onos.net.device.PortDescription; 30 import org.onlab.onos.net.device.PortDescription;
31 import org.onlab.onos.net.provider.AbstractProvider; 31 import org.onlab.onos.net.provider.AbstractProvider;
32 import org.onlab.onos.net.provider.ProviderId; 32 import org.onlab.onos.net.provider.ProviderId;
33 -import org.onlab.onos.store.StoreService; 33 +import org.onlab.onos.store.common.StoreService;
34 import org.onlab.onos.store.device.impl.DistributedDeviceStore; 34 import org.onlab.onos.store.device.impl.DistributedDeviceStore;
35 import org.onlab.onos.store.impl.StoreManager; 35 import org.onlab.onos.store.impl.StoreManager;
36 36
......
...@@ -12,7 +12,9 @@ import org.apache.felix.scr.annotations.Activate; ...@@ -12,7 +12,9 @@ import org.apache.felix.scr.annotations.Activate;
12 import org.apache.felix.scr.annotations.Component; 12 import org.apache.felix.scr.annotations.Component;
13 import org.apache.felix.scr.annotations.Deactivate; 13 import org.apache.felix.scr.annotations.Deactivate;
14 import org.apache.felix.scr.annotations.Service; 14 import org.apache.felix.scr.annotations.Service;
15 +import org.onlab.onos.cluster.ClusterEvent;
15 import org.onlab.onos.cluster.ClusterStore; 16 import org.onlab.onos.cluster.ClusterStore;
17 +import org.onlab.onos.cluster.ClusterStoreDelegate;
16 import org.onlab.onos.cluster.ControllerNode; 18 import org.onlab.onos.cluster.ControllerNode;
17 import org.onlab.onos.cluster.DefaultControllerNode; 19 import org.onlab.onos.cluster.DefaultControllerNode;
18 import org.onlab.onos.cluster.NodeId; 20 import org.onlab.onos.cluster.NodeId;
...@@ -26,6 +28,8 @@ import java.util.Set; ...@@ -26,6 +28,8 @@ import java.util.Set;
26 import java.util.concurrent.ConcurrentHashMap; 28 import java.util.concurrent.ConcurrentHashMap;
27 29
28 import static com.google.common.cache.CacheBuilder.newBuilder; 30 import static com.google.common.cache.CacheBuilder.newBuilder;
31 +import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_ACTIVATED;
32 +import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_DEACTIVATED;
29 import static org.onlab.onos.cluster.ControllerNode.State; 33 import static org.onlab.onos.cluster.ControllerNode.State;
30 34
31 /** 35 /**
...@@ -33,14 +37,15 @@ import static org.onlab.onos.cluster.ControllerNode.State; ...@@ -33,14 +37,15 @@ import static org.onlab.onos.cluster.ControllerNode.State;
33 */ 37 */
34 @Component(immediate = true) 38 @Component(immediate = true)
35 @Service 39 @Service
36 -public class DistributedClusterStore extends AbstractDistributedStore 40 +public class DistributedClusterStore
41 + extends AbstractDistributedStore<ClusterEvent, ClusterStoreDelegate>
37 implements ClusterStore { 42 implements ClusterStore {
38 43
39 private IMap<byte[], byte[]> rawNodes; 44 private IMap<byte[], byte[]> rawNodes;
40 private LoadingCache<NodeId, Optional<DefaultControllerNode>> nodes; 45 private LoadingCache<NodeId, Optional<DefaultControllerNode>> nodes;
41 46
42 private String listenerId; 47 private String listenerId;
43 - private final MembershipListener listener = new InnerMembershipListener(); 48 + private final MembershipListener listener = new InternalMembershipListener();
44 private final Map<NodeId, State> states = new ConcurrentHashMap<>(); 49 private final Map<NodeId, State> states = new ConcurrentHashMap<>();
45 50
46 @Activate 51 @Activate
...@@ -106,11 +111,12 @@ public class DistributedClusterStore extends AbstractDistributedStore ...@@ -106,11 +111,12 @@ public class DistributedClusterStore extends AbstractDistributedStore
106 } 111 }
107 112
108 // Adds a new node based on the specified member 113 // Adds a new node based on the specified member
109 - private synchronized void addMember(Member member) { 114 + private synchronized ControllerNode addMember(Member member) {
110 DefaultControllerNode node = node(member); 115 DefaultControllerNode node = node(member);
111 rawNodes.put(serialize(node.id()), serialize(node)); 116 rawNodes.put(serialize(node.id()), serialize(node));
112 nodes.put(node.id(), Optional.of(node)); 117 nodes.put(node.id(), Optional.of(node));
113 states.put(node.id(), State.ACTIVE); 118 states.put(node.id(), State.ACTIVE);
119 + return node;
114 } 120 }
115 121
116 // Creates a controller node descriptor from the Hazelcast member. 122 // Creates a controller node descriptor from the Hazelcast member.
...@@ -125,18 +131,20 @@ public class DistributedClusterStore extends AbstractDistributedStore ...@@ -125,18 +131,20 @@ public class DistributedClusterStore extends AbstractDistributedStore
125 } 131 }
126 132
127 // Interceptor for membership events. 133 // Interceptor for membership events.
128 - private class InnerMembershipListener implements MembershipListener { 134 + private class InternalMembershipListener implements MembershipListener {
129 @Override 135 @Override
130 public void memberAdded(MembershipEvent membershipEvent) { 136 public void memberAdded(MembershipEvent membershipEvent) {
131 log.info("Member {} added", membershipEvent.getMember()); 137 log.info("Member {} added", membershipEvent.getMember());
132 - addMember(membershipEvent.getMember()); 138 + ControllerNode node = addMember(membershipEvent.getMember());
139 + notifyDelegate(new ClusterEvent(INSTANCE_ACTIVATED, node));
133 } 140 }
134 141
135 @Override 142 @Override
136 public void memberRemoved(MembershipEvent membershipEvent) { 143 public void memberRemoved(MembershipEvent membershipEvent) {
137 log.info("Member {} removed", membershipEvent.getMember()); 144 log.info("Member {} removed", membershipEvent.getMember());
138 - states.put(new NodeId(memberAddress(membershipEvent.getMember()).toString()), 145 + NodeId nodeId = new NodeId(memberAddress(membershipEvent.getMember()).toString());
139 - State.INACTIVE); 146 + states.put(nodeId, State.INACTIVE);
147 + notifyDelegate(new ClusterEvent(INSTANCE_DEACTIVATED, getNode(nodeId)));
140 } 148 }
141 149
142 @Override 150 @Override
......
...@@ -13,6 +13,7 @@ import org.apache.felix.scr.annotations.Service; ...@@ -13,6 +13,7 @@ import org.apache.felix.scr.annotations.Service;
13 import org.onlab.onos.cluster.ClusterService; 13 import org.onlab.onos.cluster.ClusterService;
14 import org.onlab.onos.cluster.MastershipEvent; 14 import org.onlab.onos.cluster.MastershipEvent;
15 import org.onlab.onos.cluster.MastershipStore; 15 import org.onlab.onos.cluster.MastershipStore;
16 +import org.onlab.onos.cluster.MastershipStoreDelegate;
16 import org.onlab.onos.cluster.NodeId; 17 import org.onlab.onos.cluster.NodeId;
17 import org.onlab.onos.net.DeviceId; 18 import org.onlab.onos.net.DeviceId;
18 import org.onlab.onos.net.MastershipRole; 19 import org.onlab.onos.net.MastershipRole;
...@@ -31,7 +32,8 @@ import static com.google.common.cache.CacheBuilder.newBuilder; ...@@ -31,7 +32,8 @@ import static com.google.common.cache.CacheBuilder.newBuilder;
31 */ 32 */
32 @Component(immediate = true) 33 @Component(immediate = true)
33 @Service 34 @Service
34 -public class DistributedMastershipStore extends AbstractDistributedStore 35 +public class DistributedMastershipStore
36 + extends AbstractDistributedStore<MastershipEvent, MastershipStoreDelegate>
35 implements MastershipStore { 37 implements MastershipStore {
36 38
37 private IMap<byte[], byte[]> rawMasters; 39 private IMap<byte[], byte[]> rawMasters;
......
1 -package org.onlab.onos.store; 1 +package org.onlab.onos.store.common;
2 2
3 import com.hazelcast.core.HazelcastInstance; 3 import com.hazelcast.core.HazelcastInstance;
4 4
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
2 * Common abstractions and facilities for implementing distributed store 2 * Common abstractions and facilities for implementing distributed store
3 * using Hazelcast. 3 * using Hazelcast.
4 */ 4 */
5 -package org.onlab.onos.store; 5 +package org.onlab.onos.store.common;
......
...@@ -21,6 +21,7 @@ import org.onlab.onos.net.PortNumber; ...@@ -21,6 +21,7 @@ import org.onlab.onos.net.PortNumber;
21 import org.onlab.onos.net.device.DeviceDescription; 21 import org.onlab.onos.net.device.DeviceDescription;
22 import org.onlab.onos.net.device.DeviceEvent; 22 import org.onlab.onos.net.device.DeviceEvent;
23 import org.onlab.onos.net.device.DeviceStore; 23 import org.onlab.onos.net.device.DeviceStore;
24 +import org.onlab.onos.net.device.DeviceStoreDelegate;
24 import org.onlab.onos.net.device.PortDescription; 25 import org.onlab.onos.net.device.PortDescription;
25 import org.onlab.onos.net.provider.ProviderId; 26 import org.onlab.onos.net.provider.ProviderId;
26 import org.onlab.onos.store.impl.AbsentInvalidatingLoadingCache; 27 import org.onlab.onos.store.impl.AbsentInvalidatingLoadingCache;
...@@ -48,7 +49,8 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -48,7 +49,8 @@ import static org.slf4j.LoggerFactory.getLogger;
48 */ 49 */
49 @Component(immediate = true) 50 @Component(immediate = true)
50 @Service 51 @Service
51 -public class DistributedDeviceStore extends AbstractDistributedStore 52 +public class DistributedDeviceStore
53 + extends AbstractDistributedStore<DeviceEvent, DeviceStoreDelegate>
52 implements DeviceStore { 54 implements DeviceStore {
53 55
54 private final Logger log = getLogger(getClass()); 56 private final Logger log = getLogger(getClass());
......
...@@ -10,7 +10,10 @@ import org.apache.felix.scr.annotations.Activate; ...@@ -10,7 +10,10 @@ import org.apache.felix.scr.annotations.Activate;
10 import org.apache.felix.scr.annotations.Component; 10 import org.apache.felix.scr.annotations.Component;
11 import org.apache.felix.scr.annotations.Reference; 11 import org.apache.felix.scr.annotations.Reference;
12 import org.apache.felix.scr.annotations.ReferenceCardinality; 12 import org.apache.felix.scr.annotations.ReferenceCardinality;
13 -import org.onlab.onos.store.StoreService; 13 +import org.onlab.onos.event.Event;
14 +import org.onlab.onos.store.AbstractStore;
15 +import org.onlab.onos.store.StoreDelegate;
16 +import org.onlab.onos.store.common.StoreService;
14 import org.slf4j.Logger; 17 import org.slf4j.Logger;
15 18
16 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -20,7 +23,8 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -20,7 +23,8 @@ import static org.slf4j.LoggerFactory.getLogger;
20 * Abstraction of a distributed store based on Hazelcast. 23 * Abstraction of a distributed store based on Hazelcast.
21 */ 24 */
22 @Component(componentAbstract = true) 25 @Component(componentAbstract = true)
23 -public abstract class AbstractDistributedStore { 26 +public abstract class AbstractDistributedStore<E extends Event, D extends StoreDelegate<E>>
27 + extends AbstractStore<E, D> {
24 28
25 protected final Logger log = getLogger(getClass()); 29 protected final Logger log = getLogger(getClass());
26 30
......
...@@ -2,7 +2,7 @@ package org.onlab.onos.store.impl; ...@@ -2,7 +2,7 @@ package org.onlab.onos.store.impl;
2 2
3 import static com.google.common.base.Preconditions.checkNotNull; 3 import static com.google.common.base.Preconditions.checkNotNull;
4 4
5 -import org.onlab.onos.store.StoreService; 5 +import org.onlab.onos.store.common.StoreService;
6 6
7 import com.google.common.base.Optional; 7 import com.google.common.base.Optional;
8 import com.google.common.cache.CacheLoader; 8 import com.google.common.cache.CacheLoader;
......
...@@ -21,7 +21,7 @@ import org.onlab.onos.net.MastershipRole; ...@@ -21,7 +21,7 @@ import org.onlab.onos.net.MastershipRole;
21 import org.onlab.onos.net.Port; 21 import org.onlab.onos.net.Port;
22 import org.onlab.onos.net.PortNumber; 22 import org.onlab.onos.net.PortNumber;
23 import org.onlab.onos.net.provider.ProviderId; 23 import org.onlab.onos.net.provider.ProviderId;
24 -import org.onlab.onos.store.StoreService; 24 +import org.onlab.onos.store.common.StoreService;
25 import org.onlab.onos.store.serializers.DefaultPortSerializer; 25 import org.onlab.onos.store.serializers.DefaultPortSerializer;
26 import org.onlab.onos.store.serializers.DeviceIdSerializer; 26 import org.onlab.onos.store.serializers.DeviceIdSerializer;
27 import org.onlab.onos.store.serializers.IpPrefixSerializer; 27 import org.onlab.onos.store.serializers.IpPrefixSerializer;
......
...@@ -5,10 +5,13 @@ import org.apache.felix.scr.annotations.Activate; ...@@ -5,10 +5,13 @@ import org.apache.felix.scr.annotations.Activate;
5 import org.apache.felix.scr.annotations.Component; 5 import org.apache.felix.scr.annotations.Component;
6 import org.apache.felix.scr.annotations.Deactivate; 6 import org.apache.felix.scr.annotations.Deactivate;
7 import org.apache.felix.scr.annotations.Service; 7 import org.apache.felix.scr.annotations.Service;
8 +import org.onlab.onos.cluster.ClusterEvent;
8 import org.onlab.onos.cluster.ClusterStore; 9 import org.onlab.onos.cluster.ClusterStore;
10 +import org.onlab.onos.cluster.ClusterStoreDelegate;
9 import org.onlab.onos.cluster.ControllerNode; 11 import org.onlab.onos.cluster.ControllerNode;
10 import org.onlab.onos.cluster.DefaultControllerNode; 12 import org.onlab.onos.cluster.DefaultControllerNode;
11 import org.onlab.onos.cluster.NodeId; 13 import org.onlab.onos.cluster.NodeId;
14 +import org.onlab.onos.store.AbstractStore;
12 import org.onlab.packet.IpPrefix; 15 import org.onlab.packet.IpPrefix;
13 import org.slf4j.Logger; 16 import org.slf4j.Logger;
14 17
...@@ -22,7 +25,9 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -22,7 +25,9 @@ import static org.slf4j.LoggerFactory.getLogger;
22 */ 25 */
23 @Component(immediate = true) 26 @Component(immediate = true)
24 @Service 27 @Service
25 -public class SimpleClusterStore implements ClusterStore { 28 +public class SimpleClusterStore
29 + extends AbstractStore<ClusterEvent, ClusterStoreDelegate>
30 + implements ClusterStore {
26 31
27 public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1"); 32 public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
28 33
......
...@@ -97,11 +97,17 @@ ...@@ -97,11 +97,17 @@
97 <feature>onos-thirdparty-web</feature> 97 <feature>onos-thirdparty-web</feature>
98 <bundle>mvn:org.onlab.onos/onos-app-tvue/1.0.0-SNAPSHOT</bundle> 98 <bundle>mvn:org.onlab.onos/onos-app-tvue/1.0.0-SNAPSHOT</bundle>
99 </feature> 99 </feature>
100 - 100 +
101 <feature name="onos-app-fwd" version="1.0.0" 101 <feature name="onos-app-fwd" version="1.0.0"
102 description="ONOS sample forwarding application"> 102 description="ONOS sample forwarding application">
103 <feature>onos-api</feature> 103 <feature>onos-api</feature>
104 <bundle>mvn:org.onlab.onos/onos-app-fwd/1.0.0-SNAPSHOT</bundle> 104 <bundle>mvn:org.onlab.onos/onos-app-fwd/1.0.0-SNAPSHOT</bundle>
105 </feature> 105 </feature>
106 106
107 + <feature name="onos-app-foo" version="1.0.0"
108 + description="ONOS sample playground application">
109 + <feature>onos-api</feature>
110 + <bundle>mvn:org.onlab.onos/onos-app-foo/1.0.0-SNAPSHOT</bundle>
111 + </feature>
112 +
107 </features> 113 </features>
......
...@@ -51,7 +51,7 @@ perl -pi.old -e "s|^(featuresRepositories=.*)|\1,mvn:org.onlab.onos/onos-feature ...@@ -51,7 +51,7 @@ perl -pi.old -e "s|^(featuresRepositories=.*)|\1,mvn:org.onlab.onos/onos-feature
51 $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg 51 $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg
52 52
53 # Patch the Apache Karaf distribution file to load ONOS features 53 # Patch the Apache Karaf distribution file to load ONOS features
54 -perl -pi.old -e 's|^(featuresBoot=.*)|\1,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd|' \ 54 +perl -pi.old -e 's|^(featuresBoot=.*)|\1,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd,onos-app-foo|' \
55 $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg 55 $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg
56 56
57 # Patch the Apache Karaf distribution with ONOS branding bundle 57 # Patch the Apache Karaf distribution with ONOS branding bundle
......