Merge "Bug 1341 - Make RESTConf websocket port configurable"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / streams / websockets / WebSocketServer.java
1 package org.opendaylight.controller.sal.streams.websockets;
2
3 import io.netty.bootstrap.ServerBootstrap;
4 import io.netty.channel.Channel;
5 import io.netty.channel.EventLoopGroup;
6 import io.netty.channel.nio.NioEventLoopGroup;
7 import io.netty.channel.socket.nio.NioServerSocketChannel;
8
9 import org.opendaylight.controller.sal.streams.listeners.Notificator;
10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
12
13 import com.google.common.base.Preconditions;
14
15 /**
16  * {@link WebSocketServer} is responsible to start and stop web socket server
17  */
18 public class WebSocketServer implements Runnable {
19
20     private static final Logger logger = LoggerFactory
21             .getLogger(WebSocketServer.class);
22     public static final String WEBSOCKET_SERVER_CONFIG_PROPERTY = "restconf.websocket.port";
23     public static final int DEFAULT_PORT = 8181;
24     private EventLoopGroup bossGroup;
25     private EventLoopGroup workerGroup;
26     private static WebSocketServer singleton = null;
27     private int port = DEFAULT_PORT;
28
29     private WebSocketServer(int port) {
30         this.port = port;
31     }
32
33     /**
34      * Create instance of {@link WebSocketServer}
35      * @param port TCP port used for this server
36      * @return instance of {@link WebSocketServer}
37      */
38     public static WebSocketServer createInstance(int port) {
39         if(singleton != null) {
40             throw new IllegalStateException("createInstance() has already been called");
41         }
42         if(port < 1024) {
43             throw new IllegalArgumentException("Privileged port (below 1024) is not allowed");
44         }
45         singleton = new WebSocketServer(port);
46         return singleton;
47     }
48
49     /**
50      * Return websocket TCP port
51      */
52     public int getPort() {
53         return port;
54     }
55
56     /**
57      * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}
58      * @return instance of {@link WebSocketServer}
59      */
60     public static WebSocketServer getInstance() {
61         Preconditions.checkNotNull(singleton,
62                 "createInstance() must be called prior to getInstance()");
63         return singleton;
64     }
65
66     /**
67      * Destroy this already created instance
68      */
69     public static void destroyInstance() {
70         if(singleton == null) {
71             throw new IllegalStateException(
72                     "createInstance() must be called prior to destroyInstance()");
73         }
74         getInstance().stop();
75     }
76
77     @Override
78     public void run() {
79         bossGroup = new NioEventLoopGroup();
80         workerGroup = new NioEventLoopGroup();
81         try {
82             ServerBootstrap b = new ServerBootstrap();
83             b.group(bossGroup, workerGroup)
84                     .channel(NioServerSocketChannel.class)
85                     .childHandler(new WebSocketServerInitializer());
86
87             Channel ch = b.bind(port).sync().channel();
88             logger.info("Web socket server started at port {}.", port);
89
90             ch.closeFuture().sync();
91         } catch (InterruptedException e) {
92             // NOOP
93         } finally {
94             stop();
95         }
96     }
97
98     /**
99      * Stops the web socket server and removes all listeners.
100      */
101     private void stop() {
102         Notificator.removeAllListeners();
103         if (bossGroup != null) {
104             bossGroup.shutdownGracefully();
105         }
106         if (workerGroup != null) {
107             workerGroup.shutdownGracefully();
108         }
109     }
110
111 }