diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java index f25ef918a8..602c66db03 100644 --- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java +++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java @@ -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) { diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java index efe30843d9..4ddfc739e7 100644 --- a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java +++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java @@ -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 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); diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java index 12e48f4529..a6cd314b3c 100644 --- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java +++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java @@ -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 { diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java index b9b5e8cff9..0688f45d2c 100644 --- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java +++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java @@ -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,16 +62,18 @@ public final class UiSharedTopologyModel { private static final Logger log = LoggerFactory.getLogger(UiSharedTopologyModel.class); + private final ModelEventListener modelEventListener; + + private final Set sessions = new HashSet<>(); private UiSharedTopologyModel() { - // TODO: set up core model listeners and build the state of the model + 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 } - // TODO: Note to Thomas (or others).. - // Don't we have a common pattern for adding/removing listeners and - // invoking them when things happen? - - /** * 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.