blob: 2e45dc66c82f06c457b827a322c107ad8a3ea157 [file] [log] [blame]
Thomas Vachuska750ab042015-06-17 10:42:15 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska750ab042015-06-17 10:42:15 -07003 *
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.onlab.stc;
17
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070018import com.fasterxml.jackson.databind.node.ObjectNode;
Thomas Vachuska750ab042015-06-17 10:42:15 -070019import com.google.common.io.ByteStreams;
20import com.google.common.net.MediaType;
21import org.eclipse.jetty.websocket.WebSocket;
22import org.eclipse.jetty.websocket.WebSocketServlet;
23
24import javax.servlet.ServletException;
25import javax.servlet.http.HttpServletRequest;
26import javax.servlet.http.HttpServletResponse;
27import java.io.IOException;
28import java.io.InputStream;
29import java.util.HashSet;
30import java.util.Iterator;
31import java.util.Set;
32import java.util.Timer;
33import java.util.TimerTask;
34
35/**
36 * Web socket servlet capable of creating web sockets for the STC monitor.
37 */
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070038public class MonitorWebSocketServlet extends WebSocketServlet
39 implements MonitorDelegate {
Thomas Vachuska750ab042015-06-17 10:42:15 -070040
41 private static final long PING_DELAY_MS = 5000;
42 private static final String DOT = ".";
43
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070044 private static Monitor monitor;
Thomas Vachuska750ab042015-06-17 10:42:15 -070045 private static MonitorWebSocketServlet instance;
46
47 private final Set<MonitorWebSocket> sockets = new HashSet<>();
48 private final Timer timer = new Timer();
49 private final TimerTask pruner = new Pruner();
50
51 /**
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070052 * Binds the shared process flow monitor.
53 *
54 * @param m process monitor reference
55 */
56 public static void setMonitor(Monitor m) {
57 monitor = m;
58 }
59
60 /**
Thomas Vachuska750ab042015-06-17 10:42:15 -070061 * Closes all currently open monitor web-sockets.
62 */
63 public static void closeAll() {
64 if (instance != null) {
65 instance.sockets.forEach(MonitorWebSocket::close);
66 instance.sockets.clear();
67 }
68 }
69
70 @Override
71 public void init() throws ServletException {
72 super.init();
73 instance = this;
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070074 monitor.setDelegate(this);
Thomas Vachuska750ab042015-06-17 10:42:15 -070075 timer.schedule(pruner, PING_DELAY_MS, PING_DELAY_MS);
76 }
77
78 @Override
79 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
80 throws ServletException, IOException {
81 String uri = req.getRequestURI();
82 uri = uri.length() <= 1 ? "/index.html" : uri;
83 InputStream resource = getClass().getResourceAsStream(uri);
84 if (resource == null) {
85 resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
86 } else {
87 byte[] entity = ByteStreams.toByteArray(resource);
88 resp.setStatus(HttpServletResponse.SC_OK);
89 resp.setContentType(contentType(uri).toString());
90 resp.setContentLength(entity.length);
91 resp.getOutputStream().write(entity);
92 }
93 }
94
95 private MediaType contentType(String uri) {
96 int sep = uri.lastIndexOf(DOT);
97 String ext = sep > 0 ? uri.substring(sep + 1) : null;
98 return ext == null ? MediaType.APPLICATION_BINARY :
99 ext.equals("html") ? MediaType.HTML_UTF_8 :
100 ext.equals("js") ? MediaType.JAVASCRIPT_UTF_8 :
101 ext.equals("css") ? MediaType.CSS_UTF_8 :
102 MediaType.APPLICATION_BINARY;
103 }
104
105 @Override
106 public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -0700107 MonitorWebSocket socket = new MonitorWebSocket(monitor);
Thomas Vachuska750ab042015-06-17 10:42:15 -0700108 synchronized (sockets) {
109 sockets.add(socket);
110 }
111 return socket;
112 }
113
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -0700114 @Override
115 public void notify(ObjectNode event) {
116 if (instance != null) {
117 instance.sockets.forEach(ws -> ws.sendMessage(event));
118 }
119 }
120
Thomas Vachuska750ab042015-06-17 10:42:15 -0700121 // Task for pruning web-sockets that are idle.
122 private class Pruner extends TimerTask {
123 @Override
124 public void run() {
125 synchronized (sockets) {
126 Iterator<MonitorWebSocket> it = sockets.iterator();
127 while (it.hasNext()) {
128 MonitorWebSocket socket = it.next();
129 if (socket.isIdle()) {
130 it.remove();
131 socket.close();
132 }
133 }
134 }
135 }
136 }
137}