GUI -- Further work on refactoring Topology View server side code. Still WIP...
- added topology client heartbeat.
- modified AbstractListenerRegistry to allow for extension.

Change-Id: Ib8ea6ad4ba34f5732d062f1c9ef545f105eb167b
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/AltTopoViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/AltTopoViewMessageHandler.java
index fc16133..935141d 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/AltTopoViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/AltTopoViewMessageHandler.java
@@ -41,6 +41,7 @@
 import java.util.Map;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.System.currentTimeMillis;
 import static org.onosproject.ui.impl.topo.TopoUiEvent.Type.SUMMARY_UPDATE;
 
 /**
@@ -51,6 +52,7 @@
             implements OverlayService {
 
     private static final String TOPO_START = "topoStart";
+    private static final String TOPO_HEARTBEAT = "topoHeartbeat";
     private static final String TOPO_STOP = "topoStop";
     private static final String REQ_SUMMARY = "requestSummary";
     private static final String CANCEL_SUMMARY = "cancelSummary";
@@ -60,7 +62,7 @@
     protected ServiceDirectory directory;
     protected TopoUiModelService modelService;
 
-    private TopoUiListener modelListener;
+    private ModelListener modelListener;
     private String version;
     private SummaryGenerator defaultSummaryGenerator;
     private SummaryGenerator currentSummaryGenerator;
@@ -83,22 +85,17 @@
 
     @Override
     public void destroy() {
-//        cancelAllMonitoring();
-//        stopListeningToModel();
+        cancelAllMonitoring();
+        stopListeningToModel();
         super.destroy();
     }
 
 
-    private String getVersion() {
-        String ver = directory.get(CoreService.class).version().toString();
-        return ver.replace(".SNAPSHOT", "*").replaceFirst("~.*$", "");
-    }
-
-
     @Override
     protected Collection<RequestHandler> createRequestHandlers() {
         return ImmutableSet.of(
                 new TopoStart(),
+                new TopoHeartbeat(),
                 new TopoStop(),
                 new ReqSummary(),
                 new CancelSummary()
@@ -107,6 +104,27 @@
     }
 
     // =====================================================================
+
+    private void cancelAllMonitoring() {
+        // TODO:
+    }
+
+    private void startListeningToModel() {
+        topoActive = true;
+        modelService.addListener(modelListener);
+    }
+
+    private void stopListeningToModel() {
+        topoActive = false;
+        modelService.removeListener(modelListener);
+    }
+
+    private String getVersion() {
+        String ver = directory.get(CoreService.class).version().toString();
+        return ver.replace(".SNAPSHOT", "*").replaceFirst("~.*$", "");
+    }
+
+    // =====================================================================
     // Overlay Service
     // TODO: figure out how we are going to switch overlays in and out...
 
@@ -136,12 +154,21 @@
 
         @Override
         public void process(long sid, ObjectNode payload) {
-            topoActive = true;
-            modelService.addListener(modelListener);
+            startListeningToModel();
             sendMessages(modelService.getInitialState());
         }
     }
 
+    private final class TopoHeartbeat extends RequestHandler {
+        private TopoHeartbeat() {
+            super(TOPO_HEARTBEAT);
+        }
+        @Override
+        public void process(long sid, ObjectNode payload) {
+            modelListener.nudge();
+        }
+    }
+
     private final class TopoStop extends RequestHandler {
         private TopoStop() {
             super(TOPO_STOP);
@@ -149,8 +176,7 @@
 
         @Override
         public void process(long sid, ObjectNode payload) {
-            topoActive = false;
-            modelService.removeListener(modelListener);
+            stopListeningToModel();
         }
     }
 
@@ -227,6 +253,10 @@
     // Our listener for model events so we can push changes out to the UI...
 
     private class ModelListener implements TopoUiListener {
+        private static final long AWAKE_THRESHOLD_MS = 6000;
+
+        private long lastNudged = currentTimeMillis();
+
         @Override
         public void event(TopoUiEvent event) {
             log.debug("Handle Event: {}", event);
@@ -238,6 +268,15 @@
             }
             handler.handleEvent(event);
         }
+
+        @Override
+        public boolean isAwake() {
+            return currentTimeMillis() - lastNudged < AWAKE_THRESHOLD_MS;
+        }
+
+        public void nudge() {
+            lastNudged = currentTimeMillis();
+        }
     }
 
 
@@ -271,5 +310,4 @@
         eventHandlerBinding.put(SUMMARY_UPDATE, summaryHandler);
         // NOTE: no need to bind pass-thru handlers
     }
-
 }