blob: ded88066aadc7e1d20dc83e02b82d30d15c55308 [file] [log] [blame]
Thomas Vachuska3553b302015-03-07 14:49:43 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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;
Simon Hunta0ddb022015-05-01 09:53:01 -070030import org.onosproject.ui.UiMessageHandler;
Simon Hunt7715e892016-04-12 19:55:32 -070031import org.onosproject.ui.UiMessageHandlerFactory;
Simon Hunt1169c952017-06-05 11:20:11 -070032import org.onosproject.ui.UiSessionToken;
33import org.onosproject.ui.UiTokenService;
Simon Hunt22c35df2017-04-26 17:28:42 -070034import org.onosproject.ui.UiTopo2OverlayFactory;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070035import org.onosproject.ui.UiTopoLayoutService;
Simon Hunte05cae42015-07-23 17:35:24 -070036import org.onosproject.ui.UiTopoOverlayFactory;
Simon Hunt537bc762016-12-20 12:15:13 -080037import org.onosproject.ui.impl.topo.Topo2Jsonifier;
Simon Hunt22c35df2017-04-26 17:28:42 -070038import org.onosproject.ui.impl.topo.Topo2OverlayCache;
Simon Hunt2d7cd6f2017-05-04 13:04:50 -070039import org.onosproject.ui.impl.topo.Topo2TrafficMessageHandler;
Simon Hunt22c35df2017-04-26 17:28:42 -070040import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070041import org.onosproject.ui.impl.topo.UiTopoSession;
42import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
43import org.onosproject.ui.model.topo.UiTopoLayout;
Thomas Vachuska3553b302015-03-07 14:49:43 -080044import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
47import java.io.IOException;
48import java.util.HashMap;
Simon Hunt1f4365d2017-06-21 17:25:09 -070049import java.util.Locale;
Thomas Vachuska3553b302015-03-07 14:49:43 -080050import java.util.Map;
51
52/**
Simon Hunt7092cc42016-04-06 18:40:17 -070053 * Web socket capable of interacting with the Web UI.
Thomas Vachuska3553b302015-03-07 14:49:43 -080054 */
55public class UiWebSocket
56 implements UiConnection, WebSocket.OnTextMessage, WebSocket.OnControl {
57
58 private static final Logger log = LoggerFactory.getLogger(UiWebSocket.class);
59
Simon Hunt7715e892016-04-12 19:55:32 -070060 private static final String EVENT = "event";
Simon Hunt7715e892016-04-12 19:55:32 -070061 private static final String PAYLOAD = "payload";
62 private static final String UNKNOWN = "unknown";
Simon Hunt1169c952017-06-05 11:20:11 -070063 private static final String AUTHENTICATION = "authentication";
64 private static final String TOKEN = "token";
65 private static final String ERROR = "error";
Simon Hunt7715e892016-04-12 19:55:32 -070066
67 private static final String ID = "id";
68 private static final String IP = "ip";
69 private static final String CLUSTER_NODES = "clusterNodes";
70 private static final String USER = "user";
71 private static final String BOOTSTRAP = "bootstrap";
72
Simon Huntd6d3ad32017-06-21 15:27:06 -070073 private static final String UBERLION = "uberlion";
74 private static final String LION = "lion";
Simon Hunt1f4365d2017-06-21 17:25:09 -070075 private static final String LOCALE = "locale";
Simon Huntd6d3ad32017-06-21 15:27:06 -070076
Simon Huntd7395c82016-10-20 17:54:01 -070077 private static final String TOPO = "topo";
Thomas Vachuska92b016b2016-05-20 11:37:57 -070078
Thomas Vachuska1a989c12015-06-09 18:29:22 -070079 private static final long MAX_AGE_MS = 30_000;
Thomas Vachuska3553b302015-03-07 14:49:43 -080080
81 private static final byte PING = 0x9;
82 private static final byte PONG = 0xA;
83 private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
84
Simon Hunt7092cc42016-04-06 18:40:17 -070085 private final ObjectMapper mapper = new ObjectMapper();
Thomas Vachuska3553b302015-03-07 14:49:43 -080086 private final ServiceDirectory directory;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070087 private final UiTopoSession topoSession;
Thomas Vachuska3553b302015-03-07 14:49:43 -080088
89 private Connection connection;
90 private FrameConnection control;
Thomas Vachuska0af26912016-03-21 21:37:30 -070091 private String userName;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070092 private String currentView;
Thomas Vachuska3553b302015-03-07 14:49:43 -080093
Thomas Vachuska3553b302015-03-07 14:49:43 -080094 private long lastActive = System.currentTimeMillis();
95
Simon Hunta0ddb022015-05-01 09:53:01 -070096 private Map<String, UiMessageHandler> handlers;
Simon Hunte05cae42015-07-23 17:35:24 -070097 private TopoOverlayCache overlayCache;
Simon Hunt22c35df2017-04-26 17:28:42 -070098 private Topo2OverlayCache overlay2Cache;
Thomas Vachuska3553b302015-03-07 14:49:43 -080099
Simon Hunt1169c952017-06-05 11:20:11 -0700100 private UiSessionToken sessionToken;
101
102
Thomas Vachuska3553b302015-03-07 14:49:43 -0800103 /**
Simon Huntcda9c032016-04-11 10:32:54 -0700104 * Creates a new web-socket for serving data to the Web UI.
Thomas Vachuska3553b302015-03-07 14:49:43 -0800105 *
106 * @param directory service directory
Simon Hunt7715e892016-04-12 19:55:32 -0700107 * @param userName user name of the logged-in user
Thomas Vachuska3553b302015-03-07 14:49:43 -0800108 */
Thomas Vachuska0af26912016-03-21 21:37:30 -0700109 public UiWebSocket(ServiceDirectory directory, String userName) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800110 this.directory = directory;
Thomas Vachuska0af26912016-03-21 21:37:30 -0700111 this.userName = userName;
Simon Hunt537bc762016-12-20 12:15:13 -0800112
Simon Hunt95f4b422017-03-03 13:49:05 -0800113 Topo2Jsonifier t2json = new Topo2Jsonifier(directory, userName);
Simon Hunt537bc762016-12-20 12:15:13 -0800114 UiSharedTopologyModel sharedModel = directory.get(UiSharedTopologyModel.class);
115 UiTopoLayoutService layoutService = directory.get(UiTopoLayoutService.class);
Simon Huntbbd0f462017-01-10 14:50:22 -0800116
Simon Hunt8eac4ae2017-01-20 12:56:45 -0800117 sharedModel.injectJsonifier(t2json);
Simon Huntbbd0f462017-01-10 14:50:22 -0800118 topoSession = new UiTopoSession(this, t2json, sharedModel, layoutService);
Simon Hunt1169c952017-06-05 11:20:11 -0700119 sessionToken = null;
Thomas Vachuska0af26912016-03-21 21:37:30 -0700120 }
121
122 @Override
123 public String userName() {
124 return userName;
Thomas Vachuska3553b302015-03-07 14:49:43 -0800125 }
126
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700127 @Override
128 public UiTopoLayout currentLayout() {
129 return topoSession.currentLayout();
130 }
131
132 @Override
133 public void setCurrentLayout(UiTopoLayout topoLayout) {
134 topoSession.setCurrentLayout(topoLayout);
135 }
136
137 @Override
138 public String currentView() {
139 return currentView;
140 }
141
142 @Override
143 public void setCurrentView(String viewId) {
144 currentView = viewId;
145 topoSession.enableEvent(viewId.equals(TOPO));
146 }
147
Simon Huntd6d3ad32017-06-21 15:27:06 -0700148 private ObjectNode objectNode() {
149 return mapper.createObjectNode();
150 }
151
152 private ArrayNode arrayNode() {
153 return mapper.createArrayNode();
154 }
155
Thomas Vachuska3553b302015-03-07 14:49:43 -0800156 /**
Simon Huntd5b96732016-07-08 13:22:27 -0700157 * Provides a reference to the topology session.
158 *
159 * @return topo session reference
160 */
161 public UiTopoSession topoSession() {
162 return topoSession;
163 }
164
165 /**
Thomas Vachuska3553b302015-03-07 14:49:43 -0800166 * Issues a close on the connection.
167 */
168 synchronized void close() {
Simon Hunte05cae42015-07-23 17:35:24 -0700169 destroyHandlersAndOverlays();
Thomas Vachuska3553b302015-03-07 14:49:43 -0800170 if (connection.isOpen()) {
171 connection.close();
172 }
173 }
174
175 /**
176 * Indicates if this connection is idle.
177 *
178 * @return true if idle or closed
179 */
180 synchronized boolean isIdle() {
Simon Huntda580882015-05-12 20:58:18 -0700181 long quietFor = System.currentTimeMillis() - lastActive;
182 boolean idle = quietFor > MAX_AGE_MS;
Thomas Vachuska3553b302015-03-07 14:49:43 -0800183 if (idle || (connection != null && !connection.isOpen())) {
Simon Huntda580882015-05-12 20:58:18 -0700184 log.debug("IDLE (or closed) websocket [{} ms]", quietFor);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800185 return true;
186 } else if (connection != null) {
187 try {
188 control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
189 } catch (IOException e) {
190 log.warn("Unable to send ping message due to: ", e);
191 }
192 }
193 return false;
194 }
195
196 @Override
Satish K598c28d2015-11-24 17:20:40 +0530197 public synchronized void onOpen(Connection connection) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800198 this.connection = connection;
199 this.control = (FrameConnection) connection;
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700200 try {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700201 topoSession.init();
Simon Hunte05cae42015-07-23 17:35:24 -0700202 createHandlersAndOverlays();
Simon Hunt7715e892016-04-12 19:55:32 -0700203 sendBootstrapData();
Simon Huntd6d3ad32017-06-21 15:27:06 -0700204 sendUberLionBundle();
Simon Hunt7715e892016-04-12 19:55:32 -0700205 log.info("GUI client connected -- user <{}>", userName);
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700206
207 } catch (ServiceNotFoundException e) {
Brian O'Connor75deea62015-06-24 16:09:17 -0400208 log.warn("Unable to open GUI connection; services have been shut-down", e);
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700209 this.connection.close();
210 this.connection = null;
211 this.control = null;
212 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800213 }
214
215 @Override
216 public synchronized void onClose(int closeCode, String message) {
dvaddireb09fdf32017-07-04 11:42:53 +0530217 try {
218 tokenService().revokeToken(sessionToken);
219 log.info("Session token revoked");
220 } catch (ServiceNotFoundException e) {
221 log.error("Unable to reference UiTokenService");
222 }
Simon Hunt1169c952017-06-05 11:20:11 -0700223 sessionToken = null;
224
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700225 topoSession.destroy();
Simon Hunte05cae42015-07-23 17:35:24 -0700226 destroyHandlersAndOverlays();
Simon Huntda580882015-05-12 20:58:18 -0700227 log.info("GUI client disconnected [close-code={}, message={}]",
Simon Hunt22c35df2017-04-26 17:28:42 -0700228 closeCode, message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800229 }
230
231 @Override
232 public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
233 lastActive = System.currentTimeMillis();
234 return true;
235 }
236
237 @Override
238 public void onMessage(String data) {
239 lastActive = System.currentTimeMillis();
240 try {
241 ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
Simon Hunt7715e892016-04-12 19:55:32 -0700242 String type = message.path(EVENT).asText(UNKNOWN);
Simon Hunt1169c952017-06-05 11:20:11 -0700243
244 if (sessionToken == null) {
245 authenticate(type, message);
246
Thomas Vachuska3553b302015-03-07 14:49:43 -0800247 } else {
Simon Hunt1169c952017-06-05 11:20:11 -0700248 UiMessageHandler handler = handlers.get(type);
249 if (handler != null) {
250 log.debug("RX message: {}", message);
251 handler.process(message);
252 } else {
253 log.warn("No GUI message handler for type {}", type);
254 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800255 }
Simon Hunt1169c952017-06-05 11:20:11 -0700256
Thomas Vachuska3553b302015-03-07 14:49:43 -0800257 } catch (Exception e) {
258 log.warn("Unable to parse GUI message {} due to {}", data, e);
259 log.debug("Boom!!!", e);
260 }
261 }
262
263 @Override
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700264 public synchronized void sendMessage(ObjectNode message) {
Thomas Vachuska3553b302015-03-07 14:49:43 -0800265 try {
266 if (connection.isOpen()) {
267 connection.sendMessage(message.toString());
Simon Huntd5b96732016-07-08 13:22:27 -0700268 log.debug("TX message: {}", message);
Thomas Vachuska3553b302015-03-07 14:49:43 -0800269 }
270 } catch (IOException e) {
271 log.warn("Unable to send message {} to GUI due to {}", message, e);
272 log.debug("Boom!!!", e);
273 }
274 }
275
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700276 @Override
Simon Huntc5368182017-01-10 13:32:04 -0800277 public synchronized void sendMessage(String type, ObjectNode payload) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700278 ObjectNode message = objectNode();
Simon Hunt7715e892016-04-12 19:55:32 -0700279 message.put(EVENT, type);
Simon Huntd6d3ad32017-06-21 15:27:06 -0700280 message.set(PAYLOAD, payload != null ? payload : objectNode());
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700281 sendMessage(message);
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700282 }
283
Thomas Vachuska3553b302015-03-07 14:49:43 -0800284 // Creates new message handlers.
Simon Hunte05cae42015-07-23 17:35:24 -0700285 private synchronized void createHandlersAndOverlays() {
Simon Hunt7715e892016-04-12 19:55:32 -0700286 log.debug("Creating handlers and overlays...");
Thomas Vachuska3553b302015-03-07 14:49:43 -0800287 handlers = new HashMap<>();
Simon Hunte05cae42015-07-23 17:35:24 -0700288 overlayCache = new TopoOverlayCache();
Simon Hunt22c35df2017-04-26 17:28:42 -0700289 overlay2Cache = new Topo2OverlayCache();
Simon Hunte05cae42015-07-23 17:35:24 -0700290
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700291 Map<Class<?>, UiMessageHandler> handlerInstances = new HashMap<>();
292
Thomas Vachuska3553b302015-03-07 14:49:43 -0800293 UiExtensionService service = directory.get(UiExtensionService.class);
Thomas Vachuska329af532015-03-10 02:08:33 -0700294 service.getExtensions().forEach(ext -> {
295 UiMessageHandlerFactory factory = ext.messageHandlerFactory();
296 if (factory != null) {
297 factory.newHandlers().forEach(handler -> {
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800298 try {
299 handler.init(this, directory);
300 handler.messageTypes().forEach(type -> handlers.put(type, handler));
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700301 handlerInstances.put(handler.getClass(), handler);
Simon Hunte05cae42015-07-23 17:35:24 -0700302
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800303 } catch (Exception e) {
304 log.warn("Unable to setup handler {} due to", handler, e);
Simon Hunte05cae42015-07-23 17:35:24 -0700305 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700306 });
307 }
Simon Hunte05cae42015-07-23 17:35:24 -0700308
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700309 registerOverlays(ext);
Thomas Vachuska329af532015-03-10 02:08:33 -0700310 });
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700311
312 handlerCrossConnects(handlerInstances);
313
314 log.debug("#handlers = {}, #overlays = {}", handlers.size(), overlayCache.size());
315 }
316
Simon Hunt1169c952017-06-05 11:20:11 -0700317 private void authenticate(String type, ObjectNode message) {
318 if (!AUTHENTICATION.equals(type)) {
319 log.warn("Non-Authenticated Web Socket: {}", message);
320 return;
321 }
322
323 String tokstr = message.path(PAYLOAD).path(TOKEN).asText(UNKNOWN);
324 UiSessionToken token = new UiSessionToken(tokstr);
325
326 if (tokenService().isTokenValid(token)) {
327 sessionToken = token;
328 log.info("Session token authenticated");
329 log.debug("WebSocket authenticated: {}", message);
330 } else {
331 log.warn("Invalid Authentication Token: {}", message);
332 sendMessage(ERROR, notAuthorized(token));
333 }
334 }
335
336 private ObjectNode notAuthorized(UiSessionToken token) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700337 return objectNode()
Simon Hunt1169c952017-06-05 11:20:11 -0700338 .put("message", "invalid authentication token")
339 .put("badToken", token.toString());
340 }
341
Simon Hunt2d7cd6f2017-05-04 13:04:50 -0700342 private void registerOverlays(UiExtension ext) {
343 UiTopoOverlayFactory overlayFactory = ext.topoOverlayFactory();
344 if (overlayFactory != null) {
345 overlayFactory.newOverlays().forEach(overlayCache::add);
346 }
347
348 UiTopo2OverlayFactory overlay2Factory = ext.topo2OverlayFactory();
349 if (overlay2Factory != null) {
350 overlay2Factory.newOverlays().forEach(overlay2Cache::add);
351 }
352 }
353
354 private void handlerCrossConnects(Map<Class<?>, UiMessageHandler> handlers) {
355 TopologyViewMessageHandler topomh = (TopologyViewMessageHandler)
356 handlers.get(TopologyViewMessageHandler.class);
357 if (topomh != null) {
358 topomh.setOverlayCache(overlayCache);
359 }
360
361 Topo2ViewMessageHandler topo2mh = (Topo2ViewMessageHandler)
362 handlers.get(Topo2ViewMessageHandler.class);
363 if (topo2mh != null) {
364 topo2mh.setOverlayCache(overlay2Cache);
365
366 // We also need a link to Topo2Traffic
367 Topo2TrafficMessageHandler topo2traffic = (Topo2TrafficMessageHandler)
368 handlers.get(Topo2TrafficMessageHandler.class);
369 if (topo2traffic != null) {
370 topo2mh.setTrafficHandler(topo2traffic);
371 } else {
372 log.error("No topo2 traffic handler found");
373 }
374 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800375 }
376
377 // Destroys message handlers.
Simon Hunte05cae42015-07-23 17:35:24 -0700378 private synchronized void destroyHandlersAndOverlays() {
Simon Hunt7715e892016-04-12 19:55:32 -0700379 log.debug("Destroying handlers and overlays...");
Thomas Vachuska3553b302015-03-07 14:49:43 -0800380 handlers.forEach((type, handler) -> handler.destroy());
381 handlers.clear();
Simon Hunte05cae42015-07-23 17:35:24 -0700382
383 if (overlayCache != null) {
384 overlayCache.destroy();
385 overlayCache = null;
386 }
Simon Hunte6f64612017-04-28 00:01:48 -0700387 if (overlay2Cache != null) {
388 overlay2Cache.destroy();
389 overlay2Cache = null;
390 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800391 }
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700392
Simon Hunt7715e892016-04-12 19:55:32 -0700393 // Sends initial information (username and cluster member information)
394 // to allow GUI to display logged-in user, and to be able to
395 // fail-over to an alternate cluster member if necessary.
396 private void sendBootstrapData() {
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700397 ClusterService service = directory.get(ClusterService.class);
Simon Huntd6d3ad32017-06-21 15:27:06 -0700398 ArrayNode instances = arrayNode();
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700399
400 for (ControllerNode node : service.getNodes()) {
Simon Huntd6d3ad32017-06-21 15:27:06 -0700401 ObjectNode instance = objectNode()
Simon Hunt7715e892016-04-12 19:55:32 -0700402 .put(ID, node.id().toString())
403 .put(IP, node.ip().toString())
Simon Hunt8add9ee2016-09-20 17:05:07 -0700404 .put(GlyphConstants.UI_ATTACHED,
Simon Hunt22c35df2017-04-26 17:28:42 -0700405 node.equals(service.getLocalNode()));
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700406 instances.add(instance);
407 }
408
Simon Huntd6d3ad32017-06-21 15:27:06 -0700409 ObjectNode payload = objectNode();
Simon Hunt7715e892016-04-12 19:55:32 -0700410 payload.set(CLUSTER_NODES, instances);
411 payload.put(USER, userName);
Simon Huntc5368182017-01-10 13:32:04 -0800412 sendMessage(BOOTSTRAP, payload);
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700413 }
414
Simon Hunt1169c952017-06-05 11:20:11 -0700415 private UiTokenService tokenService() {
dvaddireb09fdf32017-07-04 11:42:53 +0530416 return directory.get(UiTokenService.class);
Simon Hunt1169c952017-06-05 11:20:11 -0700417 }
Simon Huntd6d3ad32017-06-21 15:27:06 -0700418
419 // sends the collated localization bundle data up to the client.
420 private void sendUberLionBundle() {
421 UiExtensionService service = directory.get(UiExtensionService.class);
422 ObjectNode lion = objectNode();
423
424 service.getExtensions().forEach(ext -> {
425 ext.lionBundles().forEach(lb -> {
426 ObjectNode lionMap = objectNode();
427 lb.getItems().forEach(item -> {
428 lionMap.put(item.key(), item.value());
429 });
430 lion.set(lb.id(), lionMap);
431 });
432 });
433
434 ObjectNode payload = objectNode();
435 payload.set(LION, lion);
Simon Hunt1f4365d2017-06-21 17:25:09 -0700436 payload.put(LOCALE, Locale.getDefault().toString());
Simon Huntd6d3ad32017-06-21 15:27:06 -0700437 sendMessage(UBERLION, payload);
438 }
Thomas Vachuska3553b302015-03-07 14:49:43 -0800439}