blob: 3be244e00b06dedd4ace13b442ea0ccae4e60636 [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",
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700148 "equalizeMasters",
149 "spriteListRequest",
150 "spriteDataRequest"
Thomas Vachuska329af532015-03-10 02:08:33 -0700151 ));
152 }
153
154 @Override
155 public void init(UiConnection connection, ServiceDirectory directory) {
156 super.init(connection, directory);
157 intentFilter = new TopologyViewIntentFilter(intentService, deviceService,
158 hostService, linkService);
159 appId = directory.get(CoreService.class).registerApplication(APP_ID);
160 }
161
162 @Override
163 public void destroy() {
164 cancelAllRequests();
165 super.destroy();
166 }
167
168 // Processes the specified event.
169 @Override
170 public void process(ObjectNode event) {
171 String type = string(event, "event", "unknown");
172 if (type.equals("requestDetails")) {
173 requestDetails(event);
174 } else if (type.equals("updateMeta")) {
175 updateMetaUi(event);
176
177 } else if (type.equals("addHostIntent")) {
178 createHostIntent(event);
179 } else if (type.equals("addMultiSourceIntent")) {
180 createMultiSourceIntent(event);
181
182 } else if (type.equals("requestRelatedIntents")) {
183 stopTrafficMonitoring();
184 requestRelatedIntents(event);
185
186 } else if (type.equals("requestNextRelatedIntent")) {
187 stopTrafficMonitoring();
188 requestAnotherRelatedIntent(event, +1);
189 } else if (type.equals("requestPrevRelatedIntent")) {
190 stopTrafficMonitoring();
191 requestAnotherRelatedIntent(event, -1);
192 } else if (type.equals("requestSelectedIntentTraffic")) {
193 requestSelectedIntentTraffic(event);
194 startTrafficMonitoring(event);
195
196 } else if (type.equals("requestAllTraffic")) {
197 requestAllTraffic(event);
198 startTrafficMonitoring(event);
199
200 } else if (type.equals("requestDeviceLinkFlows")) {
201 requestDeviceLinkFlows(event);
202 startTrafficMonitoring(event);
203
204 } else if (type.equals("cancelTraffic")) {
205 cancelTraffic(event);
206
207 } else if (type.equals("requestSummary")) {
208 requestSummary(event);
209 startSummaryMonitoring(event);
210 } else if (type.equals("cancelSummary")) {
211 stopSummaryMonitoring();
212
213 } else if (type.equals("equalizeMasters")) {
214 equalizeMasters(event);
215
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700216 } else if (type.equals("spriteListRequest")) {
217 sendSpriteList(event);
218 } else if (type.equals("spriteDataRequest")) {
219 sendSpriteData(event);
220
Thomas Vachuska329af532015-03-10 02:08:33 -0700221 } else if (type.equals("topoStart")) {
222 sendAllInitialData();
223 } else if (type.equals("topoStop")) {
224 cancelAllRequests();
225 }
226 }
227
228 // Sends the specified data to the client.
229 protected synchronized void sendMessage(ObjectNode data) {
230 UiConnection connection = connection();
231 if (connection != null) {
232 connection.sendMessage(data);
233 }
234 }
235
236 private void sendAllInitialData() {
237 addListeners();
238 sendAllInstances(null);
239 sendAllDevices();
240 sendAllLinks();
241 sendAllHosts();
242
243 }
244
245 private void cancelAllRequests() {
246 stopSummaryMonitoring();
247 stopTrafficMonitoring();
248 removeListeners();
249 }
250
251 // Sends all controller nodes to the client as node-added messages.
252 private void sendAllInstances(String messageType) {
253 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
254 Collections.sort(nodes, NODE_COMPARATOR);
255 for (ControllerNode node : nodes) {
256 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
257 messageType));
258 }
259 }
260
261 // Sends all devices to the client as device-added messages.
262 private void sendAllDevices() {
263 // Send optical first, others later for layered rendering
264 for (Device device : deviceService.getDevices()) {
265 if (device.type() == Device.Type.ROADM) {
266 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
267 }
268 }
269 for (Device device : deviceService.getDevices()) {
270 if (device.type() != Device.Type.ROADM) {
271 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
272 }
273 }
274 }
275
276 // Sends all links to the client as link-added messages.
277 private void sendAllLinks() {
278 // Send optical first, others later for layered rendering
279 for (Link link : linkService.getLinks()) {
280 if (link.type() == Link.Type.OPTICAL) {
281 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
282 }
283 }
284 for (Link link : linkService.getLinks()) {
285 if (link.type() != Link.Type.OPTICAL) {
286 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
287 }
288 }
289 }
290
291 // Sends all hosts to the client as host-added messages.
292 private void sendAllHosts() {
293 for (Host host : hostService.getHosts()) {
294 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
295 }
296 }
297
298 // Sends back device or host details.
299 private void requestDetails(ObjectNode event) {
300 ObjectNode payload = payload(event);
301 String type = string(payload, "class", "unknown");
302 long sid = number(event, "sid");
303
304 if (type.equals("device")) {
305 sendMessage(deviceDetails(deviceId(string(payload, "id")), sid));
306 } else if (type.equals("host")) {
307 sendMessage(hostDetails(hostId(string(payload, "id")), sid));
308 }
309 }
310
311
312 // Creates host-to-host intent.
313 private void createHostIntent(ObjectNode event) {
314 ObjectNode payload = payload(event);
315 long id = number(event, "sid");
316 // TODO: add protection against device ids and non-existent hosts.
317 HostId one = hostId(string(payload, "one"));
318 HostId two = hostId(string(payload, "two"));
319
320 HostToHostIntent intent =
Ray Milkeyebc5d222015-03-18 15:45:36 -0700321 HostToHostIntent.builder()
322 .appId(appId)
323 .one(one)
324 .two(two)
325 .build();
Thomas Vachuska329af532015-03-10 02:08:33 -0700326
327 intentService.submit(intent);
328 startMonitoringIntent(event, intent);
329 }
330
331 // Creates multi-source-to-single-dest intent.
332 private void createMultiSourceIntent(ObjectNode event) {
333 ObjectNode payload = payload(event);
334 long id = number(event, "sid");
335 // TODO: add protection against device ids and non-existent hosts.
336 Set<HostId> src = getHostIds((ArrayNode) payload.path("src"));
337 HostId dst = hostId(string(payload, "dst"));
338 Host dstHost = hostService.getHost(dst);
339
340 Set<ConnectPoint> ingressPoints = getHostLocations(src);
341
342 // FIXME: clearly, this is not enough
343 TrafficSelector selector = DefaultTrafficSelector.builder()
344 .matchEthDst(dstHost.mac()).build();
Brian O'Connor6b528132015-03-10 16:39:52 -0700345 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
Thomas Vachuska329af532015-03-10 02:08:33 -0700346
347 MultiPointToSinglePointIntent intent =
Ray Milkeyebc5d222015-03-18 15:45:36 -0700348 MultiPointToSinglePointIntent.builder()
349 .appId(appId)
350 .selector(selector)
351 .treatment(treatment)
352 .ingressPoints(ingressPoints)
353 .egressPoint(dstHost.location())
354 .build();
Thomas Vachuska329af532015-03-10 02:08:33 -0700355
356 intentService.submit(intent);
357 startMonitoringIntent(event, intent);
358 }
359
360
361 private synchronized void startMonitoringIntent(ObjectNode event, Intent intent) {
362 selectedHosts = new HashSet<>();
363 selectedDevices = new HashSet<>();
364 selectedIntents = new ArrayList<>();
365 selectedIntents.add(intent);
366 currentIntentIndex = -1;
367 requestAnotherRelatedIntent(event, +1);
368 requestSelectedIntentTraffic(event);
369 }
370
371
372 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
373 Set<ConnectPoint> points = new HashSet<>();
374 for (HostId hostId : hostIds) {
375 points.add(getHostLocation(hostId));
376 }
377 return points;
378 }
379
380 private HostLocation getHostLocation(HostId hostId) {
381 return hostService.getHost(hostId).location();
382 }
383
384 // Produces a list of host ids from the specified JSON array.
385 private Set<HostId> getHostIds(ArrayNode ids) {
386 Set<HostId> hostIds = new HashSet<>();
387 for (JsonNode id : ids) {
388 hostIds.add(hostId(id.asText()));
389 }
390 return hostIds;
391 }
392
393
394 private synchronized long startTrafficMonitoring(ObjectNode event) {
395 stopTrafficMonitoring();
396 trafficEvent = event;
397 trafficTask = new TrafficMonitor();
398 timer.schedule(trafficTask, TRAFFIC_FREQUENCY, TRAFFIC_FREQUENCY);
399 return number(event, "sid");
400 }
401
402 private synchronized void stopTrafficMonitoring() {
403 if (trafficTask != null) {
404 trafficTask.cancel();
405 trafficTask = null;
406 trafficEvent = null;
407 }
408 }
409
410 // Subscribes for host traffic messages.
411 private synchronized void requestAllTraffic(ObjectNode event) {
412 long sid = startTrafficMonitoring(event);
413 sendMessage(trafficSummaryMessage(sid));
414 }
415
416 private void requestDeviceLinkFlows(ObjectNode event) {
417 ObjectNode payload = payload(event);
418 long sid = startTrafficMonitoring(event);
419
420 // Get the set of selected hosts and their intents.
421 ArrayNode ids = (ArrayNode) payload.path("ids");
422 Set<Host> hosts = new HashSet<>();
423 Set<Device> devices = getDevices(ids);
424
425 // If there is a hover node, include it in the hosts and find intents.
426 String hover = string(payload, "hover");
427 if (!isNullOrEmpty(hover)) {
428 addHover(hosts, devices, hover);
429 }
430 sendMessage(flowSummaryMessage(sid, devices));
431 }
432
433
434 // Requests related intents message.
435 private synchronized void requestRelatedIntents(ObjectNode event) {
436 ObjectNode payload = payload(event);
437 if (!payload.has("ids")) {
438 return;
439 }
440
441 long sid = number(event, "sid");
442
443 // Cancel any other traffic monitoring mode.
444 stopTrafficMonitoring();
445
446 // Get the set of selected hosts and their intents.
447 ArrayNode ids = (ArrayNode) payload.path("ids");
448 selectedHosts = getHosts(ids);
449 selectedDevices = getDevices(ids);
450 selectedIntents = intentFilter.findPathIntents(selectedHosts, selectedDevices,
451 intentService.getIntents());
452 currentIntentIndex = -1;
453
454 if (haveSelectedIntents()) {
455 // Send a message to highlight all links of all monitored intents.
456 sendMessage(trafficMessage(sid, new TrafficClass("primary", selectedIntents)));
457 }
458
459 // FIXME: Re-introduce one the client click vs hover gesture stuff is sorted out.
460// String hover = string(payload, "hover");
461// if (!isNullOrEmpty(hover)) {
462// // If there is a hover node, include it in the selection and find intents.
463// processHoverExtendedSelection(sid, hover);
464// }
465 }
466
467 private boolean haveSelectedIntents() {
468 return selectedIntents != null && !selectedIntents.isEmpty();
469 }
470
471 // Processes the selection extended with hovered item to segregate items
472 // into primary (those including the hover) vs secondary highlights.
473 private void processHoverExtendedSelection(long sid, String hover) {
474 Set<Host> hoverSelHosts = new HashSet<>(selectedHosts);
475 Set<Device> hoverSelDevices = new HashSet<>(selectedDevices);
476 addHover(hoverSelHosts, hoverSelDevices, hover);
477
478 List<Intent> primary = selectedIntents == null ? new ArrayList<>() :
479 intentFilter.findPathIntents(hoverSelHosts, hoverSelDevices,
480 selectedIntents);
481 Set<Intent> secondary = new HashSet<>(selectedIntents);
482 secondary.removeAll(primary);
483
484 // Send a message to highlight all links of all monitored intents.
485 sendMessage(trafficMessage(sid, new TrafficClass("primary", primary),
486 new TrafficClass("secondary", secondary)));
487 }
488
489 // Requests next or previous related intent.
490 private void requestAnotherRelatedIntent(ObjectNode event, int offset) {
491 if (haveSelectedIntents()) {
492 currentIntentIndex = currentIntentIndex + offset;
493 if (currentIntentIndex < 0) {
494 currentIntentIndex = selectedIntents.size() - 1;
495 } else if (currentIntentIndex >= selectedIntents.size()) {
496 currentIntentIndex = 0;
497 }
498 sendSelectedIntent(event);
499 }
500 }
501
502 // Sends traffic information on the related intents with the currently
503 // selected intent highlighted.
504 private void sendSelectedIntent(ObjectNode event) {
505 Intent selectedIntent = selectedIntents.get(currentIntentIndex);
506 log.info("Requested next intent {}", selectedIntent.id());
507
508 Set<Intent> primary = new HashSet<>();
509 primary.add(selectedIntent);
510
511 Set<Intent> secondary = new HashSet<>(selectedIntents);
512 secondary.remove(selectedIntent);
513
514 // Send a message to highlight all links of the selected intent.
515 sendMessage(trafficMessage(number(event, "sid"),
516 new TrafficClass("primary", primary),
517 new TrafficClass("secondary", secondary)));
518 }
519
520 // Requests monitoring of traffic for the selected intent.
521 private void requestSelectedIntentTraffic(ObjectNode event) {
522 if (haveSelectedIntents()) {
523 if (currentIntentIndex < 0) {
524 currentIntentIndex = 0;
525 }
526 Intent selectedIntent = selectedIntents.get(currentIntentIndex);
527 log.info("Requested traffic for selected {}", selectedIntent.id());
528
529 Set<Intent> primary = new HashSet<>();
530 primary.add(selectedIntent);
531
532 // Send a message to highlight all links of the selected intent.
533 sendMessage(trafficMessage(number(event, "sid"),
534 new TrafficClass("primary", primary, true)));
535 }
536 }
537
538 // Cancels sending traffic messages.
539 private void cancelTraffic(ObjectNode event) {
540 selectedIntents = null;
541 sendMessage(trafficMessage(number(event, "sid")));
542 stopTrafficMonitoring();
543 }
544
545
546 private synchronized long startSummaryMonitoring(ObjectNode event) {
547 stopSummaryMonitoring();
548 summaryEvent = event;
549 summaryTask = new SummaryMonitor();
550 timer.schedule(summaryTask, SUMMARY_FREQUENCY, SUMMARY_FREQUENCY);
551 return number(event, "sid");
552 }
553
554 private synchronized void stopSummaryMonitoring() {
555 if (summaryEvent != null) {
556 summaryTask.cancel();
557 summaryTask = null;
558 summaryEvent = null;
559 }
560 }
561
562 // Subscribes for summary messages.
563 private synchronized void requestSummary(ObjectNode event) {
564 sendMessage(summmaryMessage(number(event, "sid")));
565 }
566
567
568 // Forces mastership role rebalancing.
569 private void equalizeMasters(ObjectNode event) {
570 directory.get(MastershipAdminService.class).balanceRoles();
571 }
572
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700573 // Sends a list of sprite names.
574 private void sendSpriteList(ObjectNode event) {
575 ObjectNode root = mapper.createObjectNode();
576 ArrayNode names = mapper.createArrayNode();
577 get(SpriteService.class).getNames().forEach(names::add);
578 root.set("names", names);
579 sendMessage(envelope("spriteListResponse", number(event, "sid"), root));
580 }
581
582 // Sends requested sprite data.
583 private void sendSpriteData(ObjectNode event) {
Simon Huntfd8c7d72015-04-14 17:53:37 -0700584 String name = event.path("payload").path("name").asText();
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700585 ObjectNode root = mapper.createObjectNode();
Simon Huntfd8c7d72015-04-14 17:53:37 -0700586 root.set("data", get(SpriteService.class).get(name));
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700587 sendMessage(envelope("spriteDataResponse", number(event, "sid"), root));
588 }
589
Thomas Vachuska329af532015-03-10 02:08:33 -0700590
591 // Adds all internal listeners.
592 private void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700593 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700594 clusterService.addListener(clusterListener);
595 mastershipService.addListener(mastershipListener);
596 deviceService.addListener(deviceListener);
597 linkService.addListener(linkListener);
598 hostService.addListener(hostListener);
599 intentService.addListener(intentListener);
600 flowService.addListener(flowListener);
601 }
602
603 // Removes all internal listeners.
604 private synchronized void removeListeners() {
605 if (!listenersRemoved) {
606 listenersRemoved = true;
607 clusterService.removeListener(clusterListener);
608 mastershipService.removeListener(mastershipListener);
609 deviceService.removeListener(deviceListener);
610 linkService.removeListener(linkListener);
611 hostService.removeListener(hostListener);
612 intentService.removeListener(intentListener);
613 flowService.removeListener(flowListener);
614 }
615 }
616
617 // Cluster event listener.
618 private class InternalClusterListener implements ClusterEventListener {
619 @Override
620 public void event(ClusterEvent event) {
621 sendMessage(instanceMessage(event, null));
622 }
623 }
624
625 // Mastership change listener
626 private class InternalMastershipListener implements MastershipListener {
627 @Override
628 public void event(MastershipEvent event) {
629 sendAllInstances("updateInstance");
630 Device device = deviceService.getDevice(event.subject());
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -0700631 if (device != null) {
632 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
633 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700634 }
635 }
636
637 // Device event listener.
638 private class InternalDeviceListener implements DeviceListener {
639 @Override
640 public void event(DeviceEvent event) {
641 sendMessage(deviceMessage(event));
642 eventAccummulator.add(event);
643 }
644 }
645
646 // Link event listener.
647 private class InternalLinkListener implements LinkListener {
648 @Override
649 public void event(LinkEvent event) {
650 sendMessage(linkMessage(event));
651 eventAccummulator.add(event);
652 }
653 }
654
655 // Host event listener.
656 private class InternalHostListener implements HostListener {
657 @Override
658 public void event(HostEvent event) {
659 sendMessage(hostMessage(event));
660 eventAccummulator.add(event);
661 }
662 }
663
664 // Intent event listener.
665 private class InternalIntentListener implements IntentListener {
666 @Override
667 public void event(IntentEvent event) {
668 if (trafficEvent != null) {
669 requestSelectedIntentTraffic(trafficEvent);
670 }
671 eventAccummulator.add(event);
672 }
673 }
674
675 // Intent event listener.
676 private class InternalFlowListener implements FlowRuleListener {
677 @Override
678 public void event(FlowRuleEvent event) {
679 eventAccummulator.add(event);
680 }
681 }
682
683 // Periodic update of the traffic information
684 private class TrafficMonitor extends TimerTask {
685 @Override
686 public void run() {
687 try {
688 if (trafficEvent != null) {
689 String type = string(trafficEvent, "event", "unknown");
690 if (type.equals("requestAllTraffic")) {
691 requestAllTraffic(trafficEvent);
692 } else if (type.equals("requestDeviceLinkFlows")) {
693 requestDeviceLinkFlows(trafficEvent);
694 } else if (type.equals("requestSelectedIntentTraffic")) {
695 requestSelectedIntentTraffic(trafficEvent);
696 }
697 }
698 } catch (Exception e) {
699 log.warn("Unable to handle traffic request due to {}", e.getMessage());
700 log.warn("Boom!", e);
701 }
702 }
703 }
704
705 // Periodic update of the summary information
706 private class SummaryMonitor extends TimerTask {
707 @Override
708 public void run() {
709 try {
710 if (summaryEvent != null) {
711 requestSummary(summaryEvent);
712 }
713 } catch (Exception e) {
714 log.warn("Unable to handle summary request due to {}", e.getMessage());
715 log.warn("Boom!", e);
716 }
717 }
718 }
719
720 // Accumulates events to drive methodic update of the summary pane.
721 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
722 protected InternalEventAccummulator() {
723 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
724 }
725
726 @Override
727 public void processItems(List<Event> items) {
728 try {
729 if (summaryEvent != null) {
730 sendMessage(summmaryMessage(0));
731 }
732 } catch (Exception e) {
733 log.warn("Unable to handle summary request due to {}", e.getMessage());
734 log.debug("Boom!", e);
735 }
736 }
737 }
738}
739