[ONOS-3851] Initial implementation of Web GUI of CPMan
- Revise chart model to provide default label - Visualize control message stats per device Change-Id: I88b8e63ce92114907bba185b1906569fa8cc0b83
Showing
8 changed files
with
203 additions
and
91 deletions
... | @@ -17,6 +17,7 @@ package org.onosproject.cpman; | ... | @@ -17,6 +17,7 @@ package org.onosproject.cpman; |
17 | 17 | ||
18 | import com.google.common.base.MoreObjects; | 18 | import com.google.common.base.MoreObjects; |
19 | 19 | ||
20 | +import java.util.Arrays; | ||
20 | import java.util.Objects; | 21 | import java.util.Objects; |
21 | 22 | ||
22 | import static com.google.common.base.MoreObjects.toStringHelper; | 23 | import static com.google.common.base.MoreObjects.toStringHelper; |
... | @@ -29,13 +30,14 @@ public class ControlLoadSnapshot { | ... | @@ -29,13 +30,14 @@ public class ControlLoadSnapshot { |
29 | private final long latest; | 30 | private final long latest; |
30 | private final long average; | 31 | private final long average; |
31 | private final long time; | 32 | private final long time; |
33 | + private long[] recent; | ||
32 | 34 | ||
33 | /** | 35 | /** |
34 | * Instantiates a new control metric response with given latest, average, time. | 36 | * Instantiates a new control metric response with given latest, average, time. |
35 | * | 37 | * |
36 | * @param latest latest value of control metric | 38 | * @param latest latest value of control metric |
37 | * @param average average value of control metric | 39 | * @param average average value of control metric |
38 | - * @param time last logging time fo control metric | 40 | + * @param time last logging time of control metric |
39 | */ | 41 | */ |
40 | public ControlLoadSnapshot(long latest, long average, long time) { | 42 | public ControlLoadSnapshot(long latest, long average, long time) { |
41 | this.latest = latest; | 43 | this.latest = latest; |
... | @@ -44,6 +46,22 @@ public class ControlLoadSnapshot { | ... | @@ -44,6 +46,22 @@ public class ControlLoadSnapshot { |
44 | } | 46 | } |
45 | 47 | ||
46 | /** | 48 | /** |
49 | + * Instantiates a new control metric response with given latest, average, time, | ||
50 | + * recent values. | ||
51 | + * | ||
52 | + * @param latest latest value of control metric | ||
53 | + * @param average average value of control metric | ||
54 | + * @param time last logging time of control metric | ||
55 | + * @param recent a set of historical data | ||
56 | + */ | ||
57 | + public ControlLoadSnapshot(long latest, long average, long time, long[] recent) { | ||
58 | + this.latest = latest; | ||
59 | + this.average = average; | ||
60 | + this.time = time; | ||
61 | + this.recent = recent; | ||
62 | + } | ||
63 | + | ||
64 | + /** | ||
47 | * Returns latest value of control metric. | 65 | * Returns latest value of control metric. |
48 | * | 66 | * |
49 | * @return latest value of control metric | 67 | * @return latest value of control metric |
... | @@ -70,9 +88,18 @@ public class ControlLoadSnapshot { | ... | @@ -70,9 +88,18 @@ public class ControlLoadSnapshot { |
70 | return average; | 88 | return average; |
71 | } | 89 | } |
72 | 90 | ||
91 | + /** | ||
92 | + * Returns a set of historical recent of control metric. | ||
93 | + * | ||
94 | + * @return a set of historical recent of control metric | ||
95 | + */ | ||
96 | + public long[] recent() { | ||
97 | + return recent; | ||
98 | + } | ||
99 | + | ||
73 | @Override | 100 | @Override |
74 | public int hashCode() { | 101 | public int hashCode() { |
75 | - return Objects.hash(latest, average, time); | 102 | + return Objects.hash(latest, average, time, recent); |
76 | } | 103 | } |
77 | 104 | ||
78 | @Override | 105 | @Override |
... | @@ -84,7 +111,8 @@ public class ControlLoadSnapshot { | ... | @@ -84,7 +111,8 @@ public class ControlLoadSnapshot { |
84 | final ControlLoadSnapshot other = (ControlLoadSnapshot) obj; | 111 | final ControlLoadSnapshot other = (ControlLoadSnapshot) obj; |
85 | return Objects.equals(this.latest, other.latest) && | 112 | return Objects.equals(this.latest, other.latest) && |
86 | Objects.equals(this.average, other.average) && | 113 | Objects.equals(this.average, other.average) && |
87 | - Objects.equals(this.time, other.time); | 114 | + Objects.equals(this.time, other.time) && |
115 | + Arrays.equals(this.recent, other.recent); | ||
88 | } | 116 | } |
89 | return false; | 117 | return false; |
90 | } | 118 | } |
... | @@ -95,7 +123,9 @@ public class ControlLoadSnapshot { | ... | @@ -95,7 +123,9 @@ public class ControlLoadSnapshot { |
95 | helper = toStringHelper(this) | 123 | helper = toStringHelper(this) |
96 | .add("latest", latest) | 124 | .add("latest", latest) |
97 | .add("average", average) | 125 | .add("average", average) |
98 | - .add("time", time); | 126 | + .add("time", time) |
127 | + .add("recent", recent); | ||
128 | + | ||
99 | return helper.toString(); | 129 | return helper.toString(); |
100 | } | 130 | } |
101 | } | 131 | } | ... | ... |
... | @@ -16,44 +16,122 @@ | ... | @@ -16,44 +16,122 @@ |
16 | package org.onosproject.cpman.gui; | 16 | package org.onosproject.cpman.gui; |
17 | 17 | ||
18 | import com.fasterxml.jackson.databind.node.ObjectNode; | 18 | import com.fasterxml.jackson.databind.node.ObjectNode; |
19 | +import com.google.common.base.Strings; | ||
19 | import com.google.common.collect.ImmutableSet; | 20 | import com.google.common.collect.ImmutableSet; |
21 | +import com.google.common.collect.Maps; | ||
22 | +import org.apache.commons.lang.ArrayUtils; | ||
23 | +import org.apache.commons.lang3.StringUtils; | ||
24 | +import org.joda.time.LocalDateTime; | ||
25 | +import org.onosproject.cluster.ClusterService; | ||
26 | +import org.onosproject.cpman.ControlLoadSnapshot; | ||
27 | +import org.onosproject.cpman.ControlMetricType; | ||
28 | +import org.onosproject.cpman.ControlPlaneMonitorService; | ||
29 | +import org.onosproject.net.DeviceId; | ||
30 | +import org.onosproject.net.device.DeviceService; | ||
20 | import org.onosproject.ui.RequestHandler; | 31 | import org.onosproject.ui.RequestHandler; |
21 | import org.onosproject.ui.UiMessageHandler; | 32 | import org.onosproject.ui.UiMessageHandler; |
33 | +import org.onosproject.ui.chart.ChartModel; | ||
34 | +import org.onosproject.ui.chart.ChartRequestHandler; | ||
35 | +import org.slf4j.Logger; | ||
36 | +import org.slf4j.LoggerFactory; | ||
22 | 37 | ||
23 | import java.util.Collection; | 38 | import java.util.Collection; |
24 | -import java.util.Random; | 39 | +import java.util.Map; |
40 | +import java.util.Optional; | ||
41 | +import java.util.concurrent.ExecutionException; | ||
42 | +import java.util.concurrent.TimeUnit; | ||
43 | + | ||
44 | +import static org.onosproject.cpman.ControlResource.CONTROL_MESSAGE_METRICS; | ||
45 | +import static org.onosproject.cpman.ControlResource.Type.CONTROL_MESSAGE; | ||
25 | 46 | ||
26 | /** | 47 | /** |
27 | * CpmanViewMessageHandler class implementation. | 48 | * CpmanViewMessageHandler class implementation. |
28 | */ | 49 | */ |
29 | public class CpmanViewMessageHandler extends UiMessageHandler { | 50 | public class CpmanViewMessageHandler extends UiMessageHandler { |
30 | 51 | ||
52 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
53 | + | ||
31 | private static final String CPMAN_DATA_REQ = "cpmanDataRequest"; | 54 | private static final String CPMAN_DATA_REQ = "cpmanDataRequest"; |
32 | private static final String CPMAN_DATA_RESP = "cpmanDataResponse"; | 55 | private static final String CPMAN_DATA_RESP = "cpmanDataResponse"; |
56 | + private static final String CPMANS = "cpmans"; | ||
57 | + | ||
58 | + // TODO: we assume that server side always returns 60 data points | ||
59 | + // to feed 1 hour time slots, later this should make to be configurable | ||
60 | + private static final int NUM_OF_DATA_POINTS = 60; | ||
33 | 61 | ||
34 | - private static final String RANDOM = "random"; | 62 | + private static final int MILLI_CONV_UNIT = 1000; |
35 | 63 | ||
36 | @Override | 64 | @Override |
37 | protected Collection<RequestHandler> createRequestHandlers() { | 65 | protected Collection<RequestHandler> createRequestHandlers() { |
38 | return ImmutableSet.of( | 66 | return ImmutableSet.of( |
39 | - new CpmanDataRequestHandler() | 67 | + new ControlMessageRequest() |
40 | ); | 68 | ); |
41 | } | 69 | } |
42 | 70 | ||
43 | - // handler for sample data requests | 71 | + private final class ControlMessageRequest extends ChartRequestHandler { |
44 | - private final class CpmanDataRequestHandler extends RequestHandler { | ||
45 | 72 | ||
46 | - private CpmanDataRequestHandler() { | 73 | + private ControlMessageRequest() { |
47 | - super(CPMAN_DATA_REQ); | 74 | + super(CPMAN_DATA_REQ, CPMAN_DATA_RESP, CPMANS); |
75 | + } | ||
76 | + | ||
77 | + @Override | ||
78 | + protected String[] getSeries() { | ||
79 | + return CONTROL_MESSAGE_METRICS.stream().map(type -> | ||
80 | + StringUtils.lowerCase(type.name())).toArray(String[]::new); | ||
48 | } | 81 | } |
49 | 82 | ||
50 | @Override | 83 | @Override |
51 | - public void process(long sid, ObjectNode payload) { | 84 | + protected void populateChart(ChartModel cm, ObjectNode payload) { |
52 | - ObjectNode result = objectNode(); | 85 | + String uri = string(payload, "devId"); |
53 | - Random random = new Random(); | 86 | + if (!Strings.isNullOrEmpty(uri)) { |
54 | - result.put(RANDOM, random.nextInt(50) + 1); | 87 | + Map<ControlMetricType, Long[]> data = Maps.newHashMap(); |
88 | + DeviceId deviceId = DeviceId.deviceId(uri); | ||
89 | + ClusterService cs = get(ClusterService.class); | ||
90 | + ControlPlaneMonitorService cpms = get(ControlPlaneMonitorService.class); | ||
91 | + | ||
92 | + if (cpms.availableResources(CONTROL_MESSAGE).contains(deviceId.toString())) { | ||
93 | + LocalDateTime ldt = null; | ||
94 | + | ||
95 | + try { | ||
96 | + for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) { | ||
97 | + ControlLoadSnapshot cls = cpms.getLoad(cs.getLocalNode().id(), | ||
98 | + cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES, | ||
99 | + Optional.of(deviceId)).get(); | ||
100 | + data.put(cmt, ArrayUtils.toObject(cls.recent())); | ||
101 | + if (ldt == null) { | ||
102 | + ldt = new LocalDateTime(cls.time() * MILLI_CONV_UNIT); | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + for (int i = 0; i < NUM_OF_DATA_POINTS; i++) { | ||
107 | + Map<String, Long> local = Maps.newHashMap(); | ||
108 | + for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) { | ||
109 | + local.put(StringUtils.lowerCase(cmt.name()), data.get(cmt)[i]); | ||
110 | + } | ||
111 | + | ||
112 | + local.put(LABEL, ldt.minusMinutes(NUM_OF_DATA_POINTS - i).toDateTime().getMillis()); | ||
113 | + | ||
114 | + populateMetric(cm.addDataPoint(ldt.minusMinutes(NUM_OF_DATA_POINTS - i) | ||
115 | + .toDateTime().getMillis()), local); | ||
116 | + } | ||
117 | + | ||
118 | + } catch (InterruptedException | ExecutionException e) { | ||
119 | + log.warn(e.getMessage()); | ||
120 | + } | ||
121 | + } | ||
122 | + } else { | ||
123 | + DeviceService ds = get(DeviceService.class); | ||
124 | + ds.getAvailableDevices(); | ||
125 | + } | ||
126 | + } | ||
127 | + | ||
128 | + private void populateAllDevs(ChartModel.DataPoint dataPoint, Map<String, Long> data) { | ||
129 | + | ||
130 | + } | ||
55 | 131 | ||
56 | - sendMessage(CPMAN_DATA_RESP, 0, result); | 132 | + private void populateMetric(ChartModel.DataPoint dataPoint, |
133 | + Map<String, Long> data) { | ||
134 | + data.forEach((k, v) -> dataPoint.data(k, v.doubleValue())); | ||
57 | } | 135 | } |
58 | } | 136 | } |
59 | } | 137 | } | ... | ... |
... | @@ -81,10 +81,10 @@ public class ControlPlaneManager { | ... | @@ -81,10 +81,10 @@ public class ControlPlaneManager { |
81 | // TODO: this can be changed to switch-case if we have more than | 81 | // TODO: this can be changed to switch-case if we have more than |
82 | // one event type | 82 | // one event type |
83 | if (event.type().equals(STATS_UPDATE)) { | 83 | if (event.type().equals(STATS_UPDATE)) { |
84 | - controlMessages.forEach(c -> { | 84 | + controlMessages.forEach(c -> |
85 | monitorService.updateMetric(getControlMetric(c), 1, | 85 | monitorService.updateMetric(getControlMetric(c), 1, |
86 | - Optional.of(c.deviceId())); | 86 | + Optional.of(c.deviceId())) |
87 | - }); | 87 | + ); |
88 | } | 88 | } |
89 | } | 89 | } |
90 | } | 90 | } | ... | ... |
... | @@ -169,7 +169,7 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { | ... | @@ -169,7 +169,7 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { |
169 | if (ctrlMsgBuf.get(deviceId.get()).keySet() | 169 | if (ctrlMsgBuf.get(deviceId.get()).keySet() |
170 | .containsAll(CONTROL_MESSAGE_METRICS)) { | 170 | .containsAll(CONTROL_MESSAGE_METRICS)) { |
171 | updateControlMessages(ctrlMsgBuf.get(deviceId.get()), deviceId.get()); | 171 | updateControlMessages(ctrlMsgBuf.get(deviceId.get()), deviceId.get()); |
172 | - ctrlMsgBuf.get(deviceId.get()); | 172 | + ctrlMsgBuf.clear(); |
173 | } | 173 | } |
174 | } | 174 | } |
175 | } else { | 175 | } else { |
... | @@ -327,8 +327,10 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { | ... | @@ -327,8 +327,10 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { |
327 | */ | 327 | */ |
328 | private void updateNetworkMetrics(Map<ControlMetricType, Double> metricMap, | 328 | private void updateNetworkMetrics(Map<ControlMetricType, Double> metricMap, |
329 | String resourceName) { | 329 | String resourceName) { |
330 | - networkMetricsMap.putIfAbsent(resourceName, genMDbBuilder(resourceName, | 330 | + if (!networkMetricsMap.containsKey(resourceName)) { |
331 | + networkMetricsMap.put(resourceName, genMDbBuilder(resourceName, | ||
331 | Type.NETWORK, NETWORK_METRICS)); | 332 | Type.NETWORK, NETWORK_METRICS)); |
333 | + } | ||
332 | networkMetricsMap.get(resourceName).updateMetrics(convertMap(metricMap)); | 334 | networkMetricsMap.get(resourceName).updateMetrics(convertMap(metricMap)); |
333 | } | 335 | } |
334 | 336 | ||
... | @@ -340,8 +342,10 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { | ... | @@ -340,8 +342,10 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { |
340 | */ | 342 | */ |
341 | private void updateDiskMetrics(Map<ControlMetricType, Double> metricMap, | 343 | private void updateDiskMetrics(Map<ControlMetricType, Double> metricMap, |
342 | String resourceName) { | 344 | String resourceName) { |
343 | - diskMetricsMap.putIfAbsent(resourceName, genMDbBuilder(resourceName, | 345 | + if (!diskMetricsMap.containsKey(resourceName)) { |
346 | + diskMetricsMap.put(resourceName, genMDbBuilder(resourceName, | ||
344 | Type.DISK, DISK_METRICS)); | 347 | Type.DISK, DISK_METRICS)); |
348 | + } | ||
345 | diskMetricsMap.get(resourceName).updateMetrics(convertMap(metricMap)); | 349 | diskMetricsMap.get(resourceName).updateMetrics(convertMap(metricMap)); |
346 | } | 350 | } |
347 | 351 | ||
... | @@ -353,8 +357,10 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { | ... | @@ -353,8 +357,10 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { |
353 | */ | 357 | */ |
354 | private void updateControlMessages(Map<ControlMetricType, Double> metricMap, | 358 | private void updateControlMessages(Map<ControlMetricType, Double> metricMap, |
355 | DeviceId deviceId) { | 359 | DeviceId deviceId) { |
356 | - controlMessageMap.putIfAbsent(deviceId, genMDbBuilder(deviceId.toString(), | 360 | + if (!controlMessageMap.containsKey(deviceId)) { |
361 | + controlMessageMap.put(deviceId, genMDbBuilder(deviceId.toString(), | ||
357 | Type.CONTROL_MESSAGE, CONTROL_MESSAGE_METRICS)); | 362 | Type.CONTROL_MESSAGE, CONTROL_MESSAGE_METRICS)); |
363 | + } | ||
358 | controlMessageMap.get(deviceId).updateMetrics(convertMap(metricMap)); | 364 | controlMessageMap.get(deviceId).updateMetrics(convertMap(metricMap)); |
359 | } | 365 | } |
360 | 366 | ||
... | @@ -478,7 +484,9 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { | ... | @@ -478,7 +484,9 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService { |
478 | */ | 484 | */ |
479 | private ControlLoadSnapshot snapshot(ControlLoad cl, int duration, TimeUnit unit) { | 485 | private ControlLoadSnapshot snapshot(ControlLoad cl, int duration, TimeUnit unit) { |
480 | if (cl != null) { | 486 | if (cl != null) { |
481 | - return new ControlLoadSnapshot(cl.latest(), cl.average(duration, unit), cl.time()); | 487 | + |
488 | + return new ControlLoadSnapshot(cl.latest(), cl.average(duration, unit), | ||
489 | + cl.time(), cl.recent(duration, unit)); | ||
482 | } | 490 | } |
483 | return null; | 491 | return null; |
484 | } | 492 | } | ... | ... |
1 | <!-- partial HTML --> | 1 | <!-- partial HTML --> |
2 | <div id="ov-cpman"> | 2 | <div id="ov-cpman"> |
3 | - <div class="button-panel"> | 3 | + <div> |
4 | - <div class="my-button" ng-click="getData()"> | 4 | + <canvas id="line" class="chart chart-line" chart-data="data" |
5 | - Fetch Data | 5 | + chart-labels="labels" chart-legend="true" chart-series="series"> |
6 | - </div> | 6 | + </canvas> |
7 | - </div> | ||
8 | - | ||
9 | - <div class="data-panel"> | ||
10 | - <table> | ||
11 | - <tr> | ||
12 | - <td> Number </td> | ||
13 | - <td class="number"> {{data.random}} </td> | ||
14 | - </tr> | ||
15 | - </table> | ||
16 | </div> | 7 | </div> |
17 | </div> | 8 | </div> | ... | ... |
... | @@ -20,66 +20,60 @@ | ... | @@ -20,66 +20,60 @@ |
20 | (function () { | 20 | (function () { |
21 | 'use strict'; | 21 | 'use strict'; |
22 | 22 | ||
23 | - // injected refs | 23 | + // injected references |
24 | - var $log, $scope, wss, ks; | 24 | + var $log, $scope, $location, ks, fs, cbs; |
25 | 25 | ||
26 | - // constants | 26 | + var labels = new Array(60); |
27 | - var dataReq = 'cpmanDataRequest', | 27 | + var data = new Array(new Array(60), new Array(60), new Array(60), |
28 | - dataResp = 'cpmanDataResponse'; | 28 | + new Array(60), new Array(60), new Array(60)); |
29 | 29 | ||
30 | - function addKeyBindings() { | 30 | + angular.module('ovCpman', ["chart.js"]) |
31 | - var map = { | ||
32 | - space: [getData, 'Fetch data from server'], | ||
33 | - | ||
34 | - _helpFormat: [ | ||
35 | - ['space'] | ||
36 | - ] | ||
37 | - }; | ||
38 | - | ||
39 | - ks.keyBindings(map); | ||
40 | - } | ||
41 | - | ||
42 | - function getData() { | ||
43 | - wss.sendEvent(dataReq); | ||
44 | - } | ||
45 | - | ||
46 | - function respDataCb(data) { | ||
47 | - $scope.data = data; | ||
48 | - $scope.$apply(); | ||
49 | - } | ||
50 | - | ||
51 | - | ||
52 | - angular.module('ovCpman', []) | ||
53 | .controller('OvCpmanCtrl', | 31 | .controller('OvCpmanCtrl', |
54 | - ['$log', '$scope', 'WebSocketService', 'KeyService', | 32 | + ['$log', '$scope', '$location', 'FnService', 'ChartBuilderService', |
55 | 33 | ||
56 | - function (_$log_, _$scope_, _wss_, _ks_) { | 34 | + function (_$log_, _$scope_, _$location_, _fs_, _cbs_) { |
35 | + var params; | ||
57 | $log = _$log_; | 36 | $log = _$log_; |
58 | $scope = _$scope_; | 37 | $scope = _$scope_; |
59 | - wss = _wss_; | 38 | + $location = _$location_; |
60 | - ks = _ks_; | 39 | + fs = _fs_; |
61 | - | 40 | + cbs = _cbs_; |
62 | - var handlers = {}; | ||
63 | - $scope.data = {}; | ||
64 | 41 | ||
65 | - // data response handler | 42 | + params = $location.search(); |
66 | - handlers[dataResp] = respDataCb; | 43 | + if (params.hasOwnProperty('devId')) { |
67 | - wss.bindHandlers(handlers); | 44 | + $scope.devId = params['devId']; |
45 | + } | ||
68 | 46 | ||
69 | - addKeyBindings(); | 47 | + cbs.buildChart({ |
48 | + scope: $scope, | ||
49 | + tag: 'cpman', | ||
50 | + query: params | ||
51 | + }); | ||
70 | 52 | ||
71 | - // custom click handler | 53 | + var idx = 0; |
72 | - $scope.getData = getData; | 54 | + var date; |
55 | + $scope.$watch('chartData', function () { | ||
56 | + idx = 0; | ||
57 | + if (!fs.isEmptyObject($scope.chartData)) { | ||
58 | + $scope.chartData.forEach(function (cm) { | ||
59 | + data[0][idx] = cm.inbound_packet; | ||
60 | + data[1][idx] = cm.outbound_packet; | ||
61 | + data[2][idx] = cm.flow_mod_packet; | ||
62 | + data[3][idx] = cm.flow_removed_packet; | ||
63 | + data[4][idx] = cm.request_packet; | ||
64 | + data[5][idx] = cm.reply_packet; | ||
65 | + date = new Date(cm.label); | ||
66 | + labels[idx] = date.getHours() + ":" + date.getMinutes(); | ||
67 | + idx++; | ||
68 | + }); | ||
69 | + } | ||
70 | + }); | ||
73 | 71 | ||
74 | - // get data the first time... | 72 | + $scope.series = ['INBOUND', 'OUTBOUND', 'FLOW-MOD', |
75 | - getData(); | 73 | + 'FLOW-REMOVED', 'STATS-REQUEST', 'STATS-REPLY']; |
74 | + $scope.labels = labels; | ||
76 | 75 | ||
77 | - // cleanup | 76 | + $scope.data = data; |
78 | - $scope.$on('$destroy', function () { | ||
79 | - wss.unbindHandlers(handlers); | ||
80 | - ks.unbindKeys(); | ||
81 | - $log.log('OvCpmanCtrl has been destroyed'); | ||
82 | - }); | ||
83 | 77 | ||
84 | $log.log('OvCpmanCtrl has been created'); | 78 | $log.log('OvCpmanCtrl has been created'); |
85 | }]); | 79 | }]); | ... | ... |
... | @@ -149,11 +149,13 @@ public class MetricsDatabaseTest { | ... | @@ -149,11 +149,13 @@ public class MetricsDatabaseTest { |
149 | devMetricsMap = Maps.newHashMap(); | 149 | devMetricsMap = Maps.newHashMap(); |
150 | 150 | ||
151 | Set<DeviceId> devices = ImmutableSet.of(devId1, devId2); | 151 | Set<DeviceId> devices = ImmutableSet.of(devId1, devId2); |
152 | - devices.forEach(dev -> | 152 | + devices.forEach(dev -> { |
153 | - devMetricsMap.putIfAbsent(dev, | 153 | + if (!devMetricsMap.containsKey(dev)) { |
154 | - genMDbBuilder(type, ControlResource.CONTROL_MESSAGE_METRICS) | 154 | + devMetricsMap.put(dev, genMDbBuilder(type, ControlResource.CONTROL_MESSAGE_METRICS) |
155 | .withResourceName(dev.toString()) | 155 | .withResourceName(dev.toString()) |
156 | - .build())); | 156 | + .build()); |
157 | + } | ||
158 | + }); | ||
157 | 159 | ||
158 | Map<String, Double> metrics1 = new HashMap<>(); | 160 | Map<String, Double> metrics1 = new HashMap<>(); |
159 | ControlResource.CONTROL_MESSAGE_METRICS.forEach(msgType -> | 161 | ControlResource.CONTROL_MESSAGE_METRICS.forEach(msgType -> | ... | ... |
... | @@ -18,6 +18,10 @@ package org.onosproject.ui.chart; | ... | @@ -18,6 +18,10 @@ package org.onosproject.ui.chart; |
18 | import com.fasterxml.jackson.databind.node.ObjectNode; | 18 | import com.fasterxml.jackson.databind.node.ObjectNode; |
19 | import org.onosproject.ui.RequestHandler; | 19 | import org.onosproject.ui.RequestHandler; |
20 | 20 | ||
21 | +import java.util.ArrayList; | ||
22 | +import java.util.Arrays; | ||
23 | +import java.util.List; | ||
24 | + | ||
21 | /** | 25 | /** |
22 | * Message handler specifically for the chart views. | 26 | * Message handler specifically for the chart views. |
23 | */ | 27 | */ |
... | @@ -25,6 +29,7 @@ public abstract class ChartRequestHandler extends RequestHandler { | ... | @@ -25,6 +29,7 @@ public abstract class ChartRequestHandler extends RequestHandler { |
25 | 29 | ||
26 | private final String respType; | 30 | private final String respType; |
27 | private final String nodeName; | 31 | private final String nodeName; |
32 | + protected static final String LABEL = "label"; | ||
28 | 33 | ||
29 | /** | 34 | /** |
30 | * Constructs a chart model handler for a specific graph view. When chart | 35 | * Constructs a chart model handler for a specific graph view. When chart |
... | @@ -61,7 +66,11 @@ public abstract class ChartRequestHandler extends RequestHandler { | ... | @@ -61,7 +66,11 @@ public abstract class ChartRequestHandler extends RequestHandler { |
61 | * @return an empty chart model | 66 | * @return an empty chart model |
62 | */ | 67 | */ |
63 | protected ChartModel createChartModel() { | 68 | protected ChartModel createChartModel() { |
64 | - return new ChartModel(getSeries()); | 69 | + List<String> series = new ArrayList<>(); |
70 | + series.addAll(Arrays.asList(getSeries())); | ||
71 | + series.add(LABEL); | ||
72 | + String[] seiresArray = new String[series.size()]; | ||
73 | + return new ChartModel(series.toArray(seiresArray)); | ||
65 | } | 74 | } |
66 | 75 | ||
67 | /** | 76 | /** | ... | ... |
-
Please register or login to post a comment