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
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 f25ef91..602c66d 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 @@
     }
 
     // Cluster event listener.
+    // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
+    @Deprecated
     private class InternalClusterListener implements ClusterEventListener {
         @Override
         public void event(ClusterEvent event) {
@@ -722,6 +724,8 @@
     }
 
     // Mastership change listener
+    // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
+    @Deprecated
     private class InternalMastershipListener implements MastershipListener {
         @Override
         public void event(MastershipEvent event) {
@@ -736,6 +740,8 @@
     }
 
     // Device event listener.
+    // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
+    @Deprecated
     private class InternalDeviceListener implements DeviceListener {
         @Override
         public void event(DeviceEvent event) {
@@ -748,6 +754,8 @@
     }
 
     // Link event listener.
+    // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
+    @Deprecated
     private class InternalLinkListener implements LinkListener {
         @Override
         public void event(LinkEvent event) {
@@ -758,6 +766,8 @@
     }
 
     // Host event listener.
+    // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
+    @Deprecated
     private class InternalHostListener implements HostListener {
         @Override
         public void event(HostEvent event) {
@@ -768,6 +778,8 @@
     }
 
     // Intent event listener.
+    // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
+    @Deprecated
     private class InternalIntentListener implements IntentListener {
         @Override
         public void event(IntentEvent event) {
@@ -777,6 +789,8 @@
     }
 
     // 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 efe30843..4ddfc73 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.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.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 @@
     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 UiWebSocket(ServiceDirectory directory, String userName) {
         this.directory = directory;
         this.userName = userName;
+        this.topoSession = new UiTopoSession(this);
     }
 
     @Override
@@ -115,6 +117,7 @@
         this.connection = connection;
         this.control = (FrameConnection) connection;
         try {
+            topoSession.init();
             createHandlersAndOverlays();
             sendInstanceData();
             log.info("GUI client connected");
@@ -129,6 +132,7 @@
 
     @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 12e48f4..a6cd314 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 @@
 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 @@
     }
 
     /**
-     * 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 b9b5e8c..0688f45 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 @@
     private static final Logger log =
             LoggerFactory.getLogger(UiSharedTopologyModel.class);
 
+    private final ModelEventListener modelEventListener;
+
+    private final Set<UiTopoSession> 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 void register(UiTopoSession session) {
         log.info("Registering topology session {}", session);
-        // TODO: register the session
+        sessions.add(session);
     }
 
     /**
@@ -56,9 +91,123 @@
      */
     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.