blob: 1e8f403f407f427a341cb5b9ed5b5a569e9446cc [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.RequestHandler;
Thomas Vachuska329af532015-03-10 02:08:33 -070057import org.onosproject.ui.UiConnection;
Simon Hunt4fc86852015-08-20 17:57:52 -070058import org.onosproject.ui.impl.TrafficMonitor.Mode;
Simon Hunta17fa672015-08-19 18:42:22 -070059import org.onosproject.ui.topo.Highlights;
Simon Huntd3ceffa2015-08-25 12:44:35 -070060import org.onosproject.ui.topo.NodeSelection;
Simon Hunt0af1ec32015-07-24 12:17:55 -070061import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070062
63import java.util.ArrayList;
Simon Huntd2747a02015-04-30 22:41:16 -070064import java.util.Collection;
Thomas Vachuska329af532015-03-10 02:08:33 -070065import java.util.Collections;
66import java.util.Comparator;
67import java.util.HashSet;
68import java.util.List;
69import java.util.Set;
70import java.util.Timer;
71import java.util.TimerTask;
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070072import java.util.concurrent.ExecutorService;
Thomas Vachuska329af532015-03-10 02:08:33 -070073
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070074import static java.util.concurrent.Executors.newSingleThreadExecutor;
75import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska329af532015-03-10 02:08:33 -070076import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
77import static org.onosproject.net.DeviceId.deviceId;
78import static org.onosproject.net.HostId.hostId;
Thomas Vachuskacb5016f2015-05-18 14:11:43 -070079import static org.onosproject.net.device.DeviceEvent.Type.*;
Thomas Vachuska329af532015-03-10 02:08:33 -070080import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
81import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
Simon Huntd3ceffa2015-08-25 12:44:35 -070082import static org.onosproject.ui.JsonUtils.envelope;
83import static org.onosproject.ui.impl.topo.TopoJson.json;
Thomas Vachuska329af532015-03-10 02:08:33 -070084
85/**
86 * Web socket capable of interacting with the GUI topology view.
87 */
88public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
89
Simon Huntb745ca62015-07-28 15:37:11 -070090 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -070091 private static final String REQ_DETAILS = "requestDetails";
92 private static final String UPDATE_META = "updateMeta";
93 private static final String ADD_HOST_INTENT = "addHostIntent";
94 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
95 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
96 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
97 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
98 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -070099 private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
100 private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700101 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
102 private static final String CANCEL_TRAFFIC = "cancelTraffic";
103 private static final String REQ_SUMMARY = "requestSummary";
104 private static final String CANCEL_SUMMARY = "cancelSummary";
105 private static final String EQ_MASTERS = "equalizeMasters";
106 private static final String SPRITE_LIST_REQ = "spriteListRequest";
107 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
108 private static final String TOPO_START = "topoStart";
Simon Hunt732bb2e2015-05-13 18:32:16 -0700109 private static final String TOPO_HEARTBEAT = "topoHeartbeat";
Simon Hunte05cae42015-07-23 17:35:24 -0700110 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700111 private static final String TOPO_STOP = "topoStop";
112
Simon Huntb745ca62015-07-28 15:37:11 -0700113 // outgoing event types
114 private static final String SHOW_SUMMARY = "showSummary";
115 private static final String SHOW_DETAILS = "showDetails";
116 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
117 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
118 private static final String UPDATE_INSTANCE = "updateInstance";
119
120 // fields
121 private static final String ID = "id";
Simon Huntb745ca62015-07-28 15:37:11 -0700122 private static final String DEVICE = "device";
123 private static final String HOST = "host";
124 private static final String CLASS = "class";
125 private static final String UNKNOWN = "unknown";
126 private static final String ONE = "one";
127 private static final String TWO = "two";
128 private static final String SRC = "src";
129 private static final String DST = "dst";
130 private static final String DATA = "data";
131 private static final String NAME = "name";
132 private static final String NAMES = "names";
133 private static final String ACTIVATE = "activate";
134 private static final String DEACTIVATE = "deactivate";
Simon Huntb745ca62015-07-28 15:37:11 -0700135
Simon Huntd2747a02015-04-30 22:41:16 -0700136
Thomas Vachuska329af532015-03-10 02:08:33 -0700137 private static final String APP_ID = "org.onosproject.gui";
138
Simon Hunta17fa672015-08-19 18:42:22 -0700139 private static final long TRAFFIC_PERIOD = 5000;
140 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700141
142 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Thomas Vachuskac0fe09a2015-05-21 12:56:22 -0700143 (o1, o2) -> o1.id().toString().compareTo(o2.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700144
145
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700146 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700147
148 private static final int MAX_EVENTS = 1000;
149 private static final int MAX_BATCH_MS = 5000;
150 private static final int MAX_IDLE_MS = 1000;
151
152 private ApplicationId appId;
153
154 private final ClusterEventListener clusterListener = new InternalClusterListener();
155 private final MastershipListener mastershipListener = new InternalMastershipListener();
156 private final DeviceListener deviceListener = new InternalDeviceListener();
157 private final LinkListener linkListener = new InternalLinkListener();
158 private final HostListener hostListener = new InternalHostListener();
159 private final IntentListener intentListener = new InternalIntentListener();
160 private final FlowRuleListener flowListener = new InternalFlowListener();
161
162 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700163 private final ExecutorService msgSender =
164 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender"));
Thomas Vachuska329af532015-03-10 02:08:33 -0700165
Simon Hunta17fa672015-08-19 18:42:22 -0700166 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700167 private TrafficMonitor traffic;
Thomas Vachuska329af532015-03-10 02:08:33 -0700168
Simon Huntd2747a02015-04-30 22:41:16 -0700169 private TimerTask summaryTask = null;
170 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700171
172 private boolean listenersRemoved = false;
173
Thomas Vachuska329af532015-03-10 02:08:33 -0700174
175 @Override
176 public void init(UiConnection connection, ServiceDirectory directory) {
177 super.init(connection, directory);
Thomas Vachuska329af532015-03-10 02:08:33 -0700178 appId = directory.get(CoreService.class).registerApplication(APP_ID);
Simon Hunt4fc86852015-08-20 17:57:52 -0700179 traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700180 }
181
182 @Override
183 public void destroy() {
184 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700185 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700186 super.destroy();
187 }
188
Thomas Vachuska329af532015-03-10 02:08:33 -0700189 @Override
Simon Huntda580882015-05-12 20:58:18 -0700190 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700191 return ImmutableSet.of(
192 new TopoStart(),
Simon Hunt732bb2e2015-05-13 18:32:16 -0700193 new TopoHeartbeat(),
Simon Hunte05cae42015-07-23 17:35:24 -0700194 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700195 new TopoStop(),
196 new ReqSummary(),
197 new CancelSummary(),
198 new SpriteListReq(),
199 new SpriteDataReq(),
200 new RequestDetails(),
201 new UpdateMeta(),
202 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700203
Simon Huntd2747a02015-04-30 22:41:16 -0700204 // TODO: migrate traffic related to separate app
205 new AddHostIntent(),
206 new AddMultiSourceIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700207
208 new ReqAllFlowTraffic(),
209 new ReqAllPortTraffic(),
210 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700211 new ReqRelatedIntents(),
212 new ReqNextIntent(),
213 new ReqPrevIntent(),
214 new ReqSelectedIntentTraffic(),
Simon Hunta17fa672015-08-19 18:42:22 -0700215
Simon Huntd2747a02015-04-30 22:41:16 -0700216 new CancelTraffic()
217 );
218 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700219
Simon Hunte05cae42015-07-23 17:35:24 -0700220 /**
221 * Injects the topology overlay cache.
222 *
223 * @param overlayCache injected cache
224 */
225 void setOverlayCache(TopoOverlayCache overlayCache) {
226 this.overlayCache = overlayCache;
227 }
228
Simon Huntd2747a02015-04-30 22:41:16 -0700229 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700230
Simon Huntd2747a02015-04-30 22:41:16 -0700231 private final class TopoStart extends RequestHandler {
232 private TopoStart() {
233 super(TOPO_START);
234 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700235
Simon Huntd2747a02015-04-30 22:41:16 -0700236 @Override
237 public void process(long sid, ObjectNode payload) {
238 addListeners();
239 sendAllInstances(null);
240 sendAllDevices();
241 sendAllLinks();
242 sendAllHosts();
Thomas Vachuska329af532015-03-10 02:08:33 -0700243 }
244 }
245
Simon Hunt732bb2e2015-05-13 18:32:16 -0700246 private final class TopoHeartbeat extends RequestHandler {
247 private TopoHeartbeat() {
248 super(TOPO_HEARTBEAT);
249 }
250
251 @Override
252 public void process(long sid, ObjectNode payload) {
253 // place holder for now
254 }
255 }
256
Simon Hunte05cae42015-07-23 17:35:24 -0700257 private final class TopoSelectOverlay extends RequestHandler {
258 private TopoSelectOverlay() {
259 super(TOPO_SELECT_OVERLAY);
260 }
261
262 @Override
263 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700264 String deact = string(payload, DEACTIVATE);
265 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700266 overlayCache.switchOverlay(deact, act);
267 }
268 }
269
Simon Huntd2747a02015-04-30 22:41:16 -0700270 private final class TopoStop extends RequestHandler {
271 private TopoStop() {
272 super(TOPO_STOP);
273 }
274
275 @Override
276 public void process(long sid, ObjectNode payload) {
277 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700278 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700279 }
280 }
281
282 private final class ReqSummary extends RequestHandler {
283 private ReqSummary() {
284 super(REQ_SUMMARY);
285 }
286
287 @Override
288 public void process(long sid, ObjectNode payload) {
289 requestSummary(sid);
290 startSummaryMonitoring();
291 }
292 }
293
294 private final class CancelSummary extends RequestHandler {
295 private CancelSummary() {
296 super(CANCEL_SUMMARY);
297 }
298
299 @Override
300 public void process(long sid, ObjectNode payload) {
301 stopSummaryMonitoring();
302 }
303 }
304
305 private final class SpriteListReq extends RequestHandler {
306 private SpriteListReq() {
307 super(SPRITE_LIST_REQ);
308 }
309
310 @Override
311 public void process(long sid, ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700312 ObjectNode root = objectNode();
313 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700314 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700315 root.set(NAMES, names);
316 sendMessage(SPRITE_LIST_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700317 }
318 }
319
320 private final class SpriteDataReq extends RequestHandler {
321 private SpriteDataReq() {
322 super(SPRITE_DATA_REQ);
323 }
324
325 @Override
326 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700327 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700328 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700329 root.set(DATA, get(SpriteService.class).get(name));
330 sendMessage(SPRITE_DATA_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700331 }
332 }
333
334 private final class RequestDetails extends RequestHandler {
335 private RequestDetails() {
336 super(REQ_DETAILS);
337 }
338
339 @Override
340 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700341 String type = string(payload, CLASS, UNKNOWN);
342 String id = string(payload, ID);
343 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700344
Simon Huntb745ca62015-07-28 15:37:11 -0700345 if (type.equals(DEVICE)) {
346 pp = deviceDetails(deviceId(id), sid);
347 overlayCache.currentOverlay().modifyDeviceDetails(pp);
348 } else if (type.equals(HOST)) {
349 pp = hostDetails(hostId(id), sid);
350 overlayCache.currentOverlay().modifyHostDetails(pp);
Simon Huntd2747a02015-04-30 22:41:16 -0700351 }
Simon Huntb745ca62015-07-28 15:37:11 -0700352
Simon Huntd3ceffa2015-08-25 12:44:35 -0700353 sendMessage(envelope(SHOW_DETAILS, sid, json(pp)));
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 Huntd2862c32015-08-24 17:41:51 -0700402 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
403 traffic.monitor(intent);
404 }
Simon Huntd2747a02015-04-30 22:41:16 -0700405 }
406 }
407
408 private final class AddMultiSourceIntent extends RequestHandler {
409 private AddMultiSourceIntent() {
410 super(ADD_MULTI_SRC_INTENT);
411 }
412
413 @Override
414 public void process(long sid, ObjectNode payload) {
415 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700416 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
417 HostId dst = hostId(string(payload, DST));
Simon Huntd2747a02015-04-30 22:41:16 -0700418 Host dstHost = hostService.getHost(dst);
419
420 Set<ConnectPoint> ingressPoints = getHostLocations(src);
421
422 // FIXME: clearly, this is not enough
423 TrafficSelector selector = DefaultTrafficSelector.builder()
424 .matchEthDst(dstHost.mac()).build();
425 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
426
427 MultiPointToSinglePointIntent intent =
428 MultiPointToSinglePointIntent.builder()
429 .appId(appId)
430 .selector(selector)
431 .treatment(treatment)
432 .ingressPoints(ingressPoints)
433 .egressPoint(dstHost.location())
434 .build();
435
436 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700437 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
438 traffic.monitor(intent);
439 }
Simon Huntd2747a02015-04-30 22:41:16 -0700440 }
441 }
442
Simon Hunta17fa672015-08-19 18:42:22 -0700443 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700444
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700445 private final class ReqAllFlowTraffic extends RequestHandler {
446 private ReqAllFlowTraffic() {
447 super(REQ_ALL_FLOW_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700448 }
449
450 @Override
451 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700452 traffic.monitor(Mode.ALL_FLOW_TRAFFIC);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700453 }
454 }
455
456 private final class ReqAllPortTraffic extends RequestHandler {
457 private ReqAllPortTraffic() {
458 super(REQ_ALL_PORT_TRAFFIC);
459 }
460
461 @Override
462 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700463 traffic.monitor(Mode.ALL_PORT_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700464 }
465 }
466
467 private final class ReqDevLinkFlows extends RequestHandler {
468 private ReqDevLinkFlows() {
469 super(REQ_DEV_LINK_FLOWS);
470 }
471
472 @Override
473 public void process(long sid, ObjectNode payload) {
Simon Hunta17fa672015-08-19 18:42:22 -0700474 NodeSelection nodeSelection =
475 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700476 traffic.monitor(Mode.DEV_LINK_FLOWS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700477 }
478 }
479
480 private final class ReqRelatedIntents extends RequestHandler {
481 private ReqRelatedIntents() {
482 super(REQ_RELATED_INTENTS);
483 }
484
485 @Override
486 public void process(long sid, ObjectNode payload) {
487 NodeSelection nodeSelection =
488 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700489 traffic.monitor(Mode.RELATED_INTENTS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700490 }
491 }
492
493 private final class ReqNextIntent extends RequestHandler {
494 private ReqNextIntent() {
495 super(REQ_NEXT_INTENT);
496 }
497
498 @Override
499 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700500 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700501 }
502 }
503
504 private final class ReqPrevIntent extends RequestHandler {
505 private ReqPrevIntent() {
506 super(REQ_PREV_INTENT);
507 }
508
509 @Override
510 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700511 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700512 }
513 }
514
515 private final class ReqSelectedIntentTraffic extends RequestHandler {
516 private ReqSelectedIntentTraffic() {
517 super(REQ_SEL_INTENT_TRAFFIC);
518 }
519
520 @Override
521 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700522 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700523 }
524 }
525
526 private final class CancelTraffic extends RequestHandler {
527 private CancelTraffic() {
528 super(CANCEL_TRAFFIC);
529 }
530
531 @Override
532 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700533 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700534 }
535 }
536
537 //=======================================================================
538
Simon Hunta17fa672015-08-19 18:42:22 -0700539 // Converts highlights to JSON format and sends the message to the client
540 protected void sendHighlights(Highlights highlights) {
Simon Huntd3ceffa2015-08-25 12:44:35 -0700541 sendMessage(envelope(SHOW_HIGHLIGHTS, json(highlights)));
Simon Hunta17fa672015-08-19 18:42:22 -0700542 }
Simon Huntd2747a02015-04-30 22:41:16 -0700543
Thomas Vachuska329af532015-03-10 02:08:33 -0700544 // Sends the specified data to the client.
545 protected synchronized void sendMessage(ObjectNode data) {
546 UiConnection connection = connection();
547 if (connection != null) {
548 connection.sendMessage(data);
549 }
550 }
551
Simon Huntd2747a02015-04-30 22:41:16 -0700552 // Subscribes for summary messages.
553 private synchronized void requestSummary(long sid) {
Simon Hunt0af1ec32015-07-24 12:17:55 -0700554 PropertyPanel pp = summmaryMessage(sid);
555 overlayCache.currentOverlay().modifySummary(pp);
Simon Huntd3ceffa2015-08-25 12:44:35 -0700556 sendMessage(envelope(SHOW_SUMMARY, sid, json(pp)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700557 }
558
Simon Huntd2747a02015-04-30 22:41:16 -0700559
Thomas Vachuska329af532015-03-10 02:08:33 -0700560 private void cancelAllRequests() {
561 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700562 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700563 }
564
565 // Sends all controller nodes to the client as node-added messages.
566 private void sendAllInstances(String messageType) {
567 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
568 Collections.sort(nodes, NODE_COMPARATOR);
569 for (ControllerNode node : nodes) {
570 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
571 messageType));
572 }
573 }
574
575 // Sends all devices to the client as device-added messages.
576 private void sendAllDevices() {
577 // Send optical first, others later for layered rendering
578 for (Device device : deviceService.getDevices()) {
579 if (device.type() == Device.Type.ROADM) {
580 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
581 }
582 }
583 for (Device device : deviceService.getDevices()) {
584 if (device.type() != Device.Type.ROADM) {
585 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
586 }
587 }
588 }
589
590 // Sends all links to the client as link-added messages.
591 private void sendAllLinks() {
592 // Send optical first, others later for layered rendering
593 for (Link link : linkService.getLinks()) {
594 if (link.type() == Link.Type.OPTICAL) {
595 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
596 }
597 }
598 for (Link link : linkService.getLinks()) {
599 if (link.type() != Link.Type.OPTICAL) {
600 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
601 }
602 }
603 }
604
605 // Sends all hosts to the client as host-added messages.
606 private void sendAllHosts() {
607 for (Host host : hostService.getHosts()) {
608 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
609 }
610 }
611
Thomas Vachuska329af532015-03-10 02:08:33 -0700612 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
613 Set<ConnectPoint> points = new HashSet<>();
614 for (HostId hostId : hostIds) {
615 points.add(getHostLocation(hostId));
616 }
617 return points;
618 }
619
620 private HostLocation getHostLocation(HostId hostId) {
621 return hostService.getHost(hostId).location();
622 }
623
624 // Produces a list of host ids from the specified JSON array.
625 private Set<HostId> getHostIds(ArrayNode ids) {
626 Set<HostId> hostIds = new HashSet<>();
627 for (JsonNode id : ids) {
628 hostIds.add(hostId(id.asText()));
629 }
630 return hostIds;
631 }
632
633
Simon Huntd2747a02015-04-30 22:41:16 -0700634 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700635 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700636 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700637 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700638 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700639 }
640
641 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700642 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700643 summaryTask.cancel();
644 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700645 }
Simon Huntd2747a02015-04-30 22:41:16 -0700646 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700647 }
648
Thomas Vachuska329af532015-03-10 02:08:33 -0700649
650 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700651 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700652 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700653 clusterService.addListener(clusterListener);
654 mastershipService.addListener(mastershipListener);
655 deviceService.addListener(deviceListener);
656 linkService.addListener(linkListener);
657 hostService.addListener(hostListener);
658 intentService.addListener(intentListener);
659 flowService.addListener(flowListener);
660 }
661
662 // Removes all internal listeners.
663 private synchronized void removeListeners() {
664 if (!listenersRemoved) {
665 listenersRemoved = true;
666 clusterService.removeListener(clusterListener);
667 mastershipService.removeListener(mastershipListener);
668 deviceService.removeListener(deviceListener);
669 linkService.removeListener(linkListener);
670 hostService.removeListener(hostListener);
671 intentService.removeListener(intentListener);
672 flowService.removeListener(flowListener);
673 }
674 }
675
676 // Cluster event listener.
677 private class InternalClusterListener implements ClusterEventListener {
678 @Override
679 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700680 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700681 }
682 }
683
684 // Mastership change listener
685 private class InternalMastershipListener implements MastershipListener {
686 @Override
687 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700688 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700689 sendAllInstances(UPDATE_INSTANCE);
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700690 Device device = deviceService.getDevice(event.subject());
691 if (device != null) {
692 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
693 }
694 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700695 }
696 }
697
698 // Device event listener.
699 private class InternalDeviceListener implements DeviceListener {
700 @Override
701 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700702 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700703 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700704 eventAccummulator.add(event);
705 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700706 }
707 }
708
709 // Link event listener.
710 private class InternalLinkListener implements LinkListener {
711 @Override
712 public void event(LinkEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700713 msgSender.execute(() -> sendMessage(linkMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700714 eventAccummulator.add(event);
715 }
716 }
717
718 // Host event listener.
719 private class InternalHostListener implements HostListener {
720 @Override
721 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700722 msgSender.execute(() -> sendMessage(hostMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700723 eventAccummulator.add(event);
724 }
725 }
726
727 // Intent event listener.
728 private class InternalIntentListener implements IntentListener {
729 @Override
730 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700731 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700732 eventAccummulator.add(event);
733 }
734 }
735
736 // Intent event listener.
737 private class InternalFlowListener implements FlowRuleListener {
738 @Override
739 public void event(FlowRuleEvent event) {
740 eventAccummulator.add(event);
741 }
742 }
743
Simon Huntd2747a02015-04-30 22:41:16 -0700744
Simon Hunta17fa672015-08-19 18:42:22 -0700745 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -0700746
747 // Periodic update of the summary information
748 private class SummaryMonitor extends TimerTask {
749 @Override
750 public void run() {
751 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700752 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700753 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700754 }
755 } catch (Exception e) {
756 log.warn("Unable to handle summary request due to {}", e.getMessage());
757 log.warn("Boom!", e);
758 }
759 }
760 }
761
762 // Accumulates events to drive methodic update of the summary pane.
763 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
764 protected InternalEventAccummulator() {
765 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
766 }
767
768 @Override
769 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -0700770 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700771 long now = System.currentTimeMillis();
772 String me = this.toString();
773 String miniMe = me.replaceAll("^.*@", "me@");
774 log.debug("Time: {}; this: {}, processing items ({} events)",
775 now, miniMe, items.size());
776 // End-of-Debugging
777
Thomas Vachuska329af532015-03-10 02:08:33 -0700778 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700779 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700780 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700781 }
782 } catch (Exception e) {
783 log.warn("Unable to handle summary request due to {}", e.getMessage());
784 log.debug("Boom!", e);
785 }
786 }
787 }
788}