...
We are also going to need a couple interfaces that will be needed by the listeners and the and the delegates. The listeners are components which have registered to obtain events from this service, these are usually local. A delegate is a neighbouring manager which is receiving events from a neighbouring store for the purpose of either taking action on the store event or notifying listeners. So we are going to add NetworkListener.
...
And since we changed the interface of the Store we will have to add something to the implementations, namely SimpleNetworkStore. This abstract class is used to define the methods for posting event to its delegates.
Code Block |
---|
public class SimpleNetworkStore extends AbstractStore<NetworkEvent, NetworkStoreDelegate> |
...
Alright so now that the stores emit events the managers should be made to receive them. For this we are going to have to add a reference on the EventDeliveryService an AbstractListenerRegistry to keep track of listeners and NetworkStoreDelegate as shown in the code snippet below.
Code Block | |
---|---|
|
| |
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected EventDeliveryService eventDispatcher;
private ApplicationId appId;
private final AbstractListenerRegistry<NetworkEvent, NetworkListener>
listenerRegistry = new AbstractListenerRegistry<>();
private final NetworkStoreDelegate delegate = new InternalStoreDelegate();
|
Then we need to add a couple lines in the activate in order to register our Event type for our listeners and set our delegate.
Code Block |
---|
eventDispatcher.addSink(NetworkEvent.class, listenerRegistry);
store.setDelegate(delegate);
|
and vice versa deactivate
Code Block |
---|
eventDispatcher.removeSink(NetworkEvent.class);
store.unsetDelegate(delegate); |
Finally add the methods to add listeners and dispatch events coming from the store:
Code Block | ||
---|---|---|
| ||
@Override
public void addListener(NetworkListener listener) {
listenerRegistry.addListener(listener);
}
@Override
public void removeListener(NetworkListener listener) {
listenerRegistry.removeListener(listener);
}
private class InternalStoreDelegate implements NetworkStoreDelegate {
@Override
public void notify(NetworkEvent event) {
eventDispatcher.post(event);
}
} |
To test this you will need to complete the extra credit section .
Part 5: Distributed Store
So we can finally start implementing DistributedStore. To this start by disabling your SimpleNetworkStore:
Code Block |
---|
@Component(immediate = false, enabled = false)
@Service
public class SimpleNetworkStore |
Then copy the contents of the SimpleNetworkStore to a new file called DistributedNetworkStore (surprise!). First start by striping all the events that you generate in the methods of the store. These will be generated by the Remote Listener. Start by adding the Remote Listener to the distributed store class as an internal class.
Code Block | ||
---|---|---|
| ||
private class RemoteListener extends EntryAdapter<String, Set<HostId>> {
@Override
public void entryAdded(EntryEvent<String, Set<HostId>> event) {
notifyDelegate(new NetworkEvent(NETWORK_ADDED, event.getKey()));
}
@Override
public void entryUpdated(EntryEvent<String, Set<HostId>> event) {
notifyDelegate(new NetworkEvent(NETWORK_UPDATED, event.getKey()));
}
@Override
public void entryRemoved(EntryEvent<String, Set<HostId>> event) {
notifyDelegate(new NetworkEvent(NETWORK_REMOVED, event.getKey()));
}
} |
Replace your maps, activate and deactivate methods by the following code snippet:
Code Block | ||
---|---|---|
| ||
private SMap<String, Set<HostId>> networks;
private SMap<String, Set<Intent>> intentsPerNet;
private String listenerId;
@Activate
public void activate() {
super.activate();
networks = new SMap<>(theInstance.<byte[], byte[]>getMap("byon-networks"), this.serializer);
intentsPerNet = new SMap<>(theInstance.<byte[], byte[]>getMap("byon-network-intents"), this.serializer);
EntryListener<String, Set<HostId>> listener = new RemoteListener();
listenerId = networks.addEntryListener(listener, true);
log.info("Started");
}
@Deactivate
public void deactivate() {
networks.removeEntryListener(listenerId);
log.info("Stopped");
}
|
Verify your implementation
You can do this by recompiling, deploying, and launching another console to a second onos instance:
Code Block |
---|
distributed@mininet-vm:~/ $ onos $OC2 |
When you add and remove networks and/or hosts you should see this being reflected on the other ONOS instances.
Part 6: Event Listener
We can create the byon application using a Maven archetype:
Code Block |
---|
distributed@mininet-vm:~/onos-byon/ $ mvn archetype:generate -DarchetypeGroupId=org.onosproject -DarchetypeArtifactId=onos-bundle-archetype -DarchetypeVersion=1.0.0p1 |
Make sure you are in the onos-byon directory
When prompted for the groupId, enter org.onos.byon. When prompted for the artifactId, enter byon-monitor. The remaining fields can the default values that maven suggests.
This will create a directory called byon-monitor that contains a pom.xml file as well as some starter Java files. Let's delete the "test" subtree for now.<w
Info |
---|
IntelliJ should detect the new module and ask you to import the changes but if it does not then right click on the top-level project, select Maven followed by re-import. |
Open the pom.xml in the byon-monitor module and add the following snippet to the bottom of the dependencies block: (can either be done in IntelliJ or by hand)
Code Block |
---|
<dependency>
<groupId>org.onos.byon</groupId>
<artifactId>byon-app</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> |
The archetype comes with a file called AppComponent.java. Refactor this class and call it NetworkEventMonitor. And add the following code to it.
Code Block |
---|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkService service;
private final Listener listener = new Listener();
@Activate
protected void activate() {
service.addListener(listener);
log.info("Started");
}
@Deactivate
protected void deactivate() {
service.removeListener(listener);
log.info("Stopped");
}
private class Listener implements NetworkListener {
@Override
public void event(NetworkEvent event) {
log.info("{}", event);
}
} |
Then update the bundles line in byon-push-bits:
Code Block |
---|
bundles="byon-app byon-cli byon-monitor" |
Verify what you built
So once again recompile and redeploy byon by using the byon-push-bits command.
When you add a network you should see the following line in the ONOS log. You can get the ONOS log by running:
Code Block |
---|
distributed@mininet-vm:~/ $ ol |
And you should see a line that look like:
Code Block |
---|
INFO | event-dispatch-0 | NetworkEventMonitor | 187 - org.onos.byon.monitor - 1.0.0.SNAPSHOT | NetworkEvent{time=<time&date>, type=NETWORK_ADDED, subject=test} |
Conclusion
You have learned how to develop an ONOS distributed application on ONOS.