Bug 9256: Add websocket server config knob for ip
[netconf.git] / restconf / restconf-nb-bierman02 / src / main / java / org / opendaylight / netconf / sal / streams / websockets / WebSocketServer.java
1 /*
2  * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netconf.sal.streams.websockets;
10
11 import com.google.common.base.Preconditions;
12 import io.netty.bootstrap.ServerBootstrap;
13 import io.netty.channel.Channel;
14 import io.netty.channel.EventLoopGroup;
15 import io.netty.channel.nio.NioEventLoopGroup;
16 import io.netty.channel.socket.nio.NioServerSocketChannel;
17 import org.opendaylight.netconf.sal.streams.listeners.Notificator;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 /**
22  * {@link WebSocketServer} is the singleton responsible for starting and stopping the
23  * web socket server.
24  */
25 public class WebSocketServer implements Runnable {
26
27     private static final Logger LOG = LoggerFactory.getLogger(WebSocketServer.class);
28
29     private static final String DEFAULT_ADDRESS = "0.0.0.0";
30
31     private static WebSocketServer instance = null;
32
33     private final String address;
34     private final int port;
35
36     private EventLoopGroup bossGroup;
37     private EventLoopGroup workerGroup;
38
39
40     private WebSocketServer(final String address, final int port) {
41         this.address = address;
42         this.port = port;
43     }
44
45     /**
46      * Create singleton instance of {@link WebSocketServer}.
47      *
48      * @param port TCP port used for this server
49      * @return instance of {@link WebSocketServer}
50      */
51     private static WebSocketServer createInstance(final int port) {
52         instance = createInstance(DEFAULT_ADDRESS, port);
53         return instance;
54     }
55
56     public static WebSocketServer createInstance(final String address, final int port) {
57         Preconditions.checkState(instance == null, "createInstance() has already been called");
58         Preconditions.checkNotNull(address, "Address cannot be null.");
59         Preconditions.checkArgument(port >= 1024, "Privileged port (below 1024) is not allowed");
60
61         instance = new WebSocketServer(address, port);
62         return instance;
63     }
64
65     /**
66      * Get the websocket of TCP port.
67      *
68      * @return websocket TCP port
69      */
70     public int getPort() {
71         return port;
72     }
73
74     /**
75      * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
76      *
77      * @return instance of {@link WebSocketServer}
78      */
79     public static WebSocketServer getInstance() {
80         Preconditions.checkNotNull(instance, "createInstance() must be called prior to getInstance()");
81         return instance;
82     }
83
84     /**
85      * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
86      * If an instance doesnt exist create one with the provided fallback port.
87      *
88      * @return instance of {@link WebSocketServer}
89      */
90     public static WebSocketServer getInstance(final int fallbackPort) {
91         if (instance != null) {
92             return instance;
93         }
94
95         LOG.warn("No instance for WebSocketServer found, creating one with a fallback port: {}", fallbackPort);
96         return createInstance(fallbackPort);
97     }
98
99     /**
100      * Destroy the existing instance.
101      */
102     public static void destroyInstance() {
103         Preconditions.checkState(instance != null, "createInstance() must be called prior to destroyInstance()");
104
105         instance.stop();
106         instance = null;
107     }
108
109     @Override
110     public void run() {
111         bossGroup = new NioEventLoopGroup();
112         workerGroup = new NioEventLoopGroup();
113         try {
114             final ServerBootstrap serverBootstrap = new ServerBootstrap();
115             serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
116                     .childHandler(new WebSocketServerInitializer());
117
118             final Channel channel = serverBootstrap.bind(address, port).sync().channel();
119             LOG.info("Web socket server started at address {}, port {}.", address, port);
120
121             channel.closeFuture().sync();
122         } catch (final InterruptedException e) {
123             LOG.error("Web socket server encountered an error during startup attempt on port {}", port, e);
124         } finally {
125             stop();
126         }
127     }
128
129     /**
130      * Stops the web socket server and removes all listeners.
131      */
132     private void stop() {
133         LOG.info("Stopping the web socket server instance on port {}", port);
134         Notificator.removeAllListeners();
135         if (bossGroup != null) {
136             bossGroup.shutdownGracefully();
137             bossGroup = null;
138         }
139         if (workerGroup != null) {
140             workerGroup.shutdownGracefully();
141             workerGroup = null;
142         }
143     }
144
145 }