blob: 25c2f03e37467f8982cf4194542bd37619a29890 [file] [log] [blame]
Thomas Vachuska3553b302015-03-07 14:49:43 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska3553b302015-03-07 14:49:43 -08003 *
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.ObjectMapper;
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -070019import com.fasterxml.jackson.databind.node.ArrayNode;
Thomas Vachuska3553b302015-03-07 14:49:43 -080020import com.fasterxml.jackson.databind.node.ObjectNode;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070021import org.eclipse.jetty.websocket.api.Session;
22import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
23import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
24import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
25import org.eclipse.jetty.websocket.api.annotations.WebSocket;
Thomas Vachuska3553b302015-03-07 14:49:43 -080026import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskafc52fec2015-05-18 19:13:56 -070027import org.onlab.osgi.ServiceNotFoundException;
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -070028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.ControllerNode;
Simon Hunt8add9ee2016-09-20 17:05:07 -070030import org.onosproject.ui.GlyphConstants;
Thomas Vachuska3553b302015-03-07 14:49:43 -080031import org.onosproject.ui.UiConnection;
Simon Hunt2d7cd6f2017-05-04 13:04:50 -070032import org.onosproject.ui.UiExtension;
Thomas Vachuska3553b302015-03-07 14:49:43 -080033import org.onosproject.ui.UiExtensionService;
Laszlo Papp759f0d32018-03-05 13:24:30 +000034import org.onosproject.ui.UiGlyph;
Simon Hunta0ddb022015-05-01 09:53:01 -070035import org.onosproject.ui.UiMessageHandler;
Simon Hunt7715e892016-04-12 19:55:32 -070036import org.onosproject.ui.UiMessageHandlerFactory;
Simon Hunt1169c952017-06-05 11:20:11 -070037import org.onosproject.ui.UiSessionToken;
38import org.onosproject.ui.UiTokenService;
Simon Hunt22c35df2017-04-26 17:28:42 -070039import org.onosproject.ui.UiTopo2OverlayFactory;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070040import org.onosproject.ui.UiTopoLayoutService;
Simon Hunte05cae42015-07-23 17:35:24 -070041import org.onosproject.ui.UiTopoOverlayFactory;
Simon Hunt537bc762016-12-20 12:15:13 -080042import org.onosproject.ui.impl.topo.Topo2Jsonifier;
Simon Hunt22c35df2017-04-26 17:28:42 -070043import org.onosproject.ui.impl.topo.Topo2OverlayCache;
Simon Hunt2d7cd6f2017-05-04 13:04:50 -070044import org.onosproject.ui.impl.topo.Topo2TrafficMessageHandler;
Simon Hunt22c35df2017-04-26 17:28:42 -070045import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070046import org.onosproject.ui.impl.topo.UiTopoSession;
47import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
Simon Hunt879ce452017-08-10 23:32:00 -070048import org.onosproject.ui.lion.LionBundle;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070049import org.onosproject.ui.model.topo.UiTopoLayout;
Thomas Vachuska3553b302015-03-07 14:49:43 -080050import org.slf4j.Logger;
51import org.slf4j.LoggerFactory;
52
53import java.io.IOException;
54import java.util.HashMap;
Simon Hunt1f4365d2017-06-21 17:25:09 -070055import java.util.Locale;
Thomas Vachuska3553b302015-03-07 14:49:43 -080056import java.util.Map;
57
58/**
Simon Hunt7092cc42016-04-06 18:40:17 -070059 * Web socket capable of interacting with the Web UI.
Thomas Vachuska3553b302015-03-07 14:49:43 -080060 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061
62@WebSocket
Thomas Vachuskad0d7ea12018-10-10 10:27:04 -070063public class UiWebSocket implements UiConnection {
Thomas Vachuska3553b302015-03-07 14:49:43 -080064
65 private static final Logger log = LoggerFactory.getLogger(UiWebSocket.class);
66
Simon Hunt7715e892016-04-12 19:55:32 -070067 private static final String EVENT = "event";
Simon Hunt7715e892016-04-12 19:55:32 -070068 private static final String PAYLOAD = "payload";
69 private static final String UNKNOWN = "unknown";
Simon Hunt1169c952017-06-05 11:20:11 -070070 private static final String AUTHENTICATION = "authentication";
71 private static final String TOKEN = "token";
72 private static final String ERROR = "error";
Simon Hunt7715e892016-04-12 19:55:32 -070073
74 private static final String ID = "id";
75 private static final String IP = "ip";
76 private static final String CLUSTER_NODES = "clusterNodes";
77 private static final String USER = "user";
78 private static final String BOOTSTRAP = "bootstrap";
79
Simon Huntd6d3ad32017-06-21 15:27:06 -070080 private static final String UBERLION = "uberlion";
81 private static final String LION = "lion";
Simon Hunt1f4365d2017-06-21 17:25:09 -070082 private static final String LOCALE = "locale";
Simon Huntd6d3ad32017-06-21 15:27:06 -070083
Simon Huntd7395c82016-10-20 17:54:01 -070084 private static final String TOPO = "topo";
Thomas Vachuska92b016b2016-05-20 11:37:57 -070085
Laszlo Papp759f0d32018-03-05 13:24:30 +000086 private static final String GLYPHS = "glyphs";
87
Thomas Vachuska1a989c12015-06-09 18:29:22 -070088 private static final long MAX_AGE_MS = 30_000;
Thomas Vachuska3553b302015-03-07 14:49:43 -080089
Simon Hunt7092cc42016-04-06 18:40:17 -070090 private final ObjectMapper mapper = new ObjectMapper();
Thomas Vachuska3553b302015-03-07 14:49:43 -080091 private final ServiceDirectory directory;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070092 private final UiTopoSession topoSession;
Thomas Vachuska3553b302015-03-07 14:49:43 -080093
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 private Session session;
95 //private FrameConnection control;
Thomas Vachuska0af26912016-03-21 21:37:30 -070096 private String userName;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070097 private String currentView;
Thomas Vachuska3553b302015-03-07 14:49:43 -080098
Thomas Vachuska3553b302015-03-07 14:49:43 -080099 private long lastActive = System.currentTimeMillis();
100
Simon Hunta0ddb022015-05-01 09:53:01 -0700101 private Map<String, UiMessageHandler> handlers;
Simon Hunte05cae42015-07-23 17:35:24 -0700102 private TopoOverlayCache overlayCache;
Simon Hunt22c35df2017-04-26 17:28:42 -0700103 private Topo2OverlayCache overlay2Cache;
Thomas Vachuska3553b302015-03-07 14:49:43 -0800104
Simon Hunt879ce452017-08-10 23:32:00 -0700105 private Map<String, LionBundle> lionBundleMap;
106
Simon Hunt1169c952017-06-05 11:20:11 -0700107 private UiSessionToken sessionToken;
108
109
Thomas Vachuska3553b302015-03-07 14:49:43 -0800110 /**
Simon Huntcda9c032016-04-11 10:32:54 -0700111 * Creates a new web-socket for serving data to the Web UI.
Thomas Vachuska3553b302015-03-07 14:49:43 -0800112 *
113 * @param directory service directory
Simon Hunt7715e892016-04-12 19:55:32 -0700114 * @param userName user name of the logged-in user
Thomas Vachuska3553b302015-03-07 14:49:43 -0800115 */
Thomas Vachuska0af26912016-03-21 21:37:30 -0700116 public UiWebSocket(ServiceDirectory directory, String userName) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800117 this.directory = directory;
Thomas Vachuska0af26912016-03-21 21:37:30 -0700118 this.userName = userName;
Simon Hunt537bc762016-12-20 12:15:13 -0800119
Simon Hunt95f4b422017-03-03 13:49:05 -0800120 Topo2Jsonifier t2json = new Topo2Jsonifier(directory, userName);
Simon Hunt537bc762016-12-20 12:15:13 -0800121 UiSharedTopologyModel sharedModel = directory.get(UiSharedTopologyModel.class);
122 UiTopoLayoutService layoutService = directory.get(UiTopoLayoutService.class);
Simon Huntbbd0f462017-01-10 14:50:22 -0800123
Simon Hunt8eac4ae2017-01-20 12:56:45 -0800124 sharedModel.injectJsonifier(t2json);
Simon Huntbbd0f462017-01-10 14:50:22 -0800125 topoSession = new UiTopoSession(this, t2json, sharedModel, layoutService);
Simon Hunt1169c952017-06-05 11:20:11 -0700126 sessionToken = null;
Thomas Vachuska0af26912016-03-21 21:37:30 -0700127 }
128
129 @Override
130 public String userName() {
131 return userName;
Thomas Vachuska3553b302015-03-07 14:49:43 -0800132 }
133
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700134 @Override
135 public UiTopoLayout currentLayout() {
136 return topoSession.currentLayout();
137 }
138
139 @Override
140 public void setCurrentLayout(UiTopoLayout topoLayout) {
141 topoSession.setCurrentLayout(topoLayout);
142 }
143
144 @Override
145 public String currentView() {
146 return currentView;
147 }
148
149 @Override
150 public void setCurrentView(String viewId) {
151 currentView = viewId;
152 topoSession.enableEvent(viewId.equals(TOPO));
153 }
154
Simon Huntd6d3ad32017-06-21 15:27:06 -0700155 private ObjectNode objectNode() {
156 return mapper.createObjectNode();
157 }
158
159 private ArrayNode arrayNode() {
160 return mapper.createArrayNode();
161 }
162
Thomas Vachuska3553b302015-03-07 14:49:43 -0800163 /**
Simon Huntd5b96732016-07-08 13:22:27 -0700164 * Provides a reference to the topology session.
165 *
166 * @return topo session reference
167 */
168 public UiTopoSession topoSession() {
169 return topoSession;
170 }
171
172 /**
Thomas Vachuska3553b302015-03-07 14:49:43 -0800173 * Issues a close on the connection.
174 */
175 synchronized void close() {
Simon Hunte05cae42015-07-23 17:35:24 -0700176 destroyHandlersAndOverlays();
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700177 if (session.isOpen()) {
178 session.close();
Thomas Vachuska3553b302015-03-07 14:49:43 -0800179 }
180 }
181
182 /**
183 * Indicates if this connection is idle.
184 *
185 * @return true if idle or closed
186 */
187 synchronized boolean isIdle() {
Simon Huntda580882015-05-12 20:58:18 -0700188 long quietFor = System.currentTimeMillis() - lastActive;
189 boolean idle = quietFor > MAX_AGE_MS;
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700190 if (idle || (session != null && !session.isOpen())) {
Simon Huntda580882015-05-12 20:58:18 -0700191 log.debug("IDLE (or closed) websocket [{} ms]", quietFor);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800192 return true;
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700193 //} else if (session != null) {
194 // try {
195 // control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
196 // } catch (IOException e) {
197 // log.warn("Unable to send ping message due to: ", e);
198 // }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800199 }
200 return false;
201 }
202
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700203 @OnWebSocketConnect
204 public synchronized void onOpen(Session session) {
205 this.session = session;
206 //this.control = (FrameConnection) connection;
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700207 try {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700208 topoSession.init();
Simon Hunte05cae42015-07-23 17:35:24 -0700209 createHandlersAndOverlays();
Simon Hunt7715e892016-04-12 19:55:32 -0700210 sendBootstrapData();
Simon Huntd6d3ad32017-06-21 15:27:06 -0700211 sendUberLionBundle();
Simon Hunt7715e892016-04-12 19:55:32 -0700212 log.info("GUI client connected -- user <{}>", userName);
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700213
214 } catch (ServiceNotFoundException e) {
Brian O'Connor75deea62015-06-24 16:09:17 -0400215 log.warn("Unable to open GUI connection; services have been shut-down", e);
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700216 this.session.close();
217 this.session = null;
218 //this.control = null;
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700219 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800220 }
221
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700222 @OnWebSocketClose
Thomas Vachuska3553b302015-03-07 14:49:43 -0800223 public synchronized void onClose(int closeCode, String message) {
dvaddireb09fdf32017-07-04 11:42:53 +0530224 try {
Thomas Vachuska3ed75852018-01-17 11:53:21 -0800225 try {
226 tokenService().revokeToken(sessionToken);
227 log.info("Session token revoked");
228 } catch (ServiceNotFoundException e) {
229 log.error("Unable to reference UiTokenService");
230 }
231 sessionToken = null;
Simon Hunt1169c952017-06-05 11:20:11 -0700232
Thomas Vachuska3ed75852018-01-17 11:53:21 -0800233 topoSession.destroy();
234 destroyHandlersAndOverlays();
235 } catch (Exception e) {
236 log.warn("Unexpected error", e);
237 }
Simon Huntda580882015-05-12 20:58:18 -0700238 log.info("GUI client disconnected [close-code={}, message={}]",
Simon Hunt22c35df2017-04-26 17:28:42 -0700239 closeCode, message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800240 }
241
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700242 @OnWebSocketMessage
Thomas Vachuska2fd325f2018-10-01 13:21:23 -0700243 public void onText(Session session, String data) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800244 lastActive = System.currentTimeMillis();
245 try {
246 ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
Simon Hunt7715e892016-04-12 19:55:32 -0700247 String type = message.path(EVENT).asText(UNKNOWN);
Simon Hunt1169c952017-06-05 11:20:11 -0700248
Thomas Vachuskad3585742018-08-14 10:06:39 -0700249 if (sessionToken == null) {
250 authenticate(type, message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800251 } else {
Thomas Vachuskad3585742018-08-14 10:06:39 -0700252 UiMessageHandler handler = handlers.get(type);
253 if (handler != null) {
254 log.debug("RX message: {}", message);
255 handler.process(message);
256 } else {
257 log.warn("No GUI message handler for type {}", type);
258 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800259 }
Simon Hunt1169c952017-06-05 11:20:11 -0700260
Thomas Vachuska3553b302015-03-07 14:49:43 -0800261 } catch (Exception e) {
262 log.warn("Unable to parse GUI message {} due to {}", data, e);
263 log.debug("Boom!!!", e);
264 }
265 }
266
267 @Override
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700268 public synchronized void sendMessage(ObjectNode message) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800269 try {
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700270 if (session.isOpen()) {
271 session.getRemote().sendString(message.toString());
Simon Huntd5b96732016-07-08 13:22:27 -0700272 log.debug("TX message: {}", message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800273 }
274 } catch (IOException e) {
275 log.warn("Unable to send message {} to GUI due to {}", message, e);
276 log.debug("Boom!!!", e);
277 }
278 }
279
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700280 @Override
Simon Huntc5368182017-01-10 13:32:04 -0800281 public synchronized void sendMessage(String type, ObjectNode payload) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700282 ObjectNode message = objectNode();
Simon Hunt7715e892016-04-12 19:55:32 -0700283 message.put(EVENT, type);
Simon Huntd6d3ad32017-06-21 15:27:06 -0700284 message.set(PAYLOAD, payload != null ? payload : objectNode());
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700285 sendMessage(message);
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700286 }
287
Thomas Vachuska3553b302015-03-07 14:49:43 -0800288 // Creates new message handlers.
Simon Hunte05cae42015-07-23 17:35:24 -0700289 private synchronized void createHandlersAndOverlays() {
Simon Hunt7715e892016-04-12 19:55:32 -0700290 log.debug("Creating handlers and overlays...");
Thomas Vachuska3553b302015-03-07 14:49:43 -0800291 handlers = new HashMap<>();
Simon Hunte05cae42015-07-23 17:35:24 -0700292 overlayCache = new TopoOverlayCache();
Simon Hunt22c35df2017-04-26 17:28:42 -0700293 overlay2Cache = new Topo2OverlayCache();
Simon Hunte05cae42015-07-23 17:35:24 -0700294
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700295 Map<Class<?>, UiMessageHandler> handlerInstances = new HashMap<>();
Thomas Vachuska3553b302015-03-07 14:49:43 -0800296 UiExtensionService service = directory.get(UiExtensionService.class);
Simon Hunt879ce452017-08-10 23:32:00 -0700297 lionBundleMap = generateLionMap(service);
298
Thomas Vachuska329af532015-03-10 02:08:33 -0700299 service.getExtensions().forEach(ext -> {
300 UiMessageHandlerFactory factory = ext.messageHandlerFactory();
301 if (factory != null) {
302 factory.newHandlers().forEach(handler -> {
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800303 try {
304 handler.init(this, directory);
Simon Hunt879ce452017-08-10 23:32:00 -0700305 injectLionBundles(handler, lionBundleMap);
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800306 handler.messageTypes().forEach(type -> handlers.put(type, handler));
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700307 handlerInstances.put(handler.getClass(), handler);
Simon Hunte05cae42015-07-23 17:35:24 -0700308
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800309 } catch (Exception e) {
310 log.warn("Unable to setup handler {} due to", handler, e);
Simon Hunte05cae42015-07-23 17:35:24 -0700311 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700312 });
313 }
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700314 registerOverlays(ext);
Thomas Vachuska329af532015-03-10 02:08:33 -0700315 });
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700316
317 handlerCrossConnects(handlerInstances);
318
Simon Hunt879ce452017-08-10 23:32:00 -0700319 log.debug("#handlers = {}, #overlays = {}",
320 handlers.size(), overlayCache.size());
321 }
322
323 private Map<String, LionBundle> generateLionMap(UiExtensionService service) {
324 Map<String, LionBundle> bundles = new HashMap<>();
325 service.getExtensions().forEach(ext -> {
326 ext.lionBundles().forEach(lb -> bundles.put(lb.id(), lb));
327 });
328 return bundles;
329 }
330
331 private void injectLionBundles(UiMessageHandler handler,
332 Map<String, LionBundle> lionBundleMap) {
333 handler.requiredLionBundles().forEach(lbid -> {
334 LionBundle lb = lionBundleMap.get(lbid);
335 if (lb != null) {
336 handler.cacheLionBundle(lb);
337 } else {
338 log.warn("handler {}: Lion bundle {} non existent!",
339 handler.getClass().getName(), lbid);
340 }
341 });
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700342 }
343
Simon Hunt1169c952017-06-05 11:20:11 -0700344 private void authenticate(String type, ObjectNode message) {
345 if (!AUTHENTICATION.equals(type)) {
Thomas Vachuskabf5d1fe2018-04-25 15:49:00 -0400346 log.warn("WebSocket not authenticated: {}", message);
Thomas Vachuskad3585742018-08-14 10:06:39 -0700347 sendMessage(ERROR, notAuthorized(null));
Thomas Vachuskabf5d1fe2018-04-25 15:49:00 -0400348 close();
Simon Hunt1169c952017-06-05 11:20:11 -0700349 return;
350 }
351
352 String tokstr = message.path(PAYLOAD).path(TOKEN).asText(UNKNOWN);
353 UiSessionToken token = new UiSessionToken(tokstr);
354
355 if (tokenService().isTokenValid(token)) {
356 sessionToken = token;
357 log.info("Session token authenticated");
358 log.debug("WebSocket authenticated: {}", message);
359 } else {
360 log.warn("Invalid Authentication Token: {}", message);
361 sendMessage(ERROR, notAuthorized(token));
362 }
363 }
364
365 private ObjectNode notAuthorized(UiSessionToken token) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700366 return objectNode()
Simon Hunt1169c952017-06-05 11:20:11 -0700367 .put("message", "invalid authentication token")
Thomas Vachuskad3585742018-08-14 10:06:39 -0700368 .put("badToken", token != null ? token.toString() : "null");
Simon Hunt1169c952017-06-05 11:20:11 -0700369 }
370
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700371 private void registerOverlays(UiExtension ext) {
372 UiTopoOverlayFactory overlayFactory = ext.topoOverlayFactory();
373 if (overlayFactory != null) {
374 overlayFactory.newOverlays().forEach(overlayCache::add);
375 }
376
377 UiTopo2OverlayFactory overlay2Factory = ext.topo2OverlayFactory();
378 if (overlay2Factory != null) {
379 overlay2Factory.newOverlays().forEach(overlay2Cache::add);
380 }
381 }
382
383 private void handlerCrossConnects(Map<Class<?>, UiMessageHandler> handlers) {
384 TopologyViewMessageHandler topomh = (TopologyViewMessageHandler)
385 handlers.get(TopologyViewMessageHandler.class);
386 if (topomh != null) {
387 topomh.setOverlayCache(overlayCache);
388 }
389
390 Topo2ViewMessageHandler topo2mh = (Topo2ViewMessageHandler)
391 handlers.get(Topo2ViewMessageHandler.class);
392 if (topo2mh != null) {
393 topo2mh.setOverlayCache(overlay2Cache);
394
395 // We also need a link to Topo2Traffic
396 Topo2TrafficMessageHandler topo2traffic = (Topo2TrafficMessageHandler)
397 handlers.get(Topo2TrafficMessageHandler.class);
398 if (topo2traffic != null) {
399 topo2mh.setTrafficHandler(topo2traffic);
400 } else {
401 log.error("No topo2 traffic handler found");
402 }
403 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800404 }
405
406 // Destroys message handlers.
Simon Hunte05cae42015-07-23 17:35:24 -0700407 private synchronized void destroyHandlersAndOverlays() {
Simon Hunt7715e892016-04-12 19:55:32 -0700408 log.debug("Destroying handlers and overlays...");
Thomas Vachuska3553b302015-03-07 14:49:43 -0800409 handlers.forEach((type, handler) -> handler.destroy());
410 handlers.clear();
Simon Hunte05cae42015-07-23 17:35:24 -0700411
412 if (overlayCache != null) {
413 overlayCache.destroy();
414 overlayCache = null;
415 }
Simon Hunte6f64612017-04-28 00:01:48 -0700416 if (overlay2Cache != null) {
417 overlay2Cache.destroy();
418 overlay2Cache = null;
419 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800420 }
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700421
Simon Hunt7715e892016-04-12 19:55:32 -0700422 // Sends initial information (username and cluster member information)
423 // to allow GUI to display logged-in user, and to be able to
424 // fail-over to an alternate cluster member if necessary.
425 private void sendBootstrapData() {
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700426 ClusterService service = directory.get(ClusterService.class);
Simon Huntd6d3ad32017-06-21 15:27:06 -0700427 ArrayNode instances = arrayNode();
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700428
429 for (ControllerNode node : service.getNodes()) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700430 ObjectNode instance = objectNode()
Simon Hunt7715e892016-04-12 19:55:32 -0700431 .put(ID, node.id().toString())
432 .put(IP, node.ip().toString())
Simon Hunt8add9ee2016-09-20 17:05:07 -0700433 .put(GlyphConstants.UI_ATTACHED,
Simon Hunt22c35df2017-04-26 17:28:42 -0700434 node.equals(service.getLocalNode()));
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700435 instances.add(instance);
436 }
437
Laszlo Papp759f0d32018-03-05 13:24:30 +0000438 ArrayNode glyphInstances = arrayNode();
439 UiExtensionService uiExtensionService = directory.get(UiExtensionService.class);
440 for (UiGlyph glyph : uiExtensionService.getGlyphs()) {
441 ObjectNode glyphInstance = objectNode()
442 .put(GlyphConstants.ID, glyph.id())
443 .put(GlyphConstants.VIEWBOX, glyph.viewbox())
444 .put(GlyphConstants.PATH, glyph.path());
445 glyphInstances.add(glyphInstance);
446 }
447
Simon Huntd6d3ad32017-06-21 15:27:06 -0700448 ObjectNode payload = objectNode();
Simon Hunt7715e892016-04-12 19:55:32 -0700449 payload.set(CLUSTER_NODES, instances);
Laszlo Papp759f0d32018-03-05 13:24:30 +0000450 payload.set(GLYPHS, glyphInstances);
Simon Hunt7715e892016-04-12 19:55:32 -0700451 payload.put(USER, userName);
Laszlo Papp759f0d32018-03-05 13:24:30 +0000452
Simon Huntc5368182017-01-10 13:32:04 -0800453 sendMessage(BOOTSTRAP, payload);
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700454 }
455
Simon Hunt1169c952017-06-05 11:20:11 -0700456 private UiTokenService tokenService() {
dvaddireb09fdf32017-07-04 11:42:53 +0530457 return directory.get(UiTokenService.class);
Simon Hunt1169c952017-06-05 11:20:11 -0700458 }
Simon Huntd6d3ad32017-06-21 15:27:06 -0700459
460 // sends the collated localization bundle data up to the client.
461 private void sendUberLionBundle() {
462 UiExtensionService service = directory.get(UiExtensionService.class);
463 ObjectNode lion = objectNode();
464
465 service.getExtensions().forEach(ext -> {
466 ext.lionBundles().forEach(lb -> {
467 ObjectNode lionMap = objectNode();
Simon Hunt879ce452017-08-10 23:32:00 -0700468 lb.getItems().forEach(item -> lionMap.put(item.key(), item.value()));
Simon Huntd6d3ad32017-06-21 15:27:06 -0700469 lion.set(lb.id(), lionMap);
470 });
471 });
472
473 ObjectNode payload = objectNode();
474 payload.set(LION, lion);
Simon Hunt1f4365d2017-06-21 17:25:09 -0700475 payload.put(LOCALE, Locale.getDefault().toString());
Simon Huntd6d3ad32017-06-21 15:27:06 -0700476 sendMessage(UBERLION, payload);
477 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800478}