GUI -- Added port-statistics traffic visualization to the topo view.

Change-Id: I52b3c1739cc50a026c0796819d61ec1898937ced
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 ba34f8e..ec70531 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
@@ -92,7 +92,8 @@
     private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
     private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
     private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
-    private static final String REQ_ALL_TRAFFIC = "requestAllTraffic";
+    private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
+    private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
     private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
     private static final String CANCEL_TRAFFIC = "cancelTraffic";
     private static final String REQ_SUMMARY = "requestSummary";
@@ -187,7 +188,8 @@
                 new ReqNextIntent(),
                 new ReqPrevIntent(),
                 new ReqSelectedIntentTraffic(),
-                new ReqAllTraffic(),
+                new ReqAllFlowTraffic(),
+                new ReqAllPortTraffic(),
                 new ReqDevLinkFlows(),
                 new CancelTraffic()
         );
@@ -453,23 +455,33 @@
 
         @Override
         public void process(long sid, ObjectNode payload) {
-            trafficEvent =
-                    new TrafficEvent(TrafficEvent.Type.SEL_INTENT, payload);
+            trafficEvent = new TrafficEvent(TrafficEvent.Type.SEL_INTENT, payload);
             requestSelectedIntentTraffic();
             startTrafficMonitoring();
         }
     }
 
-    private final class ReqAllTraffic extends RequestHandler {
-        private ReqAllTraffic() {
-            super(REQ_ALL_TRAFFIC);
+    private final class ReqAllFlowTraffic extends RequestHandler {
+        private ReqAllFlowTraffic() {
+            super(REQ_ALL_FLOW_TRAFFIC);
         }
 
         @Override
         public void process(long sid, ObjectNode payload) {
-            trafficEvent =
-                    new TrafficEvent(TrafficEvent.Type.ALL_TRAFFIC, payload);
-            requestAllTraffic();
+            trafficEvent = new TrafficEvent(TrafficEvent.Type.ALL_FLOW_TRAFFIC, payload);
+            requestAllFlowTraffic();
+        }
+    }
+
+    private final class ReqAllPortTraffic extends RequestHandler {
+        private ReqAllPortTraffic() {
+            super(REQ_ALL_PORT_TRAFFIC);
+        }
+
+        @Override
+        public void process(long sid, ObjectNode payload) {
+            trafficEvent = new TrafficEvent(TrafficEvent.Type.ALL_PORT_TRAFFIC, payload);
+            requestAllPortTraffic();
         }
     }
 
@@ -480,8 +492,7 @@
 
         @Override
         public void process(long sid, ObjectNode payload) {
-            trafficEvent =
-                    new TrafficEvent(TrafficEvent.Type.DEV_LINK_FLOWS, payload);
+            trafficEvent = new TrafficEvent(TrafficEvent.Type.DEV_LINK_FLOWS, payload);
             requestDeviceLinkFlows(payload);
         }
     }
@@ -615,10 +626,16 @@
         }
     }
 
-    // Subscribes for host traffic messages.
-    private synchronized void requestAllTraffic() {
+    // Subscribes for flow traffic messages.
+    private synchronized void requestAllFlowTraffic() {
         startTrafficMonitoring();
-        sendMessage(trafficSummaryMessage());
+        sendMessage(trafficSummaryMessage(StatsType.FLOW));
+    }
+
+    // Subscribes for port traffic messages.
+    private synchronized void requestAllPortTraffic() {
+        startTrafficMonitoring();
+        sendMessage(trafficSummaryMessage(StatsType.PORT));
     }
 
     private void requestDeviceLinkFlows(ObjectNode payload) {
@@ -822,7 +839,7 @@
     // encapsulate
     private static class TrafficEvent {
         enum Type {
-            ALL_TRAFFIC, DEV_LINK_FLOWS, SEL_INTENT
+            ALL_FLOW_TRAFFIC, ALL_PORT_TRAFFIC, DEV_LINK_FLOWS, SEL_INTENT
         }
 
         private final Type type;
@@ -841,8 +858,11 @@
             try {
                 if (trafficEvent != null) {
                     switch (trafficEvent.type) {
-                        case ALL_TRAFFIC:
-                            requestAllTraffic();
+                        case ALL_FLOW_TRAFFIC:
+                            requestAllFlowTraffic();
+                            break;
+                        case ALL_PORT_TRAFFIC:
+                            requestAllPortTraffic();
                             break;
                         case DEV_LINK_FLOWS:
                             requestDeviceLinkFlows(trafficEvent.payload);
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index c7ebf35..71eb1fc 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -27,6 +27,7 @@
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.PortStatisticsService;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.Annotated;
 import org.onosproject.net.AnnotationKeys;
@@ -100,6 +101,7 @@
 import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
 import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
 import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
+import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.*;
 
 /**
  * Facility for creating messages bound for the topology viewer.
@@ -123,6 +125,8 @@
     private static final String KB_UNIT = "KB";
     private static final String B_UNIT = "B";
 
+    private static final long BPS_THRESHOLD = 1024;
+
     protected ServiceDirectory directory;
     protected ClusterService clusterService;
     protected DeviceService deviceService;
@@ -131,9 +135,14 @@
     protected MastershipService mastershipService;
     protected IntentService intentService;
     protected FlowRuleService flowService;
-    protected StatisticService statService;
+    protected StatisticService flowStatsService;
+    protected PortStatisticsService portStatsService;
     protected TopologyService topologyService;
 
+    protected enum StatsType {
+        FLOW, PORT
+    }
+
     private String version;
 
     // TODO: extract into an external & durable state; good enough for now and demo
@@ -159,7 +168,8 @@
         mastershipService = directory.get(MastershipService.class);
         intentService = directory.get(IntentService.class);
         flowService = directory.get(FlowRuleService.class);
-        statService = directory.get(StatisticService.class);
+        flowStatsService = directory.get(StatisticService.class);
+        portStatsService = directory.get(PortStatisticsService.class);
         topologyService = directory.get(TopologyService.class);
 
         String ver = directory.get(CoreService.class).version().toString();
@@ -532,8 +542,8 @@
     }
 
 
-    // Produces JSON message to trigger traffic overview visualization
-    protected ObjectNode trafficSummaryMessage() {
+    // Produces JSON message to trigger flow traffic overview visualization
+    protected ObjectNode trafficSummaryMessage(StatsType type) {
         ObjectNode payload = objectNode();
         ArrayNode paths = arrayNode();
         payload.set("paths", paths);
@@ -560,11 +570,18 @@
             boolean bi = link.two != null;
             if (isInfrastructureEgress(link.one) ||
                     (bi && isInfrastructureEgress(link.two))) {
-                link.addLoad(statService.load(link.one));
-                link.addLoad(bi ? statService.load(link.two) : null);
+                if (type == FLOW) {
+                    link.addLoad(flowStatsService.load(link.one));
+                    link.addLoad(bi ? flowStatsService.load(link.two) : null);
+                } else if (type == PORT) {
+                    link.addLoad(portStatsService.load(link.one.src()), BPS_THRESHOLD);
+                    link.addLoad(bi ? portStatsService.load(link.two.src()) : null, BPS_THRESHOLD);
+                }
                 if (link.hasTraffic) {
                     linksNodeT.add(compactLinkString(link.one));
-                    labelsT.add(formatBytes(link.bytes));
+                    labelsT.add(type == PORT ?
+                                        formatBytes(link.rate) + "ps" :
+                                        formatBytes(link.bytes));
                 } else {
                     linksNodeN.add(compactLinkString(link.one));
                     labelsN.add("");
@@ -692,7 +709,7 @@
                 BiLink biLink = addLink(biLinks, link);
                 if (isInfrastructureEgress(link)) {
                     if (showTraffic) {
-                        biLink.addLoad(statService.load(link));
+                        biLink.addLoad(flowStatsService.load(link));
                     }
                     biLink.addClass(type);
                 }
@@ -727,7 +744,7 @@
             for (Link link : links) {
                 if (isInfrastructureEgress(link)) {
                     linksNode.add(compactLinkString(link));
-                    Load load = statService.load(link);
+                    Load load = flowStatsService.load(link);
                     String label = "";
                     if (load.rate() > 0) {
                         hasTraffic = true;
@@ -814,6 +831,7 @@
         public long bytes = 0;
 
         private Set<String> classes = new HashSet<>();
+        private long rate;
 
         BiLink(LinkKey key, Link link) {
             this.key = key;
@@ -825,9 +843,14 @@
         }
 
         void addLoad(Load load) {
+            addLoad(load, 0);
+        }
+
+        void addLoad(Load load, long threshold) {
             if (load != null) {
-                this.hasTraffic = hasTraffic || load.rate() > 0;
+                this.hasTraffic = hasTraffic || load.rate() > threshold;
                 this.bytes += load.latest();
+                this.rate = load.rate();
             }
         }
 
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js
index 02a7fca..388e246 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -67,7 +67,8 @@
             rightArrow: [tts.showNextIntentAction, 'Show next related intent'],
             leftArrow: [tts.showPrevIntentAction, 'Show previous related intent'],
             W: [tts.showSelectedIntentTrafficAction, 'Monitor traffic of selected intent'],
-            A: [tts.showAllTrafficAction, 'Monitor all traffic'],
+            A: [tts.showAllFlowTrafficAction, 'Monitor all traffic using flow stats'],
+            Q: [tts.showAllPortTrafficAction, 'Monitor all traffic using port stats'],
             F: [tts.showDeviceLinkFlowsAction, 'Show device link flows'],
 
             E: [equalizeMasters, 'Equalize mastership roles'],
diff --git a/web/gui/src/main/webapp/app/view/topo/topoTraffic.js b/web/gui/src/main/webapp/app/view/topo/topoTraffic.js
index ab38e56..0ed005e 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoTraffic.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoTraffic.js
@@ -150,10 +150,17 @@
     }
 
     // keystroke-A (see topo.js)
-    function showAllTrafficAction() {
+    function showAllFlowTrafficAction() {
         hoverMode = hoverModeAll;
-        wss.sendEvent('requestAllTraffic');
-        flash.flash('All Traffic');
+        wss.sendEvent('requestAllFlowTraffic');
+        flash.flash('All Flow Traffic');
+    }
+
+    // keystroke-A (see topo.js)
+    function showAllPortTrafficAction() {
+        hoverMode = hoverModeAll;
+        wss.sendEvent('requestAllPortTraffic');
+        flash.flash('All Port Traffic');
     }
 
     // === -----------------------------
@@ -228,7 +235,8 @@
                 showNextIntentAction: showNextIntentAction,
                 showPrevIntentAction: showPrevIntentAction,
                 showSelectedIntentTrafficAction: showSelectedIntentTrafficAction,
-                showAllTrafficAction: showAllTrafficAction
+                showAllFlowTrafficAction: showAllFlowTrafficAction,
+                showAllPortTrafficAction: showAllPortTrafficAction
             };
         }]);
 }());
diff --git a/web/pom.xml b/web/pom.xml
index 8b7fb63..cd67885 100644
--- a/web/pom.xml
+++ b/web/pom.xml
@@ -48,6 +48,11 @@
 
         <dependency>
             <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
             <artifactId>onlab-osgi</artifactId>
             <version>${project.version}</version>
         </dependency>