blob: a9f349f90c14f5ec267de02cce5252b6f4281917 [file] [log] [blame]
Thomas Vachuska3553b302015-03-07 14:49:43 -08001/*
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
Thomas Vachuskafa74dd72016-03-20 19:11:12 -070018import com.fasterxml.jackson.databind.node.ObjectNode;
Thomas Vachuska3553b302015-03-07 14:49:43 -080019import org.eclipse.jetty.websocket.WebSocket;
20import org.eclipse.jetty.websocket.WebSocketServlet;
21import org.onlab.osgi.DefaultServiceDirectory;
22import org.onlab.osgi.ServiceDirectory;
23
24import javax.servlet.ServletException;
25import javax.servlet.http.HttpServletRequest;
26import java.util.HashSet;
27import java.util.Iterator;
28import java.util.Set;
29import java.util.Timer;
30import java.util.TimerTask;
31
32/**
33 * Web socket servlet capable of creating web sockets for the user interface.
34 */
35public class UiWebSocketServlet extends WebSocketServlet {
36
37 private static final long PING_DELAY_MS = 5000;
38
Thomas Vachuska51f540f2015-05-27 17:26:57 -070039 private static UiWebSocketServlet instance;
40
Thomas Vachuska3553b302015-03-07 14:49:43 -080041 private ServiceDirectory directory = new DefaultServiceDirectory();
42
43 private final Set<UiWebSocket> sockets = new HashSet<>();
44 private final Timer timer = new Timer();
45 private final TimerTask pruner = new Pruner();
Thomas Vachuska4e0e0932015-07-24 10:14:34 -070046 private boolean isStopped = false;
Thomas Vachuska3553b302015-03-07 14:49:43 -080047
Thomas Vachuska51f540f2015-05-27 17:26:57 -070048 /**
49 * Closes all currently open UI web-sockets.
50 */
51 public static void closeAll() {
52 if (instance != null) {
Thomas Vachuska4e0e0932015-07-24 10:14:34 -070053 instance.isStopped = true;
Thomas Vachuska51f540f2015-05-27 17:26:57 -070054 instance.sockets.forEach(UiWebSocket::close);
55 instance.sockets.clear();
Thomas Vachuska4e0e0932015-07-24 10:14:34 -070056 instance.pruner.cancel();
57 instance.timer.cancel();
Thomas Vachuska51f540f2015-05-27 17:26:57 -070058 }
59 }
60
Thomas Vachuska3553b302015-03-07 14:49:43 -080061 @Override
62 public void init() throws ServletException {
63 super.init();
Thomas Vachuska51f540f2015-05-27 17:26:57 -070064 instance = this;
Thomas Vachuska3553b302015-03-07 14:49:43 -080065 timer.schedule(pruner, PING_DELAY_MS, PING_DELAY_MS);
66 }
67
68 @Override
69 public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
Thomas Vachuska4e0e0932015-07-24 10:14:34 -070070 if (isStopped) {
71 return null;
72 }
Thomas Vachuska0af26912016-03-21 21:37:30 -070073
74 // FIXME: Replace this with globally shared opaque token to allow secure failover
75 String userName = request.getUserPrincipal().getName();
76 UiWebSocket socket = new UiWebSocket(directory, userName);
Thomas Vachuska3553b302015-03-07 14:49:43 -080077 synchronized (sockets) {
78 sockets.add(socket);
79 }
80 return socket;
81 }
82
Thomas Vachuskafa74dd72016-03-20 19:11:12 -070083 /**
84 * Sends the specified message to all the GUI clients.
85 *
86 * @param type message type
87 * @param payload message payload
88 */
89 static void sendToAll(String type, ObjectNode payload) {
90 if (instance != null) {
91 instance.sockets.forEach(ws -> ws.sendMessage(type, 0, payload));
92 }
93 }
94
Thomas Vachuska0af26912016-03-21 21:37:30 -070095 /**
96 * Sends the specified message to all the GUI clients of the specified user.
97 *
98 * @param userName user name
99 * @param type message type
100 * @param payload message payload
101 */
102 static void sendToUser(String userName, String type, ObjectNode payload) {
103 if (instance != null) {
104 instance.sockets.stream().filter(ws -> userName.equals(ws.userName()))
105 .forEach(ws -> ws.sendMessage(type, 0, payload));
106 }
107 }
108
Thomas Vachuska3553b302015-03-07 14:49:43 -0800109 // Task for pruning web-sockets that are idle.
110 private class Pruner extends TimerTask {
111 @Override
112 public void run() {
113 synchronized (sockets) {
114 Iterator<UiWebSocket> it = sockets.iterator();
115 while (it.hasNext()) {
116 UiWebSocket socket = it.next();
117 if (socket.isIdle()) {
118 it.remove();
119 socket.close();
120 }
121 }
122 }
123 }
124 }
125}