Additional monitoring stats in server driver

This patch also performs some refactoring to make the
JSON parameters exchanged between the driver and the device
homogeneous (i.e., following the [a-z][A-Z]* pattern).

Code reviewed and minor refactoring.
Avoid exception when timing statistics are not present.
Handle device re-connections.
Server also reports a hardware queue index per core.

Addressed code reviewer's comments.

Change-Id: I6c9d0bbd5884267ee2fdb69bf50809694994c56d
Signed-off-by: Georgios Katsikas <katsikas.gp@gmail.com>
diff --git a/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultCpuStatistics.java b/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultCpuStatistics.java
index f9c1989..2f5305d 100644
--- a/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultCpuStatistics.java
+++ b/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultCpuStatistics.java
@@ -17,10 +17,15 @@
 package org.onosproject.drivers.server.impl.stats;
 
 import org.onosproject.drivers.server.stats.CpuStatistics;
+import org.onosproject.drivers.server.stats.MonitoringUnit;
 
 import org.onosproject.net.DeviceId;
 import com.google.common.base.MoreObjects;
 
+import java.util.Optional;
+
+import static org.onosproject.drivers.server.stats.MonitoringUnit.LatencyUnit;
+import static org.onosproject.drivers.server.stats.MonitoringUnit.ThroughputUnit;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkArgument;
 
@@ -32,6 +37,9 @@
     private static final float MIN_CPU_LOAD = (float) 0.0;
     private static final float MAX_CPU_LOAD = (float) 1.0;
 
+    private static final LatencyUnit DEF_LATENCY_UNIT = LatencyUnit.NANO_SECOND;
+    private static final ThroughputUnit DEF_THROUGHPUT_UNIT = ThroughputUnit.MBPS;
+
     // Upper limit of CPU cores in one machine
     public static final int MAX_CPU_NB = 512;
 
@@ -39,27 +47,46 @@
 
     private final int id;
     private final float load;
+    private final int queue;
     private final boolean isBusy;
+    private final Optional<MonitoringUnit> throughputUnit;
+    private final Optional<Float> averageThroughput;
+    private final Optional<MonitoringUnit> latencyUnit;
+    private final Optional<Float> minLatency;
+    private final Optional<Float> medianLatency;
+    private final Optional<Float> maxLatency;
 
-    private DefaultCpuStatistics(
-            DeviceId deviceId,
-            int      id,
-            float    load,
-            boolean  isBusy) {
+    private DefaultCpuStatistics(DeviceId deviceId, int id, float load, int queue, boolean isBusy) {
+        this(deviceId, id, load, queue, isBusy, null, -1, null, -1, -1, -1);
+    }
+
+    private DefaultCpuStatistics(DeviceId deviceId, int id, float load, int queue, boolean isBusy,
+            MonitoringUnit throughputUnit, float averageThroughput, MonitoringUnit latencyUnit,
+            float minLatency, float medianLatency, float maxLatency) {
         checkNotNull(deviceId, "Device ID is NULL");
-        checkArgument(
-            (id >= 0) && (id < MAX_CPU_NB),
-            "Invalid CPU core ID " + String.valueOf(id) + ", not in [0, " + String.valueOf(MAX_CPU_NB - 1) + "]"
-        );
-        checkArgument(
-            (load >= MIN_CPU_LOAD) && (load <= MAX_CPU_LOAD),
-            "Invalid CPU load " + Float.toString(load) + ", not in [" + MIN_CPU_LOAD + ", " + MAX_CPU_LOAD + "]"
-        );
+        checkArgument((id >= 0) && (id < MAX_CPU_NB),
+            "Invalid CPU core ID " + String.valueOf(id) + ", not in [0, " + String.valueOf(MAX_CPU_NB - 1) + "]");
+        checkArgument((load >= MIN_CPU_LOAD) && (load <= MAX_CPU_LOAD),
+            "Invalid CPU load " + Float.toString(load) + ", not in [" + MIN_CPU_LOAD + ", " + MAX_CPU_LOAD + "]");
 
         this.deviceId = deviceId;
         this.id       = id;
         this.load     = load;
+        this.queue    = queue;
         this.isBusy   = isBusy;
+
+        this.throughputUnit = (throughputUnit == null) ?
+                Optional.empty() : Optional.ofNullable(throughputUnit);
+        this.averageThroughput = (averageThroughput < 0) ?
+                Optional.empty() : Optional.ofNullable(averageThroughput);
+        this.latencyUnit = (latencyUnit == null) ?
+                Optional.empty() : Optional.ofNullable(latencyUnit);
+        this.minLatency = (minLatency < 0) ?
+                Optional.empty() : Optional.ofNullable(minLatency);
+        this.medianLatency = (medianLatency < 0) ?
+                Optional.empty() : Optional.ofNullable(medianLatency);
+        this.maxLatency = (maxLatency < 0) ?
+                Optional.empty() : Optional.ofNullable(maxLatency);
     }
 
     // Constructor for serializer
@@ -67,7 +94,15 @@
         this.deviceId = null;
         this.id       = 0;
         this.load     = 0;
+        this.queue    = 0;
         this.isBusy   = false;
+
+        this.throughputUnit = null;
+        this.averageThroughput = null;
+        this.latencyUnit = null;
+        this.minLatency = null;
+        this.medianLatency = null;
+        this.maxLatency = null;
     }
 
     /**
@@ -90,18 +125,60 @@
     }
 
     @Override
+    public int queue() {
+        return this.queue;
+    }
+
+    @Override
     public boolean busy() {
         return this.isBusy;
     }
 
     @Override
+    public Optional<MonitoringUnit> throughputUnit() {
+        return this.throughputUnit;
+    }
+
+    @Override
+    public Optional<Float> averageThroughput() {
+        return this.averageThroughput;
+    }
+
+    @Override
+    public Optional<MonitoringUnit> latencyUnit() {
+        return this.latencyUnit;
+    }
+
+    @Override
+    public Optional<Float> minLatency() {
+        return this.minLatency;
+    }
+
+    @Override
+    public Optional<Float> medianLatency() {
+        return this.medianLatency;
+    }
+
+    @Override
+    public Optional<Float> maxLatency() {
+        return this.maxLatency;
+    }
+
+    @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
                 .omitNullValues()
                 .add("device", deviceId)
                 .add("id",     id())
                 .add("load",   load())
+                .add("queue",  queue())
                 .add("isBusy", busy())
+                .add("throughputUnit", throughputUnit.orElse(null))
+                .add("averageThroughput", averageThroughput.orElse(null))
+                .add("latencyUnit", latencyUnit.orElse(null))
+                .add("minLatency", minLatency.orElse(null))
+                .add("medianLatency", medianLatency.orElse(null))
+                .add("maxLatency", maxLatency.orElse(null))
                 .toString();
     }
 
@@ -109,8 +186,16 @@
 
         DeviceId deviceId;
         int      id;
-        float    load;
-        boolean  isBusy;
+        float    load = 0;
+        int      queue = -1;
+        boolean  isBusy = false;
+
+        MonitoringUnit throughputUnit = DEF_THROUGHPUT_UNIT;
+        float averageThroughput = -1;
+        MonitoringUnit latencyUnit = DEF_LATENCY_UNIT;
+        float minLatency = -1;
+        float medianLatency = -1;
+        float maxLatency = -1;
 
         private Builder() {
 
@@ -131,7 +216,7 @@
         /**
          * Sets the CPU ID.
          *
-         * @param id the CPU ID
+         * @param id CPU ID
          * @return builder object
          */
         public Builder setId(int id) {
@@ -153,6 +238,18 @@
         }
 
         /**
+         * Sets the hardware queue ID associated with this core.
+         *
+         * @param queue hardware queue ID
+         * @return builder object
+         */
+        public Builder setQueue(int queue) {
+            this.queue = queue;
+
+            return this;
+        }
+
+        /**
          * Sets the CPU status (free or busy).
          *
          * @param isBusy CPU status
@@ -165,17 +262,87 @@
         }
 
         /**
+         * Sets the throughput unit.
+         *
+         * @param throughputUnitStr throughput unit as a string
+         * @return builder object
+         */
+        public Builder setThroughputUnit(String throughputUnitStr) {
+            this.throughputUnit = ThroughputUnit.getByName(throughputUnitStr);
+
+            return this;
+        }
+
+        /**
+         * Sets the average throughput.
+         *
+         * @param averageThroughput average throughput
+         * @return builder object
+         */
+        public Builder setAverageThroughput(float averageThroughput) {
+            this.averageThroughput = averageThroughput;
+
+            return this;
+        }
+
+        /**
+         * Sets the latency unit.
+         *
+         * @param latencyUnitStr latency unit as a string
+         * @return builder object
+         */
+        public Builder setLatencyUnit(String latencyUnitStr) {
+            this.latencyUnit = LatencyUnit.getByName(latencyUnitStr);
+
+            return this;
+        }
+
+        /**
+         * Sets the minimum latency.
+         *
+         * @param minLatency minimum latency
+         * @return builder object
+         */
+        public Builder setMinLatency(float minLatency) {
+            this.minLatency = minLatency;
+
+            return this;
+        }
+
+        /**
+         * Sets the median latency.
+         *
+         * @param medianLatency median latency
+         * @return builder object
+         */
+        public Builder setMedianLatency(float medianLatency) {
+            this.medianLatency = medianLatency;
+
+            return this;
+        }
+
+        /**
+         * Sets the maximum latency.
+         *
+         * @param maxLatency maximum latency
+         * @return builder object
+         */
+        public Builder setMaxLatency(float maxLatency) {
+            this.maxLatency = maxLatency;
+
+            return this;
+        }
+
+        /**
          * Creates a DefaultCpuStatistics object.
          *
          * @return DefaultCpuStatistics object
          */
         public DefaultCpuStatistics build() {
             return new DefaultCpuStatistics(
-                deviceId,
-                id,
-                load,
-                isBusy
-            );
+                deviceId, id, load, queue, isBusy,
+                throughputUnit, averageThroughput,
+                latencyUnit, minLatency, medianLatency, maxLatency);
         }
     }
 
diff --git a/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultTimingStatistics.java b/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultTimingStatistics.java
index 8256c5f..0fe253d 100644
--- a/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultTimingStatistics.java
+++ b/drivers/server/src/main/java/org/onosproject/drivers/server/impl/stats/DefaultTimingStatistics.java
@@ -16,29 +16,39 @@
 
 package org.onosproject.drivers.server.impl.stats;
 
+import org.onosproject.drivers.server.stats.MonitoringUnit;
 import org.onosproject.drivers.server.stats.TimingStatistics;
 
+import com.google.common.base.Strings;
 import com.google.common.base.MoreObjects;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.drivers.server.stats.MonitoringUnit.LatencyUnit;
 
 /**
  * Default implementation for timing statistics.
  */
 public final class DefaultTimingStatistics implements TimingStatistics {
 
+    private static final LatencyUnit DEF_UNIT = LatencyUnit.NANO_SECOND;
+
+    private final MonitoringUnit unit;
     private final long deployCommandParsingTime;
     private final long deployCommandLaunchingTime;
     private long autoscaleTime;
 
     private DefaultTimingStatistics(
+            MonitoringUnit unit,
             long parsingTime,
             long launchingTime,
             long autoscaleTime) {
+        checkNotNull(unit, "Time statistics unit is null");
         checkArgument(parsingTime   >= 0, "Parsing time is negative");
         checkArgument(launchingTime >= 0, "Launching time is negative");
         checkArgument(autoscaleTime >= 0, "Autoscale time is negative");
 
+        this.unit = unit;
         this.deployCommandParsingTime   = parsingTime;
         this.deployCommandLaunchingTime = launchingTime;
         this.autoscaleTime = autoscaleTime;
@@ -46,6 +56,7 @@
 
     // Constructor for serializer
     private DefaultTimingStatistics() {
+        this.unit = null;
         this.deployCommandParsingTime   = 0;
         this.deployCommandLaunchingTime = 0;
         this.autoscaleTime = 0;
@@ -61,6 +72,11 @@
     }
 
     @Override
+    public MonitoringUnit unit() {
+        return this.unit;
+    }
+
+    @Override
     public long deployCommandParsingTime() {
         return this.deployCommandParsingTime;
     }
@@ -84,15 +100,17 @@
     public String toString() {
         return MoreObjects.toStringHelper(this)
                 .omitNullValues()
-                .add("parsing",   this.deployCommandParsingTime())
-                .add("launching", this.deployCommandLaunchingTime())
-                .add("total",     this.totalDeploymentTime())
-                .add("autoscale", this.autoscaleTime())
+                .add("unit", this.unit().toString())
+                .add("parsingTime", this.deployCommandParsingTime())
+                .add("launchingTime", this.deployCommandLaunchingTime())
+                .add("deploymentTime", this.totalDeploymentTime())
+                .add("autoScaleTime", this.autoscaleTime())
                 .toString();
     }
 
     public static final class Builder {
 
+        MonitoringUnit unit = DEF_UNIT;
         long deployCommandParsingTime;
         long deployCommandLaunchingTime;
         long autoscaleTime;
@@ -102,6 +120,20 @@
         }
 
         /**
+         * Sets time statistics unit.
+         *
+         * @param unitStr time statistics unit as a string
+         * @return builder object
+         */
+        public Builder setUnit(String unitStr) {
+            if (!Strings.isNullOrEmpty(unitStr)) {
+                this.unit = LatencyUnit.getByName(unitStr);
+            }
+
+            return this;
+        }
+
+        /**
          * Sets parsing time.
          *
          * @param parsingTime parsing time
@@ -144,6 +176,7 @@
          */
         public DefaultTimingStatistics build() {
             return new DefaultTimingStatistics(
+                unit,
                 deployCommandParsingTime,
                 deployCommandLaunchingTime,
                 autoscaleTime