blob: 923c3db9aaf4491eb906b4d2b63b529ab0be5225 [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;
Thomas Vachuska329af532015-03-10 02:08:33 -070051import org.onosproject.net.intent.IntentEvent;
52import org.onosproject.net.intent.IntentListener;
53import org.onosproject.net.intent.MultiPointToSinglePointIntent;
54import org.onosproject.net.link.LinkEvent;
55import org.onosproject.net.link.LinkListener;
Simon Huntd2747a02015-04-30 22:41:16 -070056import org.onosproject.ui.JsonUtils;
57import org.onosproject.ui.RequestHandler;
Thomas Vachuska329af532015-03-10 02:08:33 -070058import org.onosproject.ui.UiConnection;
Simon Hunt4fc86852015-08-20 17:57:52 -070059import org.onosproject.ui.impl.TrafficMonitor.Mode;
Simon Hunta17fa672015-08-19 18:42:22 -070060import org.onosproject.ui.impl.topo.NodeSelection;
61import org.onosproject.ui.topo.Highlights;
Simon Hunt0af1ec32015-07-24 12:17:55 -070062import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070063
64import java.util.ArrayList;
Simon Huntd2747a02015-04-30 22:41:16 -070065import java.util.Collection;
Thomas Vachuska329af532015-03-10 02:08:33 -070066import java.util.Collections;
67import java.util.Comparator;
68import java.util.HashSet;
69import java.util.List;
70import java.util.Set;
71import java.util.Timer;
72import java.util.TimerTask;
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070073import java.util.concurrent.ExecutorService;
Thomas Vachuska329af532015-03-10 02:08:33 -070074
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070075import static java.util.concurrent.Executors.newSingleThreadExecutor;
76import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska329af532015-03-10 02:08:33 -070077import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
78import static org.onosproject.net.DeviceId.deviceId;
79import static org.onosproject.net.HostId.hostId;
Thomas Vachuskacb5016f2015-05-18 14:11:43 -070080import static org.onosproject.net.device.DeviceEvent.Type.*;
Thomas Vachuska329af532015-03-10 02:08:33 -070081import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
82import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
83
84/**
85 * Web socket capable of interacting with the GUI topology view.
86 */
87public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
88
Simon Huntb745ca62015-07-28 15:37:11 -070089 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -070090 private static final String REQ_DETAILS = "requestDetails";
91 private static final String UPDATE_META = "updateMeta";
92 private static final String ADD_HOST_INTENT = "addHostIntent";
93 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
94 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
95 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
96 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
97 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -070098 private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
99 private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700100 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
101 private static final String CANCEL_TRAFFIC = "cancelTraffic";
102 private static final String REQ_SUMMARY = "requestSummary";
103 private static final String CANCEL_SUMMARY = "cancelSummary";
104 private static final String EQ_MASTERS = "equalizeMasters";
105 private static final String SPRITE_LIST_REQ = "spriteListRequest";
106 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
107 private static final String TOPO_START = "topoStart";
Simon Hunt732bb2e2015-05-13 18:32:16 -0700108 private static final String TOPO_HEARTBEAT = "topoHeartbeat";
Simon Hunte05cae42015-07-23 17:35:24 -0700109 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700110 private static final String TOPO_STOP = "topoStop";
111
Simon Huntb745ca62015-07-28 15:37:11 -0700112 // outgoing event types
113 private static final String SHOW_SUMMARY = "showSummary";
114 private static final String SHOW_DETAILS = "showDetails";
115 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
116 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
117 private static final String UPDATE_INSTANCE = "updateInstance";
118
119 // fields
120 private static final String ID = "id";
Simon Huntb745ca62015-07-28 15:37:11 -0700121 private static final String DEVICE = "device";
122 private static final String HOST = "host";
123 private static final String CLASS = "class";
124 private static final String UNKNOWN = "unknown";
125 private static final String ONE = "one";
126 private static final String TWO = "two";
127 private static final String SRC = "src";
128 private static final String DST = "dst";
129 private static final String DATA = "data";
130 private static final String NAME = "name";
131 private static final String NAMES = "names";
132 private static final String ACTIVATE = "activate";
133 private static final String DEACTIVATE = "deactivate";
Simon Huntb745ca62015-07-28 15:37:11 -0700134
Simon Huntd2747a02015-04-30 22:41:16 -0700135
Thomas Vachuska329af532015-03-10 02:08:33 -0700136 private static final String APP_ID = "org.onosproject.gui";
137
Simon Hunta17fa672015-08-19 18:42:22 -0700138 private static final long TRAFFIC_PERIOD = 5000;
139 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700140
141 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Thomas Vachuskac0fe09a2015-05-21 12:56:22 -0700142 (o1, o2) -> o1.id().toString().compareTo(o2.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700143
144
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700145 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700146
147 private static final int MAX_EVENTS = 1000;
148 private static final int MAX_BATCH_MS = 5000;
149 private static final int MAX_IDLE_MS = 1000;
150
151 private ApplicationId appId;
152
153 private final ClusterEventListener clusterListener = new InternalClusterListener();
154 private final MastershipListener mastershipListener = new InternalMastershipListener();
155 private final DeviceListener deviceListener = new InternalDeviceListener();
156 private final LinkListener linkListener = new InternalLinkListener();
157 private final HostListener hostListener = new InternalHostListener();
158 private final IntentListener intentListener = new InternalIntentListener();
159 private final FlowRuleListener flowListener = new InternalFlowListener();
160
161 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700162 private final ExecutorService msgSender =
163 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender"));
Thomas Vachuska329af532015-03-10 02:08:33 -0700164
Simon Hunta17fa672015-08-19 18:42:22 -0700165 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700166 private TrafficMonitor traffic;
Thomas Vachuska329af532015-03-10 02:08:33 -0700167
Simon Huntd2747a02015-04-30 22:41:16 -0700168 private TimerTask summaryTask = null;
169 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700170
171 private boolean listenersRemoved = false;
172
Thomas Vachuska329af532015-03-10 02:08:33 -0700173
174 @Override
175 public void init(UiConnection connection, ServiceDirectory directory) {
176 super.init(connection, directory);
Thomas Vachuska329af532015-03-10 02:08:33 -0700177 appId = directory.get(CoreService.class).registerApplication(APP_ID);
Simon Hunt4fc86852015-08-20 17:57:52 -0700178 traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700179 }
180
181 @Override
182 public void destroy() {
183 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700184 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700185 super.destroy();
186 }
187
Thomas Vachuska329af532015-03-10 02:08:33 -0700188 @Override
Simon Huntda580882015-05-12 20:58:18 -0700189 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700190 return ImmutableSet.of(
191 new TopoStart(),
Simon Hunt732bb2e2015-05-13 18:32:16 -0700192 new TopoHeartbeat(),
Simon Hunte05cae42015-07-23 17:35:24 -0700193 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700194 new TopoStop(),
195 new ReqSummary(),
196 new CancelSummary(),
197 new SpriteListReq(),
198 new SpriteDataReq(),
199 new RequestDetails(),
200 new UpdateMeta(),
201 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700202
Simon Huntd2747a02015-04-30 22:41:16 -0700203 // TODO: migrate traffic related to separate app
204 new AddHostIntent(),
205 new AddMultiSourceIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700206
207 new ReqAllFlowTraffic(),
208 new ReqAllPortTraffic(),
209 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700210 new ReqRelatedIntents(),
211 new ReqNextIntent(),
212 new ReqPrevIntent(),
213 new ReqSelectedIntentTraffic(),
Simon Hunta17fa672015-08-19 18:42:22 -0700214
Simon Huntd2747a02015-04-30 22:41:16 -0700215 new CancelTraffic()
216 );
217 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700218
Simon Hunte05cae42015-07-23 17:35:24 -0700219 /**
220 * Injects the topology overlay cache.
221 *
222 * @param overlayCache injected cache
223 */
224 void setOverlayCache(TopoOverlayCache overlayCache) {
225 this.overlayCache = overlayCache;
226 }
227
Simon Huntd2747a02015-04-30 22:41:16 -0700228 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700229
Simon Huntd2747a02015-04-30 22:41:16 -0700230 private final class TopoStart extends RequestHandler {
231 private TopoStart() {
232 super(TOPO_START);
233 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700234
Simon Huntd2747a02015-04-30 22:41:16 -0700235 @Override
236 public void process(long sid, ObjectNode payload) {
237 addListeners();
238 sendAllInstances(null);
239 sendAllDevices();
240 sendAllLinks();
241 sendAllHosts();
Thomas Vachuska329af532015-03-10 02:08:33 -0700242 }
243 }
244
Simon Hunt732bb2e2015-05-13 18:32:16 -0700245 private final class TopoHeartbeat extends RequestHandler {
246 private TopoHeartbeat() {
247 super(TOPO_HEARTBEAT);
248 }
249
250 @Override
251 public void process(long sid, ObjectNode payload) {
252 // place holder for now
253 }
254 }
255
Simon Hunte05cae42015-07-23 17:35:24 -0700256 private final class TopoSelectOverlay extends RequestHandler {
257 private TopoSelectOverlay() {
258 super(TOPO_SELECT_OVERLAY);
259 }
260
261 @Override
262 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700263 String deact = string(payload, DEACTIVATE);
264 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700265 overlayCache.switchOverlay(deact, act);
266 }
267 }
268
Simon Huntd2747a02015-04-30 22:41:16 -0700269 private final class TopoStop extends RequestHandler {
270 private TopoStop() {
271 super(TOPO_STOP);
272 }
273
274 @Override
275 public void process(long sid, ObjectNode payload) {
276 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700277 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700278 }
279 }
280
281 private final class ReqSummary extends RequestHandler {
282 private ReqSummary() {
283 super(REQ_SUMMARY);
284 }
285
286 @Override
287 public void process(long sid, ObjectNode payload) {
288 requestSummary(sid);
289 startSummaryMonitoring();
290 }
291 }
292
293 private final class CancelSummary extends RequestHandler {
294 private CancelSummary() {
295 super(CANCEL_SUMMARY);
296 }
297
298 @Override
299 public void process(long sid, ObjectNode payload) {
300 stopSummaryMonitoring();
301 }
302 }
303
304 private final class SpriteListReq extends RequestHandler {
305 private SpriteListReq() {
306 super(SPRITE_LIST_REQ);
307 }
308
309 @Override
310 public void process(long sid, ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700311 ObjectNode root = objectNode();
312 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700313 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700314 root.set(NAMES, names);
315 sendMessage(SPRITE_LIST_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700316 }
317 }
318
319 private final class SpriteDataReq extends RequestHandler {
320 private SpriteDataReq() {
321 super(SPRITE_DATA_REQ);
322 }
323
324 @Override
325 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700326 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700327 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700328 root.set(DATA, get(SpriteService.class).get(name));
329 sendMessage(SPRITE_DATA_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700330 }
331 }
332
333 private final class RequestDetails extends RequestHandler {
334 private RequestDetails() {
335 super(REQ_DETAILS);
336 }
337
338 @Override
339 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700340 String type = string(payload, CLASS, UNKNOWN);
341 String id = string(payload, ID);
342 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700343
Simon Huntb745ca62015-07-28 15:37:11 -0700344 if (type.equals(DEVICE)) {
345 pp = deviceDetails(deviceId(id), sid);
346 overlayCache.currentOverlay().modifyDeviceDetails(pp);
347 } else if (type.equals(HOST)) {
348 pp = hostDetails(hostId(id), sid);
349 overlayCache.currentOverlay().modifyHostDetails(pp);
Simon Huntd2747a02015-04-30 22:41:16 -0700350 }
Simon Huntb745ca62015-07-28 15:37:11 -0700351
352 ObjectNode json = JsonUtils.envelope(SHOW_DETAILS, sid, json(pp));
353 sendMessage(json);
Simon Huntd2747a02015-04-30 22:41:16 -0700354 }
355 }
356
357 private final class UpdateMeta extends RequestHandler {
358 private UpdateMeta() {
359 super(UPDATE_META);
360 }
361
362 @Override
363 public void process(long sid, ObjectNode payload) {
364 updateMetaUi(payload);
365 }
366 }
367
368 private final class EqMasters extends RequestHandler {
369 private EqMasters() {
370 super(EQ_MASTERS);
371 }
372
373 @Override
374 public void process(long sid, ObjectNode payload) {
375 directory.get(MastershipAdminService.class).balanceRoles();
376 }
377 }
378
Simon Hunta17fa672015-08-19 18:42:22 -0700379
380 // ========= -----------------------------------------------------------------
381
Simon Huntd2747a02015-04-30 22:41:16 -0700382 // === TODO: move traffic related classes to traffic app
383
384 private final class AddHostIntent extends RequestHandler {
385 private AddHostIntent() {
386 super(ADD_HOST_INTENT);
387 }
388
389 @Override
390 public void process(long sid, ObjectNode payload) {
391 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700392 HostId one = hostId(string(payload, ONE));
393 HostId two = hostId(string(payload, TWO));
Simon Huntd2747a02015-04-30 22:41:16 -0700394
395 HostToHostIntent intent = HostToHostIntent.builder()
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700396 .appId(appId)
397 .one(one)
398 .two(two)
399 .build();
Simon Huntd2747a02015-04-30 22:41:16 -0700400
401 intentService.submit(intent);
Simon Hunt4fc86852015-08-20 17:57:52 -0700402 traffic.monitor(intent);
Simon Huntd2747a02015-04-30 22:41:16 -0700403 }
404 }
405
406 private final class AddMultiSourceIntent extends RequestHandler {
407 private AddMultiSourceIntent() {
408 super(ADD_MULTI_SRC_INTENT);
409 }
410
411 @Override
412 public void process(long sid, ObjectNode payload) {
413 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700414 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
415 HostId dst = hostId(string(payload, DST));
Simon Huntd2747a02015-04-30 22:41:16 -0700416 Host dstHost = hostService.getHost(dst);
417
418 Set<ConnectPoint> ingressPoints = getHostLocations(src);
419
420 // FIXME: clearly, this is not enough
421 TrafficSelector selector = DefaultTrafficSelector.builder()
422 .matchEthDst(dstHost.mac()).build();
423 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
424
425 MultiPointToSinglePointIntent intent =
426 MultiPointToSinglePointIntent.builder()
427 .appId(appId)
428 .selector(selector)
429 .treatment(treatment)
430 .ingressPoints(ingressPoints)
431 .egressPoint(dstHost.location())
432 .build();
433
434 intentService.submit(intent);
Simon Hunt4fc86852015-08-20 17:57:52 -0700435 traffic.monitor(intent);
Simon Huntd2747a02015-04-30 22:41:16 -0700436 }
437 }
438
Simon Hunta17fa672015-08-19 18:42:22 -0700439 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700440
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700441 private final class ReqAllFlowTraffic extends RequestHandler {
442 private ReqAllFlowTraffic() {
443 super(REQ_ALL_FLOW_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700444 }
445
446 @Override
447 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700448 traffic.monitor(Mode.ALL_FLOW_TRAFFIC);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700449 }
450 }
451
452 private final class ReqAllPortTraffic extends RequestHandler {
453 private ReqAllPortTraffic() {
454 super(REQ_ALL_PORT_TRAFFIC);
455 }
456
457 @Override
458 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700459 traffic.monitor(Mode.ALL_PORT_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700460 }
461 }
462
463 private final class ReqDevLinkFlows extends RequestHandler {
464 private ReqDevLinkFlows() {
465 super(REQ_DEV_LINK_FLOWS);
466 }
467
468 @Override
469 public void process(long sid, ObjectNode payload) {
Simon Hunta17fa672015-08-19 18:42:22 -0700470 NodeSelection nodeSelection =
471 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700472 traffic.monitor(Mode.DEV_LINK_FLOWS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700473 }
474 }
475
476 private final class ReqRelatedIntents extends RequestHandler {
477 private ReqRelatedIntents() {
478 super(REQ_RELATED_INTENTS);
479 }
480
481 @Override
482 public void process(long sid, ObjectNode payload) {
483 NodeSelection nodeSelection =
484 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700485 traffic.monitor(Mode.RELATED_INTENTS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700486 }
487 }
488
489 private final class ReqNextIntent extends RequestHandler {
490 private ReqNextIntent() {
491 super(REQ_NEXT_INTENT);
492 }
493
494 @Override
495 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700496 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700497 }
498 }
499
500 private final class ReqPrevIntent extends RequestHandler {
501 private ReqPrevIntent() {
502 super(REQ_PREV_INTENT);
503 }
504
505 @Override
506 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700507 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700508 }
509 }
510
511 private final class ReqSelectedIntentTraffic extends RequestHandler {
512 private ReqSelectedIntentTraffic() {
513 super(REQ_SEL_INTENT_TRAFFIC);
514 }
515
516 @Override
517 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700518 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700519 }
520 }
521
522 private final class CancelTraffic extends RequestHandler {
523 private CancelTraffic() {
524 super(CANCEL_TRAFFIC);
525 }
526
527 @Override
528 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700529 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700530 }
531 }
532
533 //=======================================================================
534
Simon Hunta17fa672015-08-19 18:42:22 -0700535 // Converts highlights to JSON format and sends the message to the client
536 protected void sendHighlights(Highlights highlights) {
537 sendMessage(JsonUtils.envelope(SHOW_HIGHLIGHTS, json(highlights)));
538 }
Simon Huntd2747a02015-04-30 22:41:16 -0700539
Thomas Vachuska329af532015-03-10 02:08:33 -0700540 // Sends the specified data to the client.
541 protected synchronized void sendMessage(ObjectNode data) {
542 UiConnection connection = connection();
543 if (connection != null) {
544 connection.sendMessage(data);
545 }
546 }
547
Simon Huntd2747a02015-04-30 22:41:16 -0700548 // Subscribes for summary messages.
549 private synchronized void requestSummary(long sid) {
Simon Hunt0af1ec32015-07-24 12:17:55 -0700550 PropertyPanel pp = summmaryMessage(sid);
551 overlayCache.currentOverlay().modifySummary(pp);
Simon Huntb745ca62015-07-28 15:37:11 -0700552 ObjectNode json = JsonUtils.envelope(SHOW_SUMMARY, sid, json(pp));
Simon Hunt0af1ec32015-07-24 12:17:55 -0700553 sendMessage(json);
Thomas Vachuska329af532015-03-10 02:08:33 -0700554 }
555
Simon Huntd2747a02015-04-30 22:41:16 -0700556
Thomas Vachuska329af532015-03-10 02:08:33 -0700557 private void cancelAllRequests() {
558 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700559 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700560 }
561
562 // Sends all controller nodes to the client as node-added messages.
563 private void sendAllInstances(String messageType) {
564 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
565 Collections.sort(nodes, NODE_COMPARATOR);
566 for (ControllerNode node : nodes) {
567 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
568 messageType));
569 }
570 }
571
572 // Sends all devices to the client as device-added messages.
573 private void sendAllDevices() {
574 // Send optical first, others later for layered rendering
575 for (Device device : deviceService.getDevices()) {
576 if (device.type() == Device.Type.ROADM) {
577 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
578 }
579 }
580 for (Device device : deviceService.getDevices()) {
581 if (device.type() != Device.Type.ROADM) {
582 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
583 }
584 }
585 }
586
587 // Sends all links to the client as link-added messages.
588 private void sendAllLinks() {
589 // Send optical first, others later for layered rendering
590 for (Link link : linkService.getLinks()) {
591 if (link.type() == Link.Type.OPTICAL) {
592 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
593 }
594 }
595 for (Link link : linkService.getLinks()) {
596 if (link.type() != Link.Type.OPTICAL) {
597 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
598 }
599 }
600 }
601
602 // Sends all hosts to the client as host-added messages.
603 private void sendAllHosts() {
604 for (Host host : hostService.getHosts()) {
605 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
606 }
607 }
608
Thomas Vachuska329af532015-03-10 02:08:33 -0700609 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
610 Set<ConnectPoint> points = new HashSet<>();
611 for (HostId hostId : hostIds) {
612 points.add(getHostLocation(hostId));
613 }
614 return points;
615 }
616
617 private HostLocation getHostLocation(HostId hostId) {
618 return hostService.getHost(hostId).location();
619 }
620
621 // Produces a list of host ids from the specified JSON array.
622 private Set<HostId> getHostIds(ArrayNode ids) {
623 Set<HostId> hostIds = new HashSet<>();
624 for (JsonNode id : ids) {
625 hostIds.add(hostId(id.asText()));
626 }
627 return hostIds;
628 }
629
630
Simon Huntd2747a02015-04-30 22:41:16 -0700631 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700632 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700633 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700634 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700635 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700636 }
637
638 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700639 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700640 summaryTask.cancel();
641 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700642 }
Simon Huntd2747a02015-04-30 22:41:16 -0700643 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700644 }
645
Thomas Vachuska329af532015-03-10 02:08:33 -0700646
647 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700648 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700649 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700650 clusterService.addListener(clusterListener);
651 mastershipService.addListener(mastershipListener);
652 deviceService.addListener(deviceListener);
653 linkService.addListener(linkListener);
654 hostService.addListener(hostListener);
655 intentService.addListener(intentListener);
656 flowService.addListener(flowListener);
657 }
658
659 // Removes all internal listeners.
660 private synchronized void removeListeners() {
661 if (!listenersRemoved) {
662 listenersRemoved = true;
663 clusterService.removeListener(clusterListener);
664 mastershipService.removeListener(mastershipListener);
665 deviceService.removeListener(deviceListener);
666 linkService.removeListener(linkListener);
667 hostService.removeListener(hostListener);
668 intentService.removeListener(intentListener);
669 flowService.removeListener(flowListener);
670 }
671 }
672
673 // Cluster event listener.
674 private class InternalClusterListener implements ClusterEventListener {
675 @Override
676 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700677 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700678 }
679 }
680
681 // Mastership change listener
682 private class InternalMastershipListener implements MastershipListener {
683 @Override
684 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700685 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700686 sendAllInstances(UPDATE_INSTANCE);
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700687 Device device = deviceService.getDevice(event.subject());
688 if (device != null) {
689 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
690 }
691 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700692 }
693 }
694
695 // Device event listener.
696 private class InternalDeviceListener implements DeviceListener {
697 @Override
698 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700699 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700700 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700701 eventAccummulator.add(event);
702 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700703 }
704 }
705
706 // Link event listener.
707 private class InternalLinkListener implements LinkListener {
708 @Override
709 public void event(LinkEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700710 msgSender.execute(() -> sendMessage(linkMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700711 eventAccummulator.add(event);
712 }
713 }
714
715 // Host event listener.
716 private class InternalHostListener implements HostListener {
717 @Override
718 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700719 msgSender.execute(() -> sendMessage(hostMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700720 eventAccummulator.add(event);
721 }
722 }
723
724 // Intent event listener.
725 private class InternalIntentListener implements IntentListener {
726 @Override
727 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700728 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700729 eventAccummulator.add(event);
730 }
731 }
732
733 // Intent event listener.
734 private class InternalFlowListener implements FlowRuleListener {
735 @Override
736 public void event(FlowRuleEvent event) {
737 eventAccummulator.add(event);
738 }
739 }
740
Simon Huntd2747a02015-04-30 22:41:16 -0700741
Simon Hunta17fa672015-08-19 18:42:22 -0700742 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -0700743
744 // Periodic update of the summary information
745 private class SummaryMonitor extends TimerTask {
746 @Override
747 public void run() {
748 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700749 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700750 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700751 }
752 } catch (Exception e) {
753 log.warn("Unable to handle summary request due to {}", e.getMessage());
754 log.warn("Boom!", e);
755 }
756 }
757 }
758
759 // Accumulates events to drive methodic update of the summary pane.
760 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
761 protected InternalEventAccummulator() {
762 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
763 }
764
765 @Override
766 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -0700767 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700768 long now = System.currentTimeMillis();
769 String me = this.toString();
770 String miniMe = me.replaceAll("^.*@", "me@");
771 log.debug("Time: {}; this: {}, processing items ({} events)",
772 now, miniMe, items.size());
773 // End-of-Debugging
774
Thomas Vachuska329af532015-03-10 02:08:33 -0700775 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700776 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700777 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700778 }
779 } catch (Exception e) {
780 log.warn("Unable to handle summary request due to {}", e.getMessage());
781 log.debug("Boom!", e);
782 }
783 }
784 }
785}