2 * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.netconf.sal.streams.websockets;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
14 import io.netty.bootstrap.ServerBootstrap;
15 import io.netty.channel.Channel;
16 import io.netty.channel.EventLoopGroup;
17 import io.netty.channel.nio.NioEventLoopGroup;
18 import io.netty.channel.socket.nio.NioServerSocketChannel;
19 import org.opendaylight.netconf.sal.streams.listeners.Notificator;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
24 * {@link WebSocketServer} is the singleton responsible for starting and stopping the
27 public final class WebSocketServer implements Runnable {
29 private static final Logger LOG = LoggerFactory.getLogger(WebSocketServer.class);
31 private static final String DEFAULT_ADDRESS = "0.0.0.0";
33 private static WebSocketServer instance = null;
35 private final String address;
36 private final int port;
38 private EventLoopGroup bossGroup;
39 private EventLoopGroup workerGroup;
42 private WebSocketServer(final String address, final int port) {
43 this.address = address;
48 * Create singleton instance of {@link WebSocketServer}.
50 * @param port TCP port used for this server
51 * @return instance of {@link WebSocketServer}
53 private static WebSocketServer createInstance(final int port) {
54 instance = createInstance(DEFAULT_ADDRESS, port);
58 public static WebSocketServer createInstance(final String address, final int port) {
59 checkState(instance == null, "createInstance() has already been called");
60 checkArgument(port >= 1024, "Privileged port (below 1024) is not allowed");
62 instance = new WebSocketServer(requireNonNull(address, "Address cannot be null."), port);
63 LOG.info("Created WebSocketServer on {}:{}", address, port);
68 * Get the websocket of TCP port.
70 * @return websocket TCP port
72 public int getPort() {
77 * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
79 * @return instance of {@link WebSocketServer}
81 public static WebSocketServer getInstance() {
82 return requireNonNull(instance, "createInstance() must be called prior to getInstance()");
86 * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
87 * If an instance doesnt exist create one with the provided fallback port.
89 * @return instance of {@link WebSocketServer}
91 public static WebSocketServer getInstance(final int fallbackPort) {
92 if (instance != null) {
96 LOG.warn("No instance for WebSocketServer found, creating one with a fallback port: {}", fallbackPort);
97 return createInstance(fallbackPort);
101 * Destroy the existing instance.
103 public static void destroyInstance() {
104 checkState(instance != null, "createInstance() must be called prior to destroyInstance()");
108 LOG.info("Destroyed WebSocketServer.");
112 @SuppressWarnings("checkstyle:IllegalCatch")
114 bossGroup = new NioEventLoopGroup();
115 workerGroup = new NioEventLoopGroup();
117 final ServerBootstrap serverBootstrap = new ServerBootstrap();
118 serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
119 .childHandler(new WebSocketServerInitializer());
121 final Channel channel = serverBootstrap.bind(address, port).sync().channel();
122 LOG.info("Web socket server started at address {}, port {}.", address, port);
124 channel.closeFuture().sync();
125 } catch (final InterruptedException e) {
126 LOG.error("Web socket server encountered an error during startup attempt on port {}", port, e);
127 } catch (Throwable throwable) {
128 // sync() re-throws exceptions declared as Throwable, so the compiler doesn't see them
129 LOG.error("Error while binding to address {}, port {}", address, port, throwable);
137 * Stops the web socket server and removes all listeners.
139 private void stop() {
140 LOG.info("Stopping the web socket server instance on port {}", port);
141 Notificator.removeAllListeners();
142 if (bossGroup != null) {
143 bossGroup.shutdownGracefully();
146 if (workerGroup != null) {
147 workerGroup.shutdownGracefully();