blob: 61f801523926edb82249e0fdf399e2f0e565b67d [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;
21import org.eclipse.jetty.websocket.WebSocket;
22import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskafc52fec2015-05-18 19:13:56 -070023import org.onlab.osgi.ServiceNotFoundException;
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -070024import org.onosproject.cluster.ClusterService;
25import org.onosproject.cluster.ControllerNode;
Simon Hunt8add9ee2016-09-20 17:05:07 -070026import org.onosproject.ui.GlyphConstants;
Thomas Vachuska3553b302015-03-07 14:49:43 -080027import org.onosproject.ui.UiConnection;
Simon Hunt2d7cd6f2017-05-04 13:04:50 -070028import org.onosproject.ui.UiExtension;
Thomas Vachuska3553b302015-03-07 14:49:43 -080029import org.onosproject.ui.UiExtensionService;
Laszlo Papp759f0d32018-03-05 13:24:30 +000030import org.onosproject.ui.UiGlyph;
Simon Hunta0ddb022015-05-01 09:53:01 -070031import org.onosproject.ui.UiMessageHandler;
Simon Hunt7715e892016-04-12 19:55:32 -070032import org.onosproject.ui.UiMessageHandlerFactory;
Simon Hunt1169c952017-06-05 11:20:11 -070033import org.onosproject.ui.UiSessionToken;
34import org.onosproject.ui.UiTokenService;
Simon Hunt22c35df2017-04-26 17:28:42 -070035import org.onosproject.ui.UiTopo2OverlayFactory;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070036import org.onosproject.ui.UiTopoLayoutService;
Simon Hunte05cae42015-07-23 17:35:24 -070037import org.onosproject.ui.UiTopoOverlayFactory;
Simon Hunt537bc762016-12-20 12:15:13 -080038import org.onosproject.ui.impl.topo.Topo2Jsonifier;
Simon Hunt22c35df2017-04-26 17:28:42 -070039import org.onosproject.ui.impl.topo.Topo2OverlayCache;
Simon Hunt2d7cd6f2017-05-04 13:04:50 -070040import org.onosproject.ui.impl.topo.Topo2TrafficMessageHandler;
Simon Hunt22c35df2017-04-26 17:28:42 -070041import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070042import org.onosproject.ui.impl.topo.UiTopoSession;
43import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
Simon Hunt879ce452017-08-10 23:32:00 -070044import org.onosproject.ui.lion.LionBundle;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070045import org.onosproject.ui.model.topo.UiTopoLayout;
Thomas Vachuska3553b302015-03-07 14:49:43 -080046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
49import java.io.IOException;
50import java.util.HashMap;
Simon Hunt1f4365d2017-06-21 17:25:09 -070051import java.util.Locale;
Thomas Vachuska3553b302015-03-07 14:49:43 -080052import java.util.Map;
53
54/**
Simon Hunt7092cc42016-04-06 18:40:17 -070055 * Web socket capable of interacting with the Web UI.
Thomas Vachuska3553b302015-03-07 14:49:43 -080056 */
57public class UiWebSocket
58 implements UiConnection, WebSocket.OnTextMessage, WebSocket.OnControl {
59
60 private static final Logger log = LoggerFactory.getLogger(UiWebSocket.class);
61
Simon Hunt7715e892016-04-12 19:55:32 -070062 private static final String EVENT = "event";
Simon Hunt7715e892016-04-12 19:55:32 -070063 private static final String PAYLOAD = "payload";
64 private static final String UNKNOWN = "unknown";
Simon Hunt1169c952017-06-05 11:20:11 -070065 private static final String AUTHENTICATION = "authentication";
66 private static final String TOKEN = "token";
67 private static final String ERROR = "error";
Simon Hunt7715e892016-04-12 19:55:32 -070068
69 private static final String ID = "id";
70 private static final String IP = "ip";
71 private static final String CLUSTER_NODES = "clusterNodes";
72 private static final String USER = "user";
73 private static final String BOOTSTRAP = "bootstrap";
74
Simon Huntd6d3ad32017-06-21 15:27:06 -070075 private static final String UBERLION = "uberlion";
76 private static final String LION = "lion";
Simon Hunt1f4365d2017-06-21 17:25:09 -070077 private static final String LOCALE = "locale";
Simon Huntd6d3ad32017-06-21 15:27:06 -070078
Simon Huntd7395c82016-10-20 17:54:01 -070079 private static final String TOPO = "topo";
Thomas Vachuska92b016b2016-05-20 11:37:57 -070080
Laszlo Papp759f0d32018-03-05 13:24:30 +000081 private static final String GLYPHS = "glyphs";
82
Thomas Vachuska1a989c12015-06-09 18:29:22 -070083 private static final long MAX_AGE_MS = 30_000;
Thomas Vachuska3553b302015-03-07 14:49:43 -080084
85 private static final byte PING = 0x9;
86 private static final byte PONG = 0xA;
87 private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
88
Simon Hunt7092cc42016-04-06 18:40:17 -070089 private final ObjectMapper mapper = new ObjectMapper();
Thomas Vachuska3553b302015-03-07 14:49:43 -080090 private final ServiceDirectory directory;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070091 private final UiTopoSession topoSession;
Thomas Vachuska3553b302015-03-07 14:49:43 -080092
93 private Connection connection;
94 private FrameConnection control;
Thomas Vachuska0af26912016-03-21 21:37:30 -070095 private String userName;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070096 private String currentView;
Thomas Vachuska3553b302015-03-07 14:49:43 -080097
Thomas Vachuska3553b302015-03-07 14:49:43 -080098 private long lastActive = System.currentTimeMillis();
99
Simon Hunta0ddb022015-05-01 09:53:01 -0700100 private Map<String, UiMessageHandler> handlers;
Simon Hunte05cae42015-07-23 17:35:24 -0700101 private TopoOverlayCache overlayCache;
Simon Hunt22c35df2017-04-26 17:28:42 -0700102 private Topo2OverlayCache overlay2Cache;
Thomas Vachuska3553b302015-03-07 14:49:43 -0800103
Simon Hunt879ce452017-08-10 23:32:00 -0700104 private Map<String, LionBundle> lionBundleMap;
105
Simon Hunt1169c952017-06-05 11:20:11 -0700106 private UiSessionToken sessionToken;
107
108
Thomas Vachuska3553b302015-03-07 14:49:43 -0800109 /**
Simon Huntcda9c032016-04-11 10:32:54 -0700110 * Creates a new web-socket for serving data to the Web UI.
Thomas Vachuska3553b302015-03-07 14:49:43 -0800111 *
112 * @param directory service directory
Simon Hunt7715e892016-04-12 19:55:32 -0700113 * @param userName user name of the logged-in user
Thomas Vachuska3553b302015-03-07 14:49:43 -0800114 */
Thomas Vachuska0af26912016-03-21 21:37:30 -0700115 public UiWebSocket(ServiceDirectory directory, String userName) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800116 this.directory = directory;
Thomas Vachuska0af26912016-03-21 21:37:30 -0700117 this.userName = userName;
Simon Hunt537bc762016-12-20 12:15:13 -0800118
Simon Hunt95f4b422017-03-03 13:49:05 -0800119 Topo2Jsonifier t2json = new Topo2Jsonifier(directory, userName);
Simon Hunt537bc762016-12-20 12:15:13 -0800120 UiSharedTopologyModel sharedModel = directory.get(UiSharedTopologyModel.class);
121 UiTopoLayoutService layoutService = directory.get(UiTopoLayoutService.class);
Simon Huntbbd0f462017-01-10 14:50:22 -0800122
Simon Hunt8eac4ae2017-01-20 12:56:45 -0800123 sharedModel.injectJsonifier(t2json);
Simon Huntbbd0f462017-01-10 14:50:22 -0800124 topoSession = new UiTopoSession(this, t2json, sharedModel, layoutService);
Simon Hunt1169c952017-06-05 11:20:11 -0700125 sessionToken = null;
Thomas Vachuska0af26912016-03-21 21:37:30 -0700126 }
127
128 @Override
129 public String userName() {
130 return userName;
Thomas Vachuska3553b302015-03-07 14:49:43 -0800131 }
132
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700133 @Override
134 public UiTopoLayout currentLayout() {
135 return topoSession.currentLayout();
136 }
137
138 @Override
139 public void setCurrentLayout(UiTopoLayout topoLayout) {
140 topoSession.setCurrentLayout(topoLayout);
141 }
142
143 @Override
144 public String currentView() {
145 return currentView;
146 }
147
148 @Override
149 public void setCurrentView(String viewId) {
150 currentView = viewId;
151 topoSession.enableEvent(viewId.equals(TOPO));
152 }
153
Simon Huntd6d3ad32017-06-21 15:27:06 -0700154 private ObjectNode objectNode() {
155 return mapper.createObjectNode();
156 }
157
158 private ArrayNode arrayNode() {
159 return mapper.createArrayNode();
160 }
161
Thomas Vachuska3553b302015-03-07 14:49:43 -0800162 /**
Simon Huntd5b96732016-07-08 13:22:27 -0700163 * Provides a reference to the topology session.
164 *
165 * @return topo session reference
166 */
167 public UiTopoSession topoSession() {
168 return topoSession;
169 }
170
171 /**
Thomas Vachuska3553b302015-03-07 14:49:43 -0800172 * Issues a close on the connection.
173 */
174 synchronized void close() {
Simon Hunte05cae42015-07-23 17:35:24 -0700175 destroyHandlersAndOverlays();
Thomas Vachuska3553b302015-03-07 14:49:43 -0800176 if (connection.isOpen()) {
177 connection.close();
178 }
179 }
180
181 /**
182 * Indicates if this connection is idle.
183 *
184 * @return true if idle or closed
185 */
186 synchronized boolean isIdle() {
Simon Huntda580882015-05-12 20:58:18 -0700187 long quietFor = System.currentTimeMillis() - lastActive;
188 boolean idle = quietFor > MAX_AGE_MS;
Thomas Vachuska3553b302015-03-07 14:49:43 -0800189 if (idle || (connection != null && !connection.isOpen())) {
Simon Huntda580882015-05-12 20:58:18 -0700190 log.debug("IDLE (or closed) websocket [{} ms]", quietFor);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800191 return true;
192 } else if (connection != null) {
193 try {
194 control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
195 } catch (IOException e) {
196 log.warn("Unable to send ping message due to: ", e);
197 }
198 }
199 return false;
200 }
201
202 @Override
Satish K598c28d2015-11-24 17:20:40 +0530203 public synchronized void onOpen(Connection connection) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800204 this.connection = connection;
205 this.control = (FrameConnection) connection;
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700206 try {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700207 topoSession.init();
Simon Hunte05cae42015-07-23 17:35:24 -0700208 createHandlersAndOverlays();
Simon Hunt7715e892016-04-12 19:55:32 -0700209 sendBootstrapData();
Simon Huntd6d3ad32017-06-21 15:27:06 -0700210 sendUberLionBundle();
Simon Hunt7715e892016-04-12 19:55:32 -0700211 log.info("GUI client connected -- user <{}>", userName);
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700212
213 } catch (ServiceNotFoundException e) {
Brian O'Connor75deea62015-06-24 16:09:17 -0400214 log.warn("Unable to open GUI connection; services have been shut-down", e);
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700215 this.connection.close();
216 this.connection = null;
217 this.control = null;
218 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800219 }
220
221 @Override
222 public synchronized void onClose(int closeCode, String message) {
dvaddireb09fdf32017-07-04 11:42:53 +0530223 try {
Thomas Vachuska3ed75852018-01-17 11:53:21 -0800224 try {
225 tokenService().revokeToken(sessionToken);
226 log.info("Session token revoked");
227 } catch (ServiceNotFoundException e) {
228 log.error("Unable to reference UiTokenService");
229 }
230 sessionToken = null;
Simon Hunt1169c952017-06-05 11:20:11 -0700231
Thomas Vachuska3ed75852018-01-17 11:53:21 -0800232 topoSession.destroy();
233 destroyHandlersAndOverlays();
234 } catch (Exception e) {
235 log.warn("Unexpected error", e);
236 }
Simon Huntda580882015-05-12 20:58:18 -0700237 log.info("GUI client disconnected [close-code={}, message={}]",
Simon Hunt22c35df2017-04-26 17:28:42 -0700238 closeCode, message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800239 }
240
241 @Override
242 public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
243 lastActive = System.currentTimeMillis();
244 return true;
245 }
246
247 @Override
248 public void onMessage(String data) {
249 lastActive = System.currentTimeMillis();
250 try {
251 ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
Simon Hunt7715e892016-04-12 19:55:32 -0700252 String type = message.path(EVENT).asText(UNKNOWN);
Simon Hunt1169c952017-06-05 11:20:11 -0700253
Thomas Vachuska5b48d6c2018-04-27 18:24:27 -0700254// if (sessionToken == null) {
255// authenticate(type, message);
256//
257// } else {
258 UiMessageHandler handler = handlers.get(type);
259 if (handler != null) {
260 log.debug("RX message: {}", message);
261 handler.process(message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800262 } else {
Thomas Vachuska5b48d6c2018-04-27 18:24:27 -0700263 log.warn("No GUI message handler for type {}", type);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800264 }
Thomas Vachuska5b48d6c2018-04-27 18:24:27 -0700265// }
Simon Hunt1169c952017-06-05 11:20:11 -0700266
Thomas Vachuska3553b302015-03-07 14:49:43 -0800267 } catch (Exception e) {
268 log.warn("Unable to parse GUI message {} due to {}", data, e);
269 log.debug("Boom!!!", e);
270 }
271 }
272
273 @Override
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700274 public synchronized void sendMessage(ObjectNode message) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800275 try {
276 if (connection.isOpen()) {
277 connection.sendMessage(message.toString());
Simon Huntd5b96732016-07-08 13:22:27 -0700278 log.debug("TX message: {}", message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800279 }
280 } catch (IOException e) {
281 log.warn("Unable to send message {} to GUI due to {}", message, e);
282 log.debug("Boom!!!", e);
283 }
284 }
285
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700286 @Override
Simon Huntc5368182017-01-10 13:32:04 -0800287 public synchronized void sendMessage(String type, ObjectNode payload) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700288 ObjectNode message = objectNode();
Simon Hunt7715e892016-04-12 19:55:32 -0700289 message.put(EVENT, type);
Simon Huntd6d3ad32017-06-21 15:27:06 -0700290 message.set(PAYLOAD, payload != null ? payload : objectNode());
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700291 sendMessage(message);
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700292 }
293
Thomas Vachuska3553b302015-03-07 14:49:43 -0800294 // Creates new message handlers.
Simon Hunte05cae42015-07-23 17:35:24 -0700295 private synchronized void createHandlersAndOverlays() {
Simon Hunt7715e892016-04-12 19:55:32 -0700296 log.debug("Creating handlers and overlays...");
Thomas Vachuska3553b302015-03-07 14:49:43 -0800297 handlers = new HashMap<>();
Simon Hunte05cae42015-07-23 17:35:24 -0700298 overlayCache = new TopoOverlayCache();
Simon Hunt22c35df2017-04-26 17:28:42 -0700299 overlay2Cache = new Topo2OverlayCache();
Simon Hunte05cae42015-07-23 17:35:24 -0700300
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700301 Map<Class<?>, UiMessageHandler> handlerInstances = new HashMap<>();
Thomas Vachuska3553b302015-03-07 14:49:43 -0800302 UiExtensionService service = directory.get(UiExtensionService.class);
Simon Hunt879ce452017-08-10 23:32:00 -0700303 lionBundleMap = generateLionMap(service);
304
Thomas Vachuska329af532015-03-10 02:08:33 -0700305 service.getExtensions().forEach(ext -> {
306 UiMessageHandlerFactory factory = ext.messageHandlerFactory();
307 if (factory != null) {
308 factory.newHandlers().forEach(handler -> {
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800309 try {
310 handler.init(this, directory);
Simon Hunt879ce452017-08-10 23:32:00 -0700311 injectLionBundles(handler, lionBundleMap);
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800312 handler.messageTypes().forEach(type -> handlers.put(type, handler));
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700313 handlerInstances.put(handler.getClass(), handler);
Simon Hunte05cae42015-07-23 17:35:24 -0700314
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800315 } catch (Exception e) {
316 log.warn("Unable to setup handler {} due to", handler, e);
Simon Hunte05cae42015-07-23 17:35:24 -0700317 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700318 });
319 }
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700320 registerOverlays(ext);
Thomas Vachuska329af532015-03-10 02:08:33 -0700321 });
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700322
323 handlerCrossConnects(handlerInstances);
324
Simon Hunt879ce452017-08-10 23:32:00 -0700325 log.debug("#handlers = {}, #overlays = {}",
326 handlers.size(), overlayCache.size());
327 }
328
329 private Map<String, LionBundle> generateLionMap(UiExtensionService service) {
330 Map<String, LionBundle> bundles = new HashMap<>();
331 service.getExtensions().forEach(ext -> {
332 ext.lionBundles().forEach(lb -> bundles.put(lb.id(), lb));
333 });
334 return bundles;
335 }
336
337 private void injectLionBundles(UiMessageHandler handler,
338 Map<String, LionBundle> lionBundleMap) {
339 handler.requiredLionBundles().forEach(lbid -> {
340 LionBundle lb = lionBundleMap.get(lbid);
341 if (lb != null) {
342 handler.cacheLionBundle(lb);
343 } else {
344 log.warn("handler {}: Lion bundle {} non existent!",
345 handler.getClass().getName(), lbid);
346 }
347 });
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700348 }
349
Simon Hunt1169c952017-06-05 11:20:11 -0700350 private void authenticate(String type, ObjectNode message) {
351 if (!AUTHENTICATION.equals(type)) {
Thomas Vachuskabf5d1fe2018-04-25 15:49:00 -0400352 log.warn("WebSocket not authenticated: {}", message);
353 close();
Simon Hunt1169c952017-06-05 11:20:11 -0700354 return;
355 }
356
357 String tokstr = message.path(PAYLOAD).path(TOKEN).asText(UNKNOWN);
358 UiSessionToken token = new UiSessionToken(tokstr);
359
360 if (tokenService().isTokenValid(token)) {
361 sessionToken = token;
362 log.info("Session token authenticated");
363 log.debug("WebSocket authenticated: {}", message);
364 } else {
365 log.warn("Invalid Authentication Token: {}", message);
366 sendMessage(ERROR, notAuthorized(token));
367 }
368 }
369
370 private ObjectNode notAuthorized(UiSessionToken token) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700371 return objectNode()
Simon Hunt1169c952017-06-05 11:20:11 -0700372 .put("message", "invalid authentication token")
373 .put("badToken", token.toString());
374 }
375
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700376 private void registerOverlays(UiExtension ext) {
377 UiTopoOverlayFactory overlayFactory = ext.topoOverlayFactory();
378 if (overlayFactory != null) {
379 overlayFactory.newOverlays().forEach(overlayCache::add);
380 }
381
382 UiTopo2OverlayFactory overlay2Factory = ext.topo2OverlayFactory();
383 if (overlay2Factory != null) {
384 overlay2Factory.newOverlays().forEach(overlay2Cache::add);
385 }
386 }
387
388 private void handlerCrossConnects(Map<Class<?>, UiMessageHandler> handlers) {
389 TopologyViewMessageHandler topomh = (TopologyViewMessageHandler)
390 handlers.get(TopologyViewMessageHandler.class);
391 if (topomh != null) {
392 topomh.setOverlayCache(overlayCache);
393 }
394
395 Topo2ViewMessageHandler topo2mh = (Topo2ViewMessageHandler)
396 handlers.get(Topo2ViewMessageHandler.class);
397 if (topo2mh != null) {
398 topo2mh.setOverlayCache(overlay2Cache);
399
400 // We also need a link to Topo2Traffic
401 Topo2TrafficMessageHandler topo2traffic = (Topo2TrafficMessageHandler)
402 handlers.get(Topo2TrafficMessageHandler.class);
403 if (topo2traffic != null) {
404 topo2mh.setTrafficHandler(topo2traffic);
405 } else {
406 log.error("No topo2 traffic handler found");
407 }
408 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800409 }
410
411 // Destroys message handlers.
Simon Hunte05cae42015-07-23 17:35:24 -0700412 private synchronized void destroyHandlersAndOverlays() {
Simon Hunt7715e892016-04-12 19:55:32 -0700413 log.debug("Destroying handlers and overlays...");
Thomas Vachuska3553b302015-03-07 14:49:43 -0800414 handlers.forEach((type, handler) -> handler.destroy());
415 handlers.clear();
Simon Hunte05cae42015-07-23 17:35:24 -0700416
417 if (overlayCache != null) {
418 overlayCache.destroy();
419 overlayCache = null;
420 }
Simon Hunte6f64612017-04-28 00:01:48 -0700421 if (overlay2Cache != null) {
422 overlay2Cache.destroy();
423 overlay2Cache = null;
424 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800425 }
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700426
Simon Hunt7715e892016-04-12 19:55:32 -0700427 // Sends initial information (username and cluster member information)
428 // to allow GUI to display logged-in user, and to be able to
429 // fail-over to an alternate cluster member if necessary.
430 private void sendBootstrapData() {
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700431 ClusterService service = directory.get(ClusterService.class);
Simon Huntd6d3ad32017-06-21 15:27:06 -0700432 ArrayNode instances = arrayNode();
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700433
434 for (ControllerNode node : service.getNodes()) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700435 ObjectNode instance = objectNode()
Simon Hunt7715e892016-04-12 19:55:32 -0700436 .put(ID, node.id().toString())
437 .put(IP, node.ip().toString())
Simon Hunt8add9ee2016-09-20 17:05:07 -0700438 .put(GlyphConstants.UI_ATTACHED,
Simon Hunt22c35df2017-04-26 17:28:42 -0700439 node.equals(service.getLocalNode()));
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700440 instances.add(instance);
441 }
442
Laszlo Papp759f0d32018-03-05 13:24:30 +0000443 ArrayNode glyphInstances = arrayNode();
444 UiExtensionService uiExtensionService = directory.get(UiExtensionService.class);
445 for (UiGlyph glyph : uiExtensionService.getGlyphs()) {
446 ObjectNode glyphInstance = objectNode()
447 .put(GlyphConstants.ID, glyph.id())
448 .put(GlyphConstants.VIEWBOX, glyph.viewbox())
449 .put(GlyphConstants.PATH, glyph.path());
450 glyphInstances.add(glyphInstance);
451 }
452
Simon Huntd6d3ad32017-06-21 15:27:06 -0700453 ObjectNode payload = objectNode();
Simon Hunt7715e892016-04-12 19:55:32 -0700454 payload.set(CLUSTER_NODES, instances);
Laszlo Papp759f0d32018-03-05 13:24:30 +0000455 payload.set(GLYPHS, glyphInstances);
Simon Hunt7715e892016-04-12 19:55:32 -0700456 payload.put(USER, userName);
Laszlo Papp759f0d32018-03-05 13:24:30 +0000457
Simon Huntc5368182017-01-10 13:32:04 -0800458 sendMessage(BOOTSTRAP, payload);
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700459 }
460
Simon Hunt1169c952017-06-05 11:20:11 -0700461 private UiTokenService tokenService() {
dvaddireb09fdf32017-07-04 11:42:53 +0530462 return directory.get(UiTokenService.class);
Simon Hunt1169c952017-06-05 11:20:11 -0700463 }
Simon Huntd6d3ad32017-06-21 15:27:06 -0700464
465 // sends the collated localization bundle data up to the client.
466 private void sendUberLionBundle() {
467 UiExtensionService service = directory.get(UiExtensionService.class);
468 ObjectNode lion = objectNode();
469
470 service.getExtensions().forEach(ext -> {
471 ext.lionBundles().forEach(lb -> {
472 ObjectNode lionMap = objectNode();
Simon Hunt879ce452017-08-10 23:32:00 -0700473 lb.getItems().forEach(item -> lionMap.put(item.key(), item.value()));
Simon Huntd6d3ad32017-06-21 15:27:06 -0700474 lion.set(lb.id(), lionMap);
475 });
476 });
477
478 ObjectNode payload = objectNode();
479 payload.set(LION, lion);
Simon Hunt1f4365d2017-06-21 17:25:09 -0700480 payload.put(LOCALE, Locale.getDefault().toString());
Simon Huntd6d3ad32017-06-21 15:27:06 -0700481 sendMessage(UBERLION, payload);
482 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800483}