[ONOS-3851] Implement default Web GUI page for CPMan
- Reduce the datapoints to 20, resolve cold start problem
- Code refactoring for CpmanViewMessageHandler
- Code refactoring for cpman.js
- Show "No Data" message when client does not receive any data
- Clean up cpman.css
- Specify default colors for charting
- Resolve ArrayIndexOutofBoundsException when the number returned
dataset is less the number what we expected
Change-Id: I67ab3160ab66f92eaffeffc2d61c7d0e17be0512
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/gui/CpmanViewMessageHandler.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/gui/CpmanViewMessageHandler.java
index 2d4e28f..8003933 100644
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/gui/CpmanViewMessageHandler.java
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/gui/CpmanViewMessageHandler.java
@@ -27,7 +27,6 @@
import org.onosproject.cpman.ControlMetricType;
import org.onosproject.cpman.ControlPlaneMonitorService;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceService;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.chart.ChartModel;
@@ -38,14 +37,16 @@
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import java.util.stream.LongStream;
import static org.onosproject.cpman.ControlResource.CONTROL_MESSAGE_METRICS;
import static org.onosproject.cpman.ControlResource.Type.CONTROL_MESSAGE;
/**
- * CpmanViewMessageHandler class implementation.
+ * Message handler for control plane monitoring view related messages.
*/
public class CpmanViewMessageHandler extends UiMessageHandler {
@@ -55,12 +56,14 @@
private static final String CPMAN_DATA_RESP = "cpmanDataResponse";
private static final String CPMANS = "cpmans";
- // TODO: we assume that server side always returns 60 data points
+ // TODO: we assume that server side always returns 20 data points
// to feed 1 hour time slots, later this should make to be configurable
- private static final int NUM_OF_DATA_POINTS = 60;
+ private static final int NUM_OF_DATA_POINTS = 20;
private static final int MILLI_CONV_UNIT = 1000;
+ private long timestamp = 0L;
+
@Override
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
@@ -83,50 +86,104 @@
@Override
protected void populateChart(ChartModel cm, ObjectNode payload) {
String uri = string(payload, "devId");
+ ControlPlaneMonitorService cpms = get(ControlPlaneMonitorService.class);
+ ClusterService cs = get(ClusterService.class);
if (!Strings.isNullOrEmpty(uri)) {
- Map<ControlMetricType, Long[]> data = Maps.newHashMap();
DeviceId deviceId = DeviceId.deviceId(uri);
- ClusterService cs = get(ClusterService.class);
- ControlPlaneMonitorService cpms = get(ControlPlaneMonitorService.class);
-
if (cpms.availableResources(CONTROL_MESSAGE).contains(deviceId.toString())) {
- LocalDateTime ldt = null;
+ Map<ControlMetricType, Long[]> data = generateMatrix(cpms, cs, deviceId);
+ LocalDateTime ldt = new LocalDateTime(timestamp * MILLI_CONV_UNIT);
- try {
- for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
- ControlLoadSnapshot cls = cpms.getLoad(cs.getLocalNode().id(),
- cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES,
- Optional.of(deviceId)).get();
- data.put(cmt, ArrayUtils.toObject(cls.recent()));
- if (ldt == null) {
- ldt = new LocalDateTime(cls.time() * MILLI_CONV_UNIT);
- }
- }
-
- for (int i = 0; i < NUM_OF_DATA_POINTS; i++) {
- Map<String, Long> local = Maps.newHashMap();
- for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
- local.put(StringUtils.lowerCase(cmt.name()), data.get(cmt)[i]);
- }
-
- local.put(LABEL, ldt.minusMinutes(NUM_OF_DATA_POINTS - i).toDateTime().getMillis());
-
- populateMetric(cm.addDataPoint(ldt.minusMinutes(NUM_OF_DATA_POINTS - i)
- .toDateTime().getMillis()), local);
- }
-
- } catch (InterruptedException | ExecutionException e) {
- log.warn(e.getMessage());
- }
+ populateMetrics(cm, data, ldt, NUM_OF_DATA_POINTS);
}
} else {
- DeviceService ds = get(DeviceService.class);
- ds.getAvailableDevices();
+ Set<String> deviceIds = cpms.availableResources(CONTROL_MESSAGE);
+ for (String deviceId : deviceIds) {
+ Map<ControlMetricType, Long> data =
+ populateDeviceMetrics(cpms, cs, DeviceId.deviceId(deviceId));
+ Map<String, Long> local = Maps.newHashMap();
+ for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
+ local.put(StringUtils.lowerCase(cmt.name()), data.get(cmt));
+ }
+ // TODO: need to find a way to present device id using long type
+ String shortId = StringUtils.substring(deviceId,
+ deviceId.length() - 2, deviceId.length());
+ local.put(LABEL, Long.valueOf(shortId));
+ populateMetric(cm.addDataPoint(Long.valueOf(shortId)), local);
+ }
}
}
- private void populateAllDevs(ChartModel.DataPoint dataPoint, Map<String, Long> data) {
+ private Map<ControlMetricType, Long> populateDeviceMetrics(ControlPlaneMonitorService cpms,
+ ClusterService cs, DeviceId deviceId) {
+ Map<ControlMetricType, Long> data = Maps.newHashMap();
+ for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
+ ControlLoadSnapshot cls;
+ try {
+ cls = cpms.getLoad(cs.getLocalNode().id(),
+ cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES,
+ Optional.of(deviceId)).get();
+ data.put(cmt, Math.round(LongStream.of(cls.recent()).average().getAsDouble()));
+ timestamp = cls.time();
+ } catch (InterruptedException | ExecutionException e) {
+ log.warn(e.getMessage());
+ }
+ }
+ return data;
+ }
+ private Map<ControlMetricType, Long[]> generateMatrix(ControlPlaneMonitorService cpms,
+ ClusterService cs, DeviceId deviceId) {
+ Map<ControlMetricType, Long[]> data = Maps.newHashMap();
+ for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
+ ControlLoadSnapshot cls;
+ try {
+ cls = cpms.getLoad(cs.getLocalNode().id(),
+ cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES,
+ Optional.of(deviceId)).get();
+
+ // TODO: in some cases, the number of returned dataset is
+ // less than what we expected (expected -1)
+ // As a workaround, we simply fill the slot with 0 values,
+ // such a bug should be fixed with updated RRD4J lib...
+ data.put(cmt, ArrayUtils.toObject(fillData(cls.recent(), NUM_OF_DATA_POINTS)));
+ timestamp = cls.time();
+ } catch (InterruptedException | ExecutionException e) {
+ log.warn(e.getMessage());
+ }
+ }
+ return data;
+ }
+
+ private long[] fillData(long[] origin, int expected) {
+ if (origin.length == expected) {
+ return origin;
+ } else {
+ long[] filled = new long[expected];
+ for (int i = 0; i < expected; i++) {
+ if (i == 0) {
+ filled[i] = 0;
+ } else {
+ filled[i] = origin[i - 1];
+ }
+ }
+ return filled;
+ }
+ }
+
+ private void populateMetrics(ChartModel cm, Map<ControlMetricType,
+ Long[]> data, LocalDateTime time, int numOfDp) {
+ for (int i = 0; i < numOfDp; i++) {
+ Map<String, Long> local = Maps.newHashMap();
+ for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
+ local.put(StringUtils.lowerCase(cmt.name()), data.get(cmt)[i]);
+ }
+
+ local.put(LABEL, time.minusMinutes(numOfDp - i).toDateTime().getMillis());
+
+ populateMetric(cm.addDataPoint(time.minusMinutes(numOfDp - i)
+ .toDateTime().getMillis()), local);
+ }
}
private void populateMetric(ChartModel.DataPoint dataPoint,