Simon Hunt
Committed by Gerrit Code Review

UI topo model - Started fleshing out the UiSharedTopologyModel

 - marked model listeners in TopolgyViewMessageHandler as deprecated.
 - UiWebSocket now creates a (currently inert) UiTopoSession.

Change-Id: Ic385d782a2f56a90565ad744128f8e469678bcc7
......@@ -714,6 +714,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
// Cluster event listener.
// TODO: Superceded by UiSharedTopologyModel.ModelEventListener
@Deprecated
private class InternalClusterListener implements ClusterEventListener {
@Override
public void event(ClusterEvent event) {
......@@ -722,6 +724,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
// Mastership change listener
// TODO: Superceded by UiSharedTopologyModel.ModelEventListener
@Deprecated
private class InternalMastershipListener implements MastershipListener {
@Override
public void event(MastershipEvent event) {
......@@ -736,6 +740,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
// Device event listener.
// TODO: Superceded by UiSharedTopologyModel.ModelEventListener
@Deprecated
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
......@@ -748,6 +754,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
// Link event listener.
// TODO: Superceded by UiSharedTopologyModel.ModelEventListener
@Deprecated
private class InternalLinkListener implements LinkListener {
@Override
public void event(LinkEvent event) {
......@@ -758,6 +766,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
// Host event listener.
// TODO: Superceded by UiSharedTopologyModel.ModelEventListener
@Deprecated
private class InternalHostListener implements HostListener {
@Override
public void event(HostEvent event) {
......@@ -768,6 +778,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
// Intent event listener.
// TODO: Superceded by UiSharedTopologyModel.ModelEventListener
@Deprecated
private class InternalIntentListener implements IntentListener {
@Override
public void event(IntentEvent event) {
......@@ -777,6 +789,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
// Intent event listener.
// TODO: Superceded by UiSharedTopologyModel.ModelEventListener
@Deprecated
private class InternalFlowListener implements FlowRuleListener {
@Override
public void event(FlowRuleEvent event) {
......
......@@ -28,6 +28,7 @@ import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandlerFactory;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.UiTopoOverlayFactory;
import org.onosproject.ui.impl.topo.UiTopoSession;
import org.onosproject.ui.topo.TopoConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -37,7 +38,7 @@ import java.util.HashMap;
import java.util.Map;
/**
* Web socket capable of interacting with the GUI.
* Web socket capable of interacting with the Web UI.
*/
public class UiWebSocket
implements UiConnection, WebSocket.OnTextMessage, WebSocket.OnControl {
......@@ -50,14 +51,14 @@ public class UiWebSocket
private static final byte PONG = 0xA;
private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
private final ObjectMapper mapper = new ObjectMapper();
private final ServiceDirectory directory;
private final UiTopoSession topoSession;
private Connection connection;
private FrameConnection control;
private String userName;
private final ObjectMapper mapper = new ObjectMapper();
private long lastActive = System.currentTimeMillis();
private Map<String, UiMessageHandler> handlers;
......@@ -72,6 +73,7 @@ public class UiWebSocket
public UiWebSocket(ServiceDirectory directory, String userName) {
this.directory = directory;
this.userName = userName;
this.topoSession = new UiTopoSession(this);
}
@Override
......@@ -115,6 +117,7 @@ public class UiWebSocket
this.connection = connection;
this.control = (FrameConnection) connection;
try {
topoSession.init();
createHandlersAndOverlays();
sendInstanceData();
log.info("GUI client connected");
......@@ -129,6 +132,7 @@ public class UiWebSocket
@Override
public synchronized void onClose(int closeCode, String message) {
topoSession.destroy();
destroyHandlersAndOverlays();
log.info("GUI client disconnected [close-code={}, message={}]",
closeCode, message);
......
......@@ -36,31 +36,33 @@ import org.slf4j.LoggerFactory;
public class UiTopoSession {
private final Logger log = LoggerFactory.getLogger(getClass());
private final String username;
private final UiWebSocket webSocket;
private final UiSharedTopologyModel sharedModel;
private final String username;
final UiSharedTopologyModel sharedModel;
private boolean registered = false;
private UiTopoLayoutService service;
private UiTopoLayout layout;
private UiTopoLayout currentLayout;
/**
* Creates a new topology layout.
* @param username user name
* Creates a new topology session for the specified web socket connection.
*
* @param webSocket web socket
*/
public UiTopoSession(String username, UiWebSocket webSocket) {
this.username = username;
public UiTopoSession(UiWebSocket webSocket) {
this.webSocket = webSocket;
this.username = webSocket.userName();
this.sharedModel = UiSharedTopologyModel.instance();
}
/**
* Initializes the layout; registering with the shared model.
* Initializes the session; registering with the shared model.
*/
public void init() {
if (!registered) {
log.debug("{} : Registering with shared model", this);
sharedModel.register(this);
registered = true;
} else {
......@@ -69,10 +71,11 @@ public class UiTopoSession {
}
/**
* Destroys the layout; unregistering from the shared model.
* Destroys the session; unregistering from the shared model.
*/
public void destroy() {
if (!registered) {
if (registered) {
log.debug("{} : Unregistering from shared model", this);
sharedModel.unregister(this);
registered = false;
} else {
......
......@@ -16,10 +16,43 @@
package org.onosproject.ui.impl.topo.model;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
import org.onosproject.cluster.ClusterEvent;
import org.onosproject.cluster.ClusterEventListener;
import org.onosproject.cluster.ClusterService;
import org.onosproject.incubator.net.PortStatisticsService;
import org.onosproject.incubator.net.tunnel.TunnelService;
import org.onosproject.mastership.MastershipEvent;
import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.FlowRuleEvent;
import org.onosproject.net.flow.FlowRuleListener;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentListener;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.link.LinkEvent;
import org.onosproject.net.link.LinkListener;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.region.RegionEvent;
import org.onosproject.net.region.RegionListener;
import org.onosproject.net.region.RegionService;
import org.onosproject.net.statistic.StatisticService;
import org.onosproject.net.topology.TopologyService;
import org.onosproject.ui.impl.topo.UiTopoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
/**
* A lazily-initialized Singleton that creates and maintains the UI-model
* of the network topology.
......@@ -29,15 +62,17 @@ public final class UiSharedTopologyModel {
private static final Logger log =
LoggerFactory.getLogger(UiSharedTopologyModel.class);
private final ModelEventListener modelEventListener;
private UiSharedTopologyModel() {
// TODO: set up core model listeners and build the state of the model
}
private final Set<UiTopoSession> sessions = new HashSet<>();
// TODO: Note to Thomas (or others)..
// Don't we have a common pattern for adding/removing listeners and
// invoking them when things happen?
private UiSharedTopologyModel() {
modelEventListener = new ModelEventListener().init();
// TODO: build and maintain the state of the model
// (1) query model for current state
// (2) update state as model events arrive
}
/**
* Registers a UI topology session with the topology model.
......@@ -46,7 +81,7 @@ public final class UiSharedTopologyModel {
*/
public void register(UiTopoSession session) {
log.info("Registering topology session {}", session);
// TODO: register the session
sessions.add(session);
}
/**
......@@ -56,9 +91,123 @@ public final class UiSharedTopologyModel {
*/
public void unregister(UiTopoSession session) {
log.info("Unregistering topology session {}", session);
// TODO: unregister the session
sessions.remove(session);
}
// TODO: notify registered sessions when changes happen to the model
// ----------
// inner class to encapsulate the model listeners
private final class ModelEventListener {
// TODO: Review - is this good enough? couldn't otherwise see how to inject
private final ServiceDirectory directory = new DefaultServiceDirectory();
private ClusterService clusterService;
private MastershipService mastershipService;
private RegionService regionService;
private DeviceService deviceService;
private LinkService linkService;
private HostService hostService;
private IntentService intentService;
private FlowRuleService flowService;
private StatisticService flowStatsService;
private PortStatisticsService portStatsService;
private TopologyService topologyService;
private TunnelService tunnelService;
private ModelEventListener init() {
clusterService = directory.get(ClusterService.class);
mastershipService = directory.get(MastershipService.class);
regionService = directory.get(RegionService.class);
deviceService = directory.get(DeviceService.class);
linkService = directory.get(LinkService.class);
hostService = directory.get(HostService.class);
intentService = directory.get(IntentService.class);
flowService = directory.get(FlowRuleService.class);
// passive services (?) to whom we are not listening...
flowStatsService = directory.get(StatisticService.class);
portStatsService = directory.get(PortStatisticsService.class);
topologyService = directory.get(TopologyService.class);
tunnelService = directory.get(TunnelService.class);
return this;
}
private class InternalClusterListener implements ClusterEventListener {
@Override
public void event(ClusterEvent event) {
// TODO: handle cluster event
// (1) emit cluster member event
}
}
private class InternalMastershipListener implements MastershipListener {
@Override
public void event(MastershipEvent event) {
// TODO: handle mastership event
// (1) emit cluster member update for all members
// (2) emit update device event for he whose mastership changed
}
}
private class InternalRegionListener implements RegionListener {
@Override
public void event(RegionEvent event) {
// TODO: handle region event
// (1) emit region event
}
}
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
// TODO: handle device event
// (1) emit device event
}
}
private class InternalLinkListener implements LinkListener {
@Override
public void event(LinkEvent event) {
// TODO: handle link event
// (1) consolidate infrastructure links -> UiLink (?)
// (2) emit link event
}
}
private class InternalHostListener implements HostListener {
@Override
public void event(HostEvent event) {
// TODO: handle host event
// (1) emit host event
}
}
private class InternalIntentListener implements IntentListener {
@Override
public void event(IntentEvent event) {
// TODO: handle intent event
// (1) update cache of intent counts?
}
}
private class InternalFlowRuleListener implements FlowRuleListener {
@Override
public void event(FlowRuleEvent event) {
// TODO: handle flowrule event
// (1) update cache of flow counts?
}
}
}
// ----------
/**
* Bill Pugh Singleton pattern. INSTANCE won't be instantiated until the
* LazyHolder class is loaded via a call to the instance() method below.
......