blob: 292a5f9585b7ebff9866c3a2014a69910568f1d9 [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;
Simon Huntde99e0b2015-10-23 18:54:06 -070036import org.onosproject.net.DeviceId;
Thomas Vachuska329af532015-03-10 02:08:33 -070037import org.onosproject.net.Host;
38import org.onosproject.net.HostId;
39import org.onosproject.net.HostLocation;
40import org.onosproject.net.Link;
41import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
43import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.FlowRuleEvent;
46import org.onosproject.net.flow.FlowRuleListener;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
49import org.onosproject.net.host.HostEvent;
50import org.onosproject.net.host.HostListener;
51import org.onosproject.net.intent.HostToHostIntent;
Thomas Vachuska329af532015-03-10 02:08:33 -070052import 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;
Simon Huntd2747a02015-04-30 22:41:16 -070057import 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.topo.Highlights;
Simon Huntd3ceffa2015-08-25 12:44:35 -070061import org.onosproject.ui.topo.NodeSelection;
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;
Simon Huntd3ceffa2015-08-25 12:44:35 -070083import static org.onosproject.ui.JsonUtils.envelope;
Simon Hunt52560662015-08-27 22:46:44 -070084import static org.onosproject.ui.topo.TopoJson.highlightsMessage;
85import static org.onosproject.ui.topo.TopoJson.json;
Thomas Vachuska329af532015-03-10 02:08:33 -070086
87/**
88 * Web socket capable of interacting with the GUI topology view.
89 */
90public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
91
Simon Huntb745ca62015-07-28 15:37:11 -070092 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -070093 private static final String REQ_DETAILS = "requestDetails";
94 private static final String UPDATE_META = "updateMeta";
95 private static final String ADD_HOST_INTENT = "addHostIntent";
96 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
97 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
98 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
99 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
100 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700101 private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
102 private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700103 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
104 private static final String CANCEL_TRAFFIC = "cancelTraffic";
105 private static final String REQ_SUMMARY = "requestSummary";
106 private static final String CANCEL_SUMMARY = "cancelSummary";
107 private static final String EQ_MASTERS = "equalizeMasters";
108 private static final String SPRITE_LIST_REQ = "spriteListRequest";
109 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
110 private static final String TOPO_START = "topoStart";
Simon Hunt732bb2e2015-05-13 18:32:16 -0700111 private static final String TOPO_HEARTBEAT = "topoHeartbeat";
Simon Hunte05cae42015-07-23 17:35:24 -0700112 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700113 private static final String TOPO_STOP = "topoStop";
114
Simon Huntb745ca62015-07-28 15:37:11 -0700115 // outgoing event types
116 private static final String SHOW_SUMMARY = "showSummary";
117 private static final String SHOW_DETAILS = "showDetails";
118 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
119 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
120 private static final String UPDATE_INSTANCE = "updateInstance";
121
122 // fields
123 private static final String ID = "id";
Simon Huntb745ca62015-07-28 15:37:11 -0700124 private static final String DEVICE = "device";
125 private static final String HOST = "host";
126 private static final String CLASS = "class";
127 private static final String UNKNOWN = "unknown";
128 private static final String ONE = "one";
129 private static final String TWO = "two";
130 private static final String SRC = "src";
131 private static final String DST = "dst";
132 private static final String DATA = "data";
133 private static final String NAME = "name";
134 private static final String NAMES = "names";
135 private static final String ACTIVATE = "activate";
136 private static final String DEACTIVATE = "deactivate";
Simon Huntb745ca62015-07-28 15:37:11 -0700137
Simon Huntd2747a02015-04-30 22:41:16 -0700138
Thomas Vachuska329af532015-03-10 02:08:33 -0700139 private static final String APP_ID = "org.onosproject.gui";
140
Simon Hunta17fa672015-08-19 18:42:22 -0700141 private static final long TRAFFIC_PERIOD = 5000;
142 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700143
144 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Thomas Vachuskac0fe09a2015-05-21 12:56:22 -0700145 (o1, o2) -> o1.id().toString().compareTo(o2.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700146
147
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700148 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700149
150 private static final int MAX_EVENTS = 1000;
151 private static final int MAX_BATCH_MS = 5000;
152 private static final int MAX_IDLE_MS = 1000;
153
154 private ApplicationId appId;
155
156 private final ClusterEventListener clusterListener = new InternalClusterListener();
157 private final MastershipListener mastershipListener = new InternalMastershipListener();
158 private final DeviceListener deviceListener = new InternalDeviceListener();
159 private final LinkListener linkListener = new InternalLinkListener();
160 private final HostListener hostListener = new InternalHostListener();
161 private final IntentListener intentListener = new InternalIntentListener();
162 private final FlowRuleListener flowListener = new InternalFlowListener();
163
164 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700165 private final ExecutorService msgSender =
166 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender"));
Thomas Vachuska329af532015-03-10 02:08:33 -0700167
Simon Hunta17fa672015-08-19 18:42:22 -0700168 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700169 private TrafficMonitor traffic;
Thomas Vachuska329af532015-03-10 02:08:33 -0700170
Simon Huntd2747a02015-04-30 22:41:16 -0700171 private TimerTask summaryTask = null;
172 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700173
174 private boolean listenersRemoved = false;
175
Thomas Vachuska329af532015-03-10 02:08:33 -0700176
177 @Override
178 public void init(UiConnection connection, ServiceDirectory directory) {
179 super.init(connection, directory);
Thomas Vachuska329af532015-03-10 02:08:33 -0700180 appId = directory.get(CoreService.class).registerApplication(APP_ID);
Simon Hunt4fc86852015-08-20 17:57:52 -0700181 traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700182 }
183
184 @Override
185 public void destroy() {
186 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700187 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700188 super.destroy();
189 }
190
Thomas Vachuska329af532015-03-10 02:08:33 -0700191 @Override
Simon Huntda580882015-05-12 20:58:18 -0700192 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700193 return ImmutableSet.of(
194 new TopoStart(),
Simon Hunt732bb2e2015-05-13 18:32:16 -0700195 new TopoHeartbeat(),
Simon Hunte05cae42015-07-23 17:35:24 -0700196 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700197 new TopoStop(),
198 new ReqSummary(),
199 new CancelSummary(),
200 new SpriteListReq(),
201 new SpriteDataReq(),
202 new RequestDetails(),
203 new UpdateMeta(),
204 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700205
Simon Huntd2747a02015-04-30 22:41:16 -0700206 // TODO: migrate traffic related to separate app
207 new AddHostIntent(),
208 new AddMultiSourceIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700209
210 new ReqAllFlowTraffic(),
211 new ReqAllPortTraffic(),
212 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700213 new ReqRelatedIntents(),
214 new ReqNextIntent(),
215 new ReqPrevIntent(),
216 new ReqSelectedIntentTraffic(),
Simon Hunta17fa672015-08-19 18:42:22 -0700217
Simon Huntd2747a02015-04-30 22:41:16 -0700218 new CancelTraffic()
219 );
220 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700221
Simon Hunte05cae42015-07-23 17:35:24 -0700222 /**
223 * Injects the topology overlay cache.
224 *
225 * @param overlayCache injected cache
226 */
227 void setOverlayCache(TopoOverlayCache overlayCache) {
228 this.overlayCache = overlayCache;
229 }
230
Simon Huntd2747a02015-04-30 22:41:16 -0700231 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700232
Simon Huntd2747a02015-04-30 22:41:16 -0700233 private final class TopoStart extends RequestHandler {
234 private TopoStart() {
235 super(TOPO_START);
236 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700237
Simon Huntd2747a02015-04-30 22:41:16 -0700238 @Override
239 public void process(long sid, ObjectNode payload) {
240 addListeners();
241 sendAllInstances(null);
242 sendAllDevices();
243 sendAllLinks();
244 sendAllHosts();
Thomas Vachuska329af532015-03-10 02:08:33 -0700245 }
246 }
247
Simon Hunt732bb2e2015-05-13 18:32:16 -0700248 private final class TopoHeartbeat extends RequestHandler {
249 private TopoHeartbeat() {
250 super(TOPO_HEARTBEAT);
251 }
252
253 @Override
254 public void process(long sid, ObjectNode payload) {
255 // place holder for now
256 }
257 }
258
Simon Hunte05cae42015-07-23 17:35:24 -0700259 private final class TopoSelectOverlay extends RequestHandler {
260 private TopoSelectOverlay() {
261 super(TOPO_SELECT_OVERLAY);
262 }
263
264 @Override
265 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700266 String deact = string(payload, DEACTIVATE);
267 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700268 overlayCache.switchOverlay(deact, act);
269 }
270 }
271
Simon Huntd2747a02015-04-30 22:41:16 -0700272 private final class TopoStop extends RequestHandler {
273 private TopoStop() {
274 super(TOPO_STOP);
275 }
276
277 @Override
278 public void process(long sid, ObjectNode payload) {
279 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700280 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700281 }
282 }
283
284 private final class ReqSummary extends RequestHandler {
285 private ReqSummary() {
286 super(REQ_SUMMARY);
287 }
288
289 @Override
290 public void process(long sid, ObjectNode payload) {
291 requestSummary(sid);
292 startSummaryMonitoring();
293 }
294 }
295
296 private final class CancelSummary extends RequestHandler {
297 private CancelSummary() {
298 super(CANCEL_SUMMARY);
299 }
300
301 @Override
302 public void process(long sid, ObjectNode payload) {
303 stopSummaryMonitoring();
304 }
305 }
306
307 private final class SpriteListReq extends RequestHandler {
308 private SpriteListReq() {
309 super(SPRITE_LIST_REQ);
310 }
311
312 @Override
313 public void process(long sid, ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700314 ObjectNode root = objectNode();
315 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700316 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700317 root.set(NAMES, names);
318 sendMessage(SPRITE_LIST_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700319 }
320 }
321
322 private final class SpriteDataReq extends RequestHandler {
323 private SpriteDataReq() {
324 super(SPRITE_DATA_REQ);
325 }
326
327 @Override
328 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700329 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700330 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700331 root.set(DATA, get(SpriteService.class).get(name));
332 sendMessage(SPRITE_DATA_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700333 }
334 }
335
336 private final class RequestDetails extends RequestHandler {
337 private RequestDetails() {
338 super(REQ_DETAILS);
339 }
340
341 @Override
342 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700343 String type = string(payload, CLASS, UNKNOWN);
344 String id = string(payload, ID);
345 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700346
Simon Huntb745ca62015-07-28 15:37:11 -0700347 if (type.equals(DEVICE)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700348 DeviceId did = deviceId(id);
349 pp = deviceDetails(did, sid);
350 overlayCache.currentOverlay().modifyDeviceDetails(pp, did);
Simon Huntb745ca62015-07-28 15:37:11 -0700351 } else if (type.equals(HOST)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700352 HostId hid = hostId(id);
353 pp = hostDetails(hid, sid);
354 overlayCache.currentOverlay().modifyHostDetails(pp, hid);
Simon Huntd2747a02015-04-30 22:41:16 -0700355 }
Simon Huntb745ca62015-07-28 15:37:11 -0700356
Simon Huntd3ceffa2015-08-25 12:44:35 -0700357 sendMessage(envelope(SHOW_DETAILS, sid, json(pp)));
Simon Huntd2747a02015-04-30 22:41:16 -0700358 }
359 }
360
361 private final class UpdateMeta extends RequestHandler {
362 private UpdateMeta() {
363 super(UPDATE_META);
364 }
365
366 @Override
367 public void process(long sid, ObjectNode payload) {
368 updateMetaUi(payload);
369 }
370 }
371
372 private final class EqMasters extends RequestHandler {
373 private EqMasters() {
374 super(EQ_MASTERS);
375 }
376
377 @Override
378 public void process(long sid, ObjectNode payload) {
379 directory.get(MastershipAdminService.class).balanceRoles();
380 }
381 }
382
Simon Hunta17fa672015-08-19 18:42:22 -0700383
384 // ========= -----------------------------------------------------------------
385
Simon Huntd2747a02015-04-30 22:41:16 -0700386 // === TODO: move traffic related classes to traffic app
387
388 private final class AddHostIntent extends RequestHandler {
389 private AddHostIntent() {
390 super(ADD_HOST_INTENT);
391 }
392
393 @Override
394 public void process(long sid, ObjectNode payload) {
395 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700396 HostId one = hostId(string(payload, ONE));
397 HostId two = hostId(string(payload, TWO));
Simon Huntd2747a02015-04-30 22:41:16 -0700398
399 HostToHostIntent intent = HostToHostIntent.builder()
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700400 .appId(appId)
401 .one(one)
402 .two(two)
403 .build();
Simon Huntd2747a02015-04-30 22:41:16 -0700404
405 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700406 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
407 traffic.monitor(intent);
408 }
Simon Huntd2747a02015-04-30 22:41:16 -0700409 }
410 }
411
412 private final class AddMultiSourceIntent extends RequestHandler {
413 private AddMultiSourceIntent() {
414 super(ADD_MULTI_SRC_INTENT);
415 }
416
417 @Override
418 public void process(long sid, ObjectNode payload) {
419 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700420 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
421 HostId dst = hostId(string(payload, DST));
Simon Huntd2747a02015-04-30 22:41:16 -0700422 Host dstHost = hostService.getHost(dst);
423
424 Set<ConnectPoint> ingressPoints = getHostLocations(src);
425
426 // FIXME: clearly, this is not enough
427 TrafficSelector selector = DefaultTrafficSelector.builder()
428 .matchEthDst(dstHost.mac()).build();
429 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
430
431 MultiPointToSinglePointIntent intent =
432 MultiPointToSinglePointIntent.builder()
433 .appId(appId)
434 .selector(selector)
435 .treatment(treatment)
436 .ingressPoints(ingressPoints)
437 .egressPoint(dstHost.location())
438 .build();
439
440 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700441 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
442 traffic.monitor(intent);
443 }
Simon Huntd2747a02015-04-30 22:41:16 -0700444 }
445 }
446
Simon Hunta17fa672015-08-19 18:42:22 -0700447 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700448
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700449 private final class ReqAllFlowTraffic extends RequestHandler {
450 private ReqAllFlowTraffic() {
451 super(REQ_ALL_FLOW_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700452 }
453
454 @Override
455 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700456 traffic.monitor(Mode.ALL_FLOW_TRAFFIC);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700457 }
458 }
459
460 private final class ReqAllPortTraffic extends RequestHandler {
461 private ReqAllPortTraffic() {
462 super(REQ_ALL_PORT_TRAFFIC);
463 }
464
465 @Override
466 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700467 traffic.monitor(Mode.ALL_PORT_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700468 }
469 }
470
471 private final class ReqDevLinkFlows extends RequestHandler {
472 private ReqDevLinkFlows() {
473 super(REQ_DEV_LINK_FLOWS);
474 }
475
476 @Override
477 public void process(long sid, ObjectNode payload) {
Simon Hunta17fa672015-08-19 18:42:22 -0700478 NodeSelection nodeSelection =
479 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700480 traffic.monitor(Mode.DEV_LINK_FLOWS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700481 }
482 }
483
484 private final class ReqRelatedIntents extends RequestHandler {
485 private ReqRelatedIntents() {
486 super(REQ_RELATED_INTENTS);
487 }
488
489 @Override
490 public void process(long sid, ObjectNode payload) {
491 NodeSelection nodeSelection =
492 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700493 traffic.monitor(Mode.RELATED_INTENTS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700494 }
495 }
496
497 private final class ReqNextIntent extends RequestHandler {
498 private ReqNextIntent() {
499 super(REQ_NEXT_INTENT);
500 }
501
502 @Override
503 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700504 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700505 }
506 }
507
508 private final class ReqPrevIntent extends RequestHandler {
509 private ReqPrevIntent() {
510 super(REQ_PREV_INTENT);
511 }
512
513 @Override
514 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700515 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700516 }
517 }
518
519 private final class ReqSelectedIntentTraffic extends RequestHandler {
520 private ReqSelectedIntentTraffic() {
521 super(REQ_SEL_INTENT_TRAFFIC);
522 }
523
524 @Override
525 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700526 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700527 }
528 }
529
530 private final class CancelTraffic extends RequestHandler {
531 private CancelTraffic() {
532 super(CANCEL_TRAFFIC);
533 }
534
535 @Override
536 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700537 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700538 }
539 }
540
541 //=======================================================================
542
Simon Hunta17fa672015-08-19 18:42:22 -0700543 // Converts highlights to JSON format and sends the message to the client
544 protected void sendHighlights(Highlights highlights) {
Simon Hunt52560662015-08-27 22:46:44 -0700545 sendMessage(highlightsMessage(highlights));
Thomas Vachuska329af532015-03-10 02:08:33 -0700546 }
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 Huntd3ceffa2015-08-25 12:44:35 -0700552 sendMessage(envelope(SHOW_SUMMARY, sid, json(pp)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700553 }
554
Simon Huntd2747a02015-04-30 22:41:16 -0700555
Thomas Vachuska329af532015-03-10 02:08:33 -0700556 private void cancelAllRequests() {
557 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700558 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700559 }
560
561 // Sends all controller nodes to the client as node-added messages.
562 private void sendAllInstances(String messageType) {
563 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
564 Collections.sort(nodes, NODE_COMPARATOR);
565 for (ControllerNode node : nodes) {
566 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
567 messageType));
568 }
569 }
570
571 // Sends all devices to the client as device-added messages.
572 private void sendAllDevices() {
573 // Send optical first, others later for layered rendering
574 for (Device device : deviceService.getDevices()) {
575 if (device.type() == Device.Type.ROADM) {
576 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
577 }
578 }
579 for (Device device : deviceService.getDevices()) {
580 if (device.type() != Device.Type.ROADM) {
581 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
582 }
583 }
584 }
585
586 // Sends all links to the client as link-added messages.
587 private void sendAllLinks() {
588 // Send optical first, others later for layered rendering
589 for (Link link : linkService.getLinks()) {
590 if (link.type() == Link.Type.OPTICAL) {
591 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
592 }
593 }
594 for (Link link : linkService.getLinks()) {
595 if (link.type() != Link.Type.OPTICAL) {
596 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
597 }
598 }
599 }
600
601 // Sends all hosts to the client as host-added messages.
602 private void sendAllHosts() {
603 for (Host host : hostService.getHosts()) {
604 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
605 }
606 }
607
Thomas Vachuska329af532015-03-10 02:08:33 -0700608 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
609 Set<ConnectPoint> points = new HashSet<>();
610 for (HostId hostId : hostIds) {
611 points.add(getHostLocation(hostId));
612 }
613 return points;
614 }
615
616 private HostLocation getHostLocation(HostId hostId) {
617 return hostService.getHost(hostId).location();
618 }
619
620 // Produces a list of host ids from the specified JSON array.
621 private Set<HostId> getHostIds(ArrayNode ids) {
622 Set<HostId> hostIds = new HashSet<>();
623 for (JsonNode id : ids) {
624 hostIds.add(hostId(id.asText()));
625 }
626 return hostIds;
627 }
628
629
Simon Huntd2747a02015-04-30 22:41:16 -0700630 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700631 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700632 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700633 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700634 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700635 }
636
637 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700638 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700639 summaryTask.cancel();
640 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700641 }
Simon Huntd2747a02015-04-30 22:41:16 -0700642 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700643 }
644
Thomas Vachuska329af532015-03-10 02:08:33 -0700645
646 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700647 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700648 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700649 clusterService.addListener(clusterListener);
650 mastershipService.addListener(mastershipListener);
651 deviceService.addListener(deviceListener);
652 linkService.addListener(linkListener);
653 hostService.addListener(hostListener);
654 intentService.addListener(intentListener);
655 flowService.addListener(flowListener);
656 }
657
658 // Removes all internal listeners.
659 private synchronized void removeListeners() {
660 if (!listenersRemoved) {
661 listenersRemoved = true;
662 clusterService.removeListener(clusterListener);
663 mastershipService.removeListener(mastershipListener);
664 deviceService.removeListener(deviceListener);
665 linkService.removeListener(linkListener);
666 hostService.removeListener(hostListener);
667 intentService.removeListener(intentListener);
668 flowService.removeListener(flowListener);
669 }
670 }
671
672 // Cluster event listener.
673 private class InternalClusterListener implements ClusterEventListener {
674 @Override
675 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700676 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700677 }
678 }
679
680 // Mastership change listener
681 private class InternalMastershipListener implements MastershipListener {
682 @Override
683 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700684 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700685 sendAllInstances(UPDATE_INSTANCE);
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700686 Device device = deviceService.getDevice(event.subject());
687 if (device != null) {
688 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
689 }
690 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700691 }
692 }
693
694 // Device event listener.
695 private class InternalDeviceListener implements DeviceListener {
696 @Override
697 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700698 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700699 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700700 eventAccummulator.add(event);
701 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700702 }
703 }
704
705 // Link event listener.
706 private class InternalLinkListener implements LinkListener {
707 @Override
708 public void event(LinkEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700709 msgSender.execute(() -> sendMessage(linkMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700710 eventAccummulator.add(event);
711 }
712 }
713
714 // Host event listener.
715 private class InternalHostListener implements HostListener {
716 @Override
717 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700718 msgSender.execute(() -> sendMessage(hostMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700719 eventAccummulator.add(event);
720 }
721 }
722
723 // Intent event listener.
724 private class InternalIntentListener implements IntentListener {
725 @Override
726 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700727 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700728 eventAccummulator.add(event);
729 }
730 }
731
732 // Intent event listener.
733 private class InternalFlowListener implements FlowRuleListener {
734 @Override
735 public void event(FlowRuleEvent event) {
736 eventAccummulator.add(event);
737 }
738 }
739
Simon Huntd2747a02015-04-30 22:41:16 -0700740
Simon Hunta17fa672015-08-19 18:42:22 -0700741 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -0700742
743 // Periodic update of the summary information
744 private class SummaryMonitor extends TimerTask {
745 @Override
746 public void run() {
747 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700748 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700749 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700750 }
751 } catch (Exception e) {
752 log.warn("Unable to handle summary request due to {}", e.getMessage());
753 log.warn("Boom!", e);
754 }
755 }
756 }
757
758 // Accumulates events to drive methodic update of the summary pane.
759 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
760 protected InternalEventAccummulator() {
761 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
762 }
763
764 @Override
765 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -0700766 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700767 long now = System.currentTimeMillis();
768 String me = this.toString();
769 String miniMe = me.replaceAll("^.*@", "me@");
770 log.debug("Time: {}; this: {}, processing items ({} events)",
771 now, miniMe, items.size());
772 // End-of-Debugging
773
Thomas Vachuska329af532015-03-10 02:08:33 -0700774 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700775 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700776 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700777 }
778 } catch (Exception e) {
779 log.warn("Unable to handle summary request due to {}", e.getMessage());
780 log.debug("Boom!", e);
781 }
782 }
783 }
784}