GUI - Topologies - refactoring of ServicesBundle.
Jira: ONOS-6259
 - also fixed bug where edge links were being omitted.

Change-Id: I19ac83d09ce7930de7a927fb2754e0c5004705f2
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitorBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitorBase.java
new file mode 100644
index 0000000..dfedaf3
--- /dev/null
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitorBase.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.onosproject.ui.impl;
+
+import org.onosproject.ui.impl.topo.util.ServicesBundle;
+import org.onosproject.ui.topo.AbstractTopoMonitor;
+import org.onosproject.ui.topo.TopoUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.IDLE;
+
+/**
+ * Base superclass for traffic monitor (both 'classic' and 'topo2' versions).
+ */
+public abstract class TrafficMonitorBase extends AbstractTopoMonitor {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    // 4 Kilo Bytes as threshold
+    static final double BPS_THRESHOLD = 4 * TopoUtils.N_KILO;
+
+
+    /**
+     * Designates the different modes of operation.
+     */
+    public enum Mode {
+        IDLE,
+        ALL_FLOW_TRAFFIC_BYTES,
+        ALL_PORT_TRAFFIC_BIT_PS,
+        ALL_PORT_TRAFFIC_PKT_PS,
+        DEV_LINK_FLOWS,
+        RELATED_INTENTS,
+        SELECTED_INTENT
+    }
+
+    /**
+     * Number of milliseconds between invocations of sending traffic data.
+     */
+    protected final long trafficPeriod;
+
+    /**
+     * Holds references to services.
+     */
+    protected final ServicesBundle services;
+
+    /**
+     * Current operating mode.
+     */
+    protected Mode mode = Mode.IDLE;
+
+    private final Timer timer;
+    private TimerTask trafficTask = null;
+
+    /**
+     * Constructs the monitor, initializing the task period and
+     * services bundle reference.
+     *
+     * @param trafficPeriod  traffic task period in ms
+     * @param servicesBundle bundle of services
+     */
+    protected TrafficMonitorBase(long trafficPeriod,
+                                 ServicesBundle servicesBundle) {
+        this.trafficPeriod = trafficPeriod;
+        this.services = servicesBundle;
+        timer = new Timer("uiTopo-" + getClass().getSimpleName());
+    }
+
+    /**
+     * Initiates monitoring of traffic for a given mode.
+     * This causes a background traffic task to be
+     * scheduled to repeatedly compute and transmit the appropriate traffic
+     * data to the client.
+     * <p>
+     * The monitoring mode is expected to be one of:
+     * <ul>
+     * <li>ALL_FLOW_TRAFFIC_BYTES</li>
+     * <li>ALL_PORT_TRAFFIC_BIT_PS</li>
+     * <li>ALL_PORT_TRAFFIC_PKT_PS</li>
+     * <li>SELECTED_INTENT</li>
+     * </ul>
+     *
+     * @param mode the monitoring mode
+     */
+    public synchronized void monitor(Mode mode) {
+        this.mode = mode;
+
+        switch (mode) {
+
+            case ALL_FLOW_TRAFFIC_BYTES:
+                clearSelection();
+                scheduleTask();
+                sendAllFlowTraffic();
+                break;
+
+            case ALL_PORT_TRAFFIC_BIT_PS:
+                clearSelection();
+                scheduleTask();
+                sendAllPortTrafficBits();
+                break;
+
+            case ALL_PORT_TRAFFIC_PKT_PS:
+                clearSelection();
+                scheduleTask();
+                sendAllPortTrafficPackets();
+                break;
+
+            case SELECTED_INTENT:
+                sendSelectedIntentTraffic();
+                scheduleTask();
+                break;
+
+            default:
+                log.warn("Unexpected call to monitor({})", mode);
+                clearAll();
+                break;
+        }
+    }
+
+    /**
+     * Subclass should compile and send appropriate highlights data showing
+     * flow traffic (bytes on links).
+     */
+    protected abstract void sendAllFlowTraffic();
+
+    /**
+     * Subclass should compile and send appropriate highlights data showing
+     * bits per second, as computed using port stats.
+     */
+    protected abstract void sendAllPortTrafficBits();
+
+    /**
+     * Subclass should compile and send appropriate highlights data showing
+     * packets per second, as computed using port stats.
+     */
+    protected abstract void sendAllPortTrafficPackets();
+
+    /**
+     * Subclass should compile and send appropriate highlights data showing
+     * number of flows traversing links for the "selected" device(s).
+     */
+    protected abstract void sendDeviceLinkFlows();
+
+    /**
+     * Subclass should compile and send appropriate highlights data showing
+     * traffic traversing links for the "selected" intent.
+     */
+    protected abstract void sendSelectedIntentTraffic();
+
+    /**
+     * Subclass should send a "clear highlights" event.
+     */
+    protected abstract void sendClearHighlights();
+
+    /**
+     * Subclasses should clear any selection state.
+     */
+    protected abstract void clearSelection();
+
+    /**
+     * Sets the mode to IDLE, clears the selection, cancels the background
+     * task, and sends a clear highlights event to the client.
+     */
+    protected void clearAll() {
+        this.mode = Mode.IDLE;
+        clearSelection();
+        cancelTask();
+        sendClearHighlights();
+    }
+
+    /**
+     * Schedules the background monitor task to run.
+     */
+    protected synchronized void scheduleTask() {
+        if (trafficTask == null) {
+            log.debug("Starting up background traffic task...");
+            trafficTask = new TrafficUpdateTask();
+            timer.schedule(trafficTask, trafficPeriod, trafficPeriod);
+        } else {
+            log.debug("(traffic task already running)");
+        }
+    }
+
+    /**
+     * Cancels the background monitor task.
+     */
+    protected synchronized void cancelTask() {
+        if (trafficTask != null) {
+            trafficTask.cancel();
+            trafficTask = null;
+        }
+    }
+
+    /**
+     * Stops monitoring. (Invokes {@link #clearAll}, if not idle).
+     */
+    public synchronized void stopMonitoring() {
+        log.debug("STOP monitoring");
+        if (mode != IDLE) {
+            clearAll();
+        }
+    }
+
+
+    // =======================================================================
+    // === Background Task
+
+    // Provides periodic update of traffic information to the client
+    private class TrafficUpdateTask extends TimerTask {
+        @Override
+        public void run() {
+            try {
+                switch (mode) {
+                    case ALL_FLOW_TRAFFIC_BYTES:
+                        sendAllFlowTraffic();
+                        break;
+                    case ALL_PORT_TRAFFIC_BIT_PS:
+                        sendAllPortTrafficBits();
+                        break;
+                    case ALL_PORT_TRAFFIC_PKT_PS:
+                        sendAllPortTrafficPackets();
+                        break;
+                    case DEV_LINK_FLOWS:
+                        sendDeviceLinkFlows();
+                        break;
+                    case SELECTED_INTENT:
+                        sendSelectedIntentTraffic();
+                        break;
+
+                    default:
+                        // RELATED_INTENTS and IDLE modes should never invoke
+                        // the background task, but if they do, they have
+                        // nothing to do
+                        break;
+                }
+
+            } catch (Exception e) {
+                log.warn("Unable to process traffic task due to {}", e.getMessage());
+                log.warn("Boom!", e);
+            }
+        }
+    }
+
+}