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
9 package org.opendaylight.restconf.nb.rfc8040.streams.websockets;
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.restconf.nb.rfc8040.streams.listeners.ListenersBroker;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
22 * {@link WebSocketServer} is the class that is responsible for starting and stopping of web-socket server with
23 * specified listening TCP port.
25 public final class WebSocketServer implements Runnable {
27 private static final Logger LOG = LoggerFactory.getLogger(WebSocketServer.class);
28 private static WebSocketServer instance = null;
30 private final int port;
32 private EventLoopGroup bossGroup;
33 private EventLoopGroup workerGroup;
36 private WebSocketServer(final int port) {
41 * Create singleton instance of {@link WebSocketServer}.
43 * @param port TCP port used for this server.
45 public static WebSocketServer createInstance(final int port) {
46 Preconditions.checkState(instance == null, "createInstance() has already been called");
47 Preconditions.checkArgument(port >= 1024, "Privileged port (below 1024) is not allowed");
49 instance = new WebSocketServer(port);
54 * Get the TCP port of websocket server.
56 * @return TCP port number.
58 public int getPort() {
63 * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
65 * @return Instance of {@link WebSocketServer}.
67 public static WebSocketServer getInstance() {
68 Preconditions.checkNotNull(instance, "createInstance() must be called prior to getInstance()");
73 * Destroy the existing instance.
75 public static void destroyInstance() {
76 Preconditions.checkState(instance != null, "createInstance() must be called prior to destroyInstance()");
83 @SuppressWarnings("checkstyle:IllegalCatch")
85 bossGroup = new NioEventLoopGroup();
86 workerGroup = new NioEventLoopGroup();
88 final ServerBootstrap serverBootstrap = new ServerBootstrap();
89 serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
90 .childHandler(new WebSocketServerInitializer());
92 final Channel channel = serverBootstrap.bind(port).sync().channel();
93 LOG.info("Web socket server started at port {}.", port);
95 channel.closeFuture().sync();
96 } catch (final InterruptedException e) {
97 LOG.error("Web socket server encountered an error during startup attempt on port {}.", port, e);
98 } catch (Throwable throwable) {
99 // sync() re-throws exceptions declared as Throwable, so the compiler doesn't see them
100 LOG.error("Error while binding to port {}.", port, throwable);
108 * Stops the web socket server and removes all listeners.
110 private void stop() {
111 LOG.debug("Stopping the web socket server instance on port {}.", port);
112 ListenersBroker.getInstance().removeAndCloseAllListeners();
113 if (bossGroup != null) {
114 bossGroup.shutdownGracefully();
117 if (workerGroup != null) {
118 workerGroup.shutdownGracefully();