blob: e63dbf7d7e8fbd85f6cf40274e1d50abfbe00794 [file] [log] [blame]
Thomas Vachuska329af532015-03-10 02:08:33 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.ui.impl;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.ImmutableSet;
22import org.onlab.osgi.ServiceDirectory;
23import org.onlab.util.AbstractAccumulator;
24import org.onlab.util.Accumulator;
25import org.onosproject.cluster.ClusterEvent;
26import org.onosproject.cluster.ClusterEventListener;
27import org.onosproject.cluster.ControllerNode;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
30import org.onosproject.event.Event;
31import org.onosproject.mastership.MastershipAdminService;
32import org.onosproject.mastership.MastershipEvent;
33import org.onosproject.mastership.MastershipListener;
34import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.Device;
36import org.onosproject.net.Host;
37import org.onosproject.net.HostId;
38import org.onosproject.net.HostLocation;
39import org.onosproject.net.Link;
40import org.onosproject.net.device.DeviceEvent;
41import org.onosproject.net.device.DeviceListener;
42import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.FlowRuleEvent;
45import org.onosproject.net.flow.FlowRuleListener;
46import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
48import org.onosproject.net.host.HostEvent;
49import org.onosproject.net.host.HostListener;
50import org.onosproject.net.intent.HostToHostIntent;
51import org.onosproject.net.intent.Intent;
52import org.onosproject.net.intent.IntentEvent;
53import org.onosproject.net.intent.IntentListener;
54import org.onosproject.net.intent.MultiPointToSinglePointIntent;
55import org.onosproject.net.link.LinkEvent;
56import org.onosproject.net.link.LinkListener;
57import org.onosproject.ui.UiConnection;
58
59import java.util.ArrayList;
60import java.util.Collections;
61import java.util.Comparator;
62import java.util.HashSet;
63import java.util.List;
64import java.util.Set;
65import java.util.Timer;
66import java.util.TimerTask;
67
68import static com.google.common.base.Strings.isNullOrEmpty;
69import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
70import static org.onosproject.net.DeviceId.deviceId;
71import static org.onosproject.net.HostId.hostId;
72import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
73import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
74import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
75import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
76
77/**
78 * Web socket capable of interacting with the GUI topology view.
79 */
80public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
81
82 private static final String APP_ID = "org.onosproject.gui";
83
84 private static final long TRAFFIC_FREQUENCY = 5000;
85 private static final long SUMMARY_FREQUENCY = 30000;
86
87 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
88 new Comparator<ControllerNode>() {
89 @Override
90 public int compare(ControllerNode o1, ControllerNode o2) {
91 return o1.id().toString().compareTo(o2.id().toString());
92 }
93 };
94
95
96 private final Timer timer = new Timer("topology-view");
97
98 private static final int MAX_EVENTS = 1000;
99 private static final int MAX_BATCH_MS = 5000;
100 private static final int MAX_IDLE_MS = 1000;
101
102 private ApplicationId appId;
103
104 private final ClusterEventListener clusterListener = new InternalClusterListener();
105 private final MastershipListener mastershipListener = new InternalMastershipListener();
106 private final DeviceListener deviceListener = new InternalDeviceListener();
107 private final LinkListener linkListener = new InternalLinkListener();
108 private final HostListener hostListener = new InternalHostListener();
109 private final IntentListener intentListener = new InternalIntentListener();
110 private final FlowRuleListener flowListener = new InternalFlowListener();
111
112 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
113
114 private TimerTask trafficTask;
115 private ObjectNode trafficEvent;
116
117 private TimerTask summaryTask;
118 private ObjectNode summaryEvent;
119
120 private boolean listenersRemoved = false;
121
122 private TopologyViewIntentFilter intentFilter;
123
124 // Current selection context
125 private Set<Host> selectedHosts;
126 private Set<Device> selectedDevices;
127 private List<Intent> selectedIntents;
128 private int currentIntentIndex = -1;
129
130 /**
131 * Creates a new web-socket for serving data to GUI topology view.
132 */
133 public TopologyViewMessageHandler() {
134 super(ImmutableSet.of("topoStart", "topoStop",
135 "requestDetails",
136 "updateMeta",
137 "addHostIntent",
138 "addMultiSourceIntent",
139 "requestRelatedIntents",
140 "requestNextRelatedIntent",
141 "requestPrevRelatedIntent",
142 "requestSelectedIntentTraffic",
143 "requestAllTraffic",
144 "requestDeviceLinkFlows",
145 "cancelTraffic",
146 "requestSummary",
147 "cancelSummary",
148 "equalizeMasters"
149 ));
150 }
151
152 @Override
153 public void init(UiConnection connection, ServiceDirectory directory) {
154 super.init(connection, directory);
155 intentFilter = new TopologyViewIntentFilter(intentService, deviceService,
156 hostService, linkService);
157 appId = directory.get(CoreService.class).registerApplication(APP_ID);
158 }
159
160 @Override
161 public void destroy() {
162 cancelAllRequests();
163 super.destroy();
164 }
165
166 // Processes the specified event.
167 @Override
168 public void process(ObjectNode event) {
169 String type = string(event, "event", "unknown");
170 if (type.equals("requestDetails")) {
171 requestDetails(event);
172 } else if (type.equals("updateMeta")) {
173 updateMetaUi(event);
174
175 } else if (type.equals("addHostIntent")) {
176 createHostIntent(event);
177 } else if (type.equals("addMultiSourceIntent")) {
178 createMultiSourceIntent(event);
179
180 } else if (type.equals("requestRelatedIntents")) {
181 stopTrafficMonitoring();
182 requestRelatedIntents(event);
183
184 } else if (type.equals("requestNextRelatedIntent")) {
185 stopTrafficMonitoring();
186 requestAnotherRelatedIntent(event, +1);
187 } else if (type.equals("requestPrevRelatedIntent")) {
188 stopTrafficMonitoring();
189 requestAnotherRelatedIntent(event, -1);
190 } else if (type.equals("requestSelectedIntentTraffic")) {
191 requestSelectedIntentTraffic(event);
192 startTrafficMonitoring(event);
193
194 } else if (type.equals("requestAllTraffic")) {
195 requestAllTraffic(event);
196 startTrafficMonitoring(event);
197
198 } else if (type.equals("requestDeviceLinkFlows")) {
199 requestDeviceLinkFlows(event);
200 startTrafficMonitoring(event);
201
202 } else if (type.equals("cancelTraffic")) {
203 cancelTraffic(event);
204
205 } else if (type.equals("requestSummary")) {
206 requestSummary(event);
207 startSummaryMonitoring(event);
208 } else if (type.equals("cancelSummary")) {
209 stopSummaryMonitoring();
210
211 } else if (type.equals("equalizeMasters")) {
212 equalizeMasters(event);
213
214 } else if (type.equals("topoStart")) {
215 sendAllInitialData();
216 } else if (type.equals("topoStop")) {
217 cancelAllRequests();
218 }
219 }
220
221 // Sends the specified data to the client.
222 protected synchronized void sendMessage(ObjectNode data) {
223 UiConnection connection = connection();
224 if (connection != null) {
225 connection.sendMessage(data);
226 }
227 }
228
229 private void sendAllInitialData() {
230 addListeners();
231 sendAllInstances(null);
232 sendAllDevices();
233 sendAllLinks();
234 sendAllHosts();
235
236 }
237
238 private void cancelAllRequests() {
239 stopSummaryMonitoring();
240 stopTrafficMonitoring();
241 removeListeners();
242 }
243
244 // Sends all controller nodes to the client as node-added messages.
245 private void sendAllInstances(String messageType) {
246 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
247 Collections.sort(nodes, NODE_COMPARATOR);
248 for (ControllerNode node : nodes) {
249 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
250 messageType));
251 }
252 }
253
254 // Sends all devices to the client as device-added messages.
255 private void sendAllDevices() {
256 // Send optical first, others later for layered rendering
257 for (Device device : deviceService.getDevices()) {
258 if (device.type() == Device.Type.ROADM) {
259 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
260 }
261 }
262 for (Device device : deviceService.getDevices()) {
263 if (device.type() != Device.Type.ROADM) {
264 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
265 }
266 }
267 }
268
269 // Sends all links to the client as link-added messages.
270 private void sendAllLinks() {
271 // Send optical first, others later for layered rendering
272 for (Link link : linkService.getLinks()) {
273 if (link.type() == Link.Type.OPTICAL) {
274 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
275 }
276 }
277 for (Link link : linkService.getLinks()) {
278 if (link.type() != Link.Type.OPTICAL) {
279 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
280 }
281 }
282 }
283
284 // Sends all hosts to the client as host-added messages.
285 private void sendAllHosts() {
286 for (Host host : hostService.getHosts()) {
287 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
288 }
289 }
290
291 // Sends back device or host details.
292 private void requestDetails(ObjectNode event) {
293 ObjectNode payload = payload(event);
294 String type = string(payload, "class", "unknown");
295 long sid = number(event, "sid");
296
297 if (type.equals("device")) {
298 sendMessage(deviceDetails(deviceId(string(payload, "id")), sid));
299 } else if (type.equals("host")) {
300 sendMessage(hostDetails(hostId(string(payload, "id")), sid));
301 }
302 }
303
304
305 // Creates host-to-host intent.
306 private void createHostIntent(ObjectNode event) {
307 ObjectNode payload = payload(event);
308 long id = number(event, "sid");
309 // TODO: add protection against device ids and non-existent hosts.
310 HostId one = hostId(string(payload, "one"));
311 HostId two = hostId(string(payload, "two"));
312
313 HostToHostIntent intent =
Ray Milkeyebc5d222015-03-18 15:45:36 -0700314 HostToHostIntent.builder()
315 .appId(appId)
316 .one(one)
317 .two(two)
318 .build();
Thomas Vachuska329af532015-03-10 02:08:33 -0700319
320 intentService.submit(intent);
321 startMonitoringIntent(event, intent);
322 }
323
324 // Creates multi-source-to-single-dest intent.
325 private void createMultiSourceIntent(ObjectNode event) {
326 ObjectNode payload = payload(event);
327 long id = number(event, "sid");
328 // TODO: add protection against device ids and non-existent hosts.
329 Set<HostId> src = getHostIds((ArrayNode) payload.path("src"));
330 HostId dst = hostId(string(payload, "dst"));
331 Host dstHost = hostService.getHost(dst);
332
333 Set<ConnectPoint> ingressPoints = getHostLocations(src);
334
335 // FIXME: clearly, this is not enough
336 TrafficSelector selector = DefaultTrafficSelector.builder()
337 .matchEthDst(dstHost.mac()).build();
Brian O'Connor6b528132015-03-10 16:39:52 -0700338 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
Thomas Vachuska329af532015-03-10 02:08:33 -0700339
340 MultiPointToSinglePointIntent intent =
Ray Milkeyebc5d222015-03-18 15:45:36 -0700341 MultiPointToSinglePointIntent.builder()
342 .appId(appId)
343 .selector(selector)
344 .treatment(treatment)
345 .ingressPoints(ingressPoints)
346 .egressPoint(dstHost.location())
347 .build();
Thomas Vachuska329af532015-03-10 02:08:33 -0700348
349 intentService.submit(intent);
350 startMonitoringIntent(event, intent);
351 }
352
353
354 private synchronized void startMonitoringIntent(ObjectNode event, Intent intent) {
355 selectedHosts = new HashSet<>();
356 selectedDevices = new HashSet<>();
357 selectedIntents = new ArrayList<>();
358 selectedIntents.add(intent);
359 currentIntentIndex = -1;
360 requestAnotherRelatedIntent(event, +1);
361 requestSelectedIntentTraffic(event);
362 }
363
364
365 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
366 Set<ConnectPoint> points = new HashSet<>();
367 for (HostId hostId : hostIds) {
368 points.add(getHostLocation(hostId));
369 }
370 return points;
371 }
372
373 private HostLocation getHostLocation(HostId hostId) {
374 return hostService.getHost(hostId).location();
375 }
376
377 // Produces a list of host ids from the specified JSON array.
378 private Set<HostId> getHostIds(ArrayNode ids) {
379 Set<HostId> hostIds = new HashSet<>();
380 for (JsonNode id : ids) {
381 hostIds.add(hostId(id.asText()));
382 }
383 return hostIds;
384 }
385
386
387 private synchronized long startTrafficMonitoring(ObjectNode event) {
388 stopTrafficMonitoring();
389 trafficEvent = event;
390 trafficTask = new TrafficMonitor();
391 timer.schedule(trafficTask, TRAFFIC_FREQUENCY, TRAFFIC_FREQUENCY);
392 return number(event, "sid");
393 }
394
395 private synchronized void stopTrafficMonitoring() {
396 if (trafficTask != null) {
397 trafficTask.cancel();
398 trafficTask = null;
399 trafficEvent = null;
400 }
401 }
402
403 // Subscribes for host traffic messages.
404 private synchronized void requestAllTraffic(ObjectNode event) {
405 long sid = startTrafficMonitoring(event);
406 sendMessage(trafficSummaryMessage(sid));
407 }
408
409 private void requestDeviceLinkFlows(ObjectNode event) {
410 ObjectNode payload = payload(event);
411 long sid = startTrafficMonitoring(event);
412
413 // Get the set of selected hosts and their intents.
414 ArrayNode ids = (ArrayNode) payload.path("ids");
415 Set<Host> hosts = new HashSet<>();
416 Set<Device> devices = getDevices(ids);
417
418 // If there is a hover node, include it in the hosts and find intents.
419 String hover = string(payload, "hover");
420 if (!isNullOrEmpty(hover)) {
421 addHover(hosts, devices, hover);
422 }
423 sendMessage(flowSummaryMessage(sid, devices));
424 }
425
426
427 // Requests related intents message.
428 private synchronized void requestRelatedIntents(ObjectNode event) {
429 ObjectNode payload = payload(event);
430 if (!payload.has("ids")) {
431 return;
432 }
433
434 long sid = number(event, "sid");
435
436 // Cancel any other traffic monitoring mode.
437 stopTrafficMonitoring();
438
439 // Get the set of selected hosts and their intents.
440 ArrayNode ids = (ArrayNode) payload.path("ids");
441 selectedHosts = getHosts(ids);
442 selectedDevices = getDevices(ids);
443 selectedIntents = intentFilter.findPathIntents(selectedHosts, selectedDevices,
444 intentService.getIntents());
445 currentIntentIndex = -1;
446
447 if (haveSelectedIntents()) {
448 // Send a message to highlight all links of all monitored intents.
449 sendMessage(trafficMessage(sid, new TrafficClass("primary", selectedIntents)));
450 }
451
452 // FIXME: Re-introduce one the client click vs hover gesture stuff is sorted out.
453// String hover = string(payload, "hover");
454// if (!isNullOrEmpty(hover)) {
455// // If there is a hover node, include it in the selection and find intents.
456// processHoverExtendedSelection(sid, hover);
457// }
458 }
459
460 private boolean haveSelectedIntents() {
461 return selectedIntents != null && !selectedIntents.isEmpty();
462 }
463
464 // Processes the selection extended with hovered item to segregate items
465 // into primary (those including the hover) vs secondary highlights.
466 private void processHoverExtendedSelection(long sid, String hover) {
467 Set<Host> hoverSelHosts = new HashSet<>(selectedHosts);
468 Set<Device> hoverSelDevices = new HashSet<>(selectedDevices);
469 addHover(hoverSelHosts, hoverSelDevices, hover);
470
471 List<Intent> primary = selectedIntents == null ? new ArrayList<>() :
472 intentFilter.findPathIntents(hoverSelHosts, hoverSelDevices,
473 selectedIntents);
474 Set<Intent> secondary = new HashSet<>(selectedIntents);
475 secondary.removeAll(primary);
476
477 // Send a message to highlight all links of all monitored intents.
478 sendMessage(trafficMessage(sid, new TrafficClass("primary", primary),
479 new TrafficClass("secondary", secondary)));
480 }
481
482 // Requests next or previous related intent.
483 private void requestAnotherRelatedIntent(ObjectNode event, int offset) {
484 if (haveSelectedIntents()) {
485 currentIntentIndex = currentIntentIndex + offset;
486 if (currentIntentIndex < 0) {
487 currentIntentIndex = selectedIntents.size() - 1;
488 } else if (currentIntentIndex >= selectedIntents.size()) {
489 currentIntentIndex = 0;
490 }
491 sendSelectedIntent(event);
492 }
493 }
494
495 // Sends traffic information on the related intents with the currently
496 // selected intent highlighted.
497 private void sendSelectedIntent(ObjectNode event) {
498 Intent selectedIntent = selectedIntents.get(currentIntentIndex);
499 log.info("Requested next intent {}", selectedIntent.id());
500
501 Set<Intent> primary = new HashSet<>();
502 primary.add(selectedIntent);
503
504 Set<Intent> secondary = new HashSet<>(selectedIntents);
505 secondary.remove(selectedIntent);
506
507 // Send a message to highlight all links of the selected intent.
508 sendMessage(trafficMessage(number(event, "sid"),
509 new TrafficClass("primary", primary),
510 new TrafficClass("secondary", secondary)));
511 }
512
513 // Requests monitoring of traffic for the selected intent.
514 private void requestSelectedIntentTraffic(ObjectNode event) {
515 if (haveSelectedIntents()) {
516 if (currentIntentIndex < 0) {
517 currentIntentIndex = 0;
518 }
519 Intent selectedIntent = selectedIntents.get(currentIntentIndex);
520 log.info("Requested traffic for selected {}", selectedIntent.id());
521
522 Set<Intent> primary = new HashSet<>();
523 primary.add(selectedIntent);
524
525 // Send a message to highlight all links of the selected intent.
526 sendMessage(trafficMessage(number(event, "sid"),
527 new TrafficClass("primary", primary, true)));
528 }
529 }
530
531 // Cancels sending traffic messages.
532 private void cancelTraffic(ObjectNode event) {
533 selectedIntents = null;
534 sendMessage(trafficMessage(number(event, "sid")));
535 stopTrafficMonitoring();
536 }
537
538
539 private synchronized long startSummaryMonitoring(ObjectNode event) {
540 stopSummaryMonitoring();
541 summaryEvent = event;
542 summaryTask = new SummaryMonitor();
543 timer.schedule(summaryTask, SUMMARY_FREQUENCY, SUMMARY_FREQUENCY);
544 return number(event, "sid");
545 }
546
547 private synchronized void stopSummaryMonitoring() {
548 if (summaryEvent != null) {
549 summaryTask.cancel();
550 summaryTask = null;
551 summaryEvent = null;
552 }
553 }
554
555 // Subscribes for summary messages.
556 private synchronized void requestSummary(ObjectNode event) {
557 sendMessage(summmaryMessage(number(event, "sid")));
558 }
559
560
561 // Forces mastership role rebalancing.
562 private void equalizeMasters(ObjectNode event) {
563 directory.get(MastershipAdminService.class).balanceRoles();
564 }
565
566
567 // Adds all internal listeners.
568 private void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700569 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700570 clusterService.addListener(clusterListener);
571 mastershipService.addListener(mastershipListener);
572 deviceService.addListener(deviceListener);
573 linkService.addListener(linkListener);
574 hostService.addListener(hostListener);
575 intentService.addListener(intentListener);
576 flowService.addListener(flowListener);
577 }
578
579 // Removes all internal listeners.
580 private synchronized void removeListeners() {
581 if (!listenersRemoved) {
582 listenersRemoved = true;
583 clusterService.removeListener(clusterListener);
584 mastershipService.removeListener(mastershipListener);
585 deviceService.removeListener(deviceListener);
586 linkService.removeListener(linkListener);
587 hostService.removeListener(hostListener);
588 intentService.removeListener(intentListener);
589 flowService.removeListener(flowListener);
590 }
591 }
592
593 // Cluster event listener.
594 private class InternalClusterListener implements ClusterEventListener {
595 @Override
596 public void event(ClusterEvent event) {
597 sendMessage(instanceMessage(event, null));
598 }
599 }
600
601 // Mastership change listener
602 private class InternalMastershipListener implements MastershipListener {
603 @Override
604 public void event(MastershipEvent event) {
605 sendAllInstances("updateInstance");
606 Device device = deviceService.getDevice(event.subject());
607 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
608 }
609 }
610
611 // Device event listener.
612 private class InternalDeviceListener implements DeviceListener {
613 @Override
614 public void event(DeviceEvent event) {
615 sendMessage(deviceMessage(event));
616 eventAccummulator.add(event);
617 }
618 }
619
620 // Link event listener.
621 private class InternalLinkListener implements LinkListener {
622 @Override
623 public void event(LinkEvent event) {
624 sendMessage(linkMessage(event));
625 eventAccummulator.add(event);
626 }
627 }
628
629 // Host event listener.
630 private class InternalHostListener implements HostListener {
631 @Override
632 public void event(HostEvent event) {
633 sendMessage(hostMessage(event));
634 eventAccummulator.add(event);
635 }
636 }
637
638 // Intent event listener.
639 private class InternalIntentListener implements IntentListener {
640 @Override
641 public void event(IntentEvent event) {
642 if (trafficEvent != null) {
643 requestSelectedIntentTraffic(trafficEvent);
644 }
645 eventAccummulator.add(event);
646 }
647 }
648
649 // Intent event listener.
650 private class InternalFlowListener implements FlowRuleListener {
651 @Override
652 public void event(FlowRuleEvent event) {
653 eventAccummulator.add(event);
654 }
655 }
656
657 // Periodic update of the traffic information
658 private class TrafficMonitor extends TimerTask {
659 @Override
660 public void run() {
661 try {
662 if (trafficEvent != null) {
663 String type = string(trafficEvent, "event", "unknown");
664 if (type.equals("requestAllTraffic")) {
665 requestAllTraffic(trafficEvent);
666 } else if (type.equals("requestDeviceLinkFlows")) {
667 requestDeviceLinkFlows(trafficEvent);
668 } else if (type.equals("requestSelectedIntentTraffic")) {
669 requestSelectedIntentTraffic(trafficEvent);
670 }
671 }
672 } catch (Exception e) {
673 log.warn("Unable to handle traffic request due to {}", e.getMessage());
674 log.warn("Boom!", e);
675 }
676 }
677 }
678
679 // Periodic update of the summary information
680 private class SummaryMonitor extends TimerTask {
681 @Override
682 public void run() {
683 try {
684 if (summaryEvent != null) {
685 requestSummary(summaryEvent);
686 }
687 } catch (Exception e) {
688 log.warn("Unable to handle summary request due to {}", e.getMessage());
689 log.warn("Boom!", e);
690 }
691 }
692 }
693
694 // Accumulates events to drive methodic update of the summary pane.
695 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
696 protected InternalEventAccummulator() {
697 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
698 }
699
700 @Override
701 public void processItems(List<Event> items) {
702 try {
703 if (summaryEvent != null) {
704 sendMessage(summmaryMessage(0));
705 }
706 } catch (Exception e) {
707 log.warn("Unable to handle summary request due to {}", e.getMessage());
708 log.debug("Boom!", e);
709 }
710 }
711 }
712}
713