Bump versions to 4.0.0-SNAPSHOT
[netconf.git] / restconf / restconf-nb-bierman02 / src / main / java / org / opendaylight / netconf / sal / streams / websockets / WebSocketServer.java
index 23bff91a5317b47726ba8d8bf6f24bc380d33054..a295c54a3f9351fa37574cd82d7fbb61362d09a8 100644 (file)
@@ -5,10 +5,12 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.netconf.sal.streams.websockets;
 
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.channel.Channel;
 import io.netty.channel.EventLoopGroup;
@@ -22,19 +24,23 @@ import org.slf4j.LoggerFactory;
  * {@link WebSocketServer} is the singleton responsible for starting and stopping the
  * web socket server.
  */
-public class WebSocketServer implements Runnable {
+public final class WebSocketServer implements Runnable {
 
     private static final Logger LOG = LoggerFactory.getLogger(WebSocketServer.class);
 
+    private static final String DEFAULT_ADDRESS = "0.0.0.0";
+
     private static WebSocketServer instance = null;
 
+    private final String address;
     private final int port;
 
     private EventLoopGroup bossGroup;
     private EventLoopGroup workerGroup;
 
 
-    private WebSocketServer(final int port) {
+    private WebSocketServer(final String address, final int port) {
+        this.address = address;
         this.port = port;
     }
 
@@ -44,11 +50,17 @@ public class WebSocketServer implements Runnable {
      * @param port TCP port used for this server
      * @return instance of {@link WebSocketServer}
      */
-    public static WebSocketServer createInstance(final int port) {
-        Preconditions.checkState(instance == null, "createInstance() has already been called");
-        Preconditions.checkArgument(port >= 1024, "Privileged port (below 1024) is not allowed");
+    private static WebSocketServer createInstance(final int port) {
+        instance = createInstance(DEFAULT_ADDRESS, port);
+        return instance;
+    }
+
+    public static WebSocketServer createInstance(final String address, final int port) {
+        checkState(instance == null, "createInstance() has already been called");
+        checkArgument(port >= 1024, "Privileged port (below 1024) is not allowed");
 
-        instance = new WebSocketServer(port);
+        instance = new WebSocketServer(requireNonNull(address, "Address cannot be null."), port);
+        LOG.info("Created WebSocketServer on {}:{}", address, port);
         return instance;
     }
 
@@ -67,21 +79,37 @@ public class WebSocketServer implements Runnable {
      * @return instance of {@link WebSocketServer}
      */
     public static WebSocketServer getInstance() {
-        Preconditions.checkNotNull(instance, "createInstance() must be called prior to getInstance()");
-        return instance;
+        return requireNonNull(instance, "createInstance() must be called prior to getInstance()");
+    }
+
+    /**
+     * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
+     * If an instance doesnt exist create one with the provided fallback port.
+     *
+     * @return instance of {@link WebSocketServer}
+     */
+    public static WebSocketServer getInstance(final int fallbackPort) {
+        if (instance != null) {
+            return instance;
+        }
+
+        LOG.warn("No instance for WebSocketServer found, creating one with a fallback port: {}", fallbackPort);
+        return createInstance(fallbackPort);
     }
 
     /**
      * Destroy the existing instance.
      */
     public static void destroyInstance() {
-        Preconditions.checkState(instance != null, "createInstance() must be called prior to destroyInstance()");
+        checkState(instance != null, "createInstance() must be called prior to destroyInstance()");
 
         instance.stop();
         instance = null;
+        LOG.info("Destroyed WebSocketServer.");
     }
 
     @Override
+    @SuppressWarnings("checkstyle:IllegalCatch")
     public void run() {
         bossGroup = new NioEventLoopGroup();
         workerGroup = new NioEventLoopGroup();
@@ -90,12 +118,16 @@ public class WebSocketServer implements Runnable {
             serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                     .childHandler(new WebSocketServerInitializer());
 
-            final Channel channel = serverBootstrap.bind(port).sync().channel();
-            LOG.info("Web socket server started at port {}.", port);
+            final Channel channel = serverBootstrap.bind(address, port).sync().channel();
+            LOG.info("Web socket server started at address {}, port {}.", address, port);
 
             channel.closeFuture().sync();
         } catch (final InterruptedException e) {
             LOG.error("Web socket server encountered an error during startup attempt on port {}", port, e);
+        } catch (Throwable throwable) {
+            // sync() re-throws exceptions declared as Throwable, so the compiler doesn't see them
+            LOG.error("Error while binding to address {}, port {}", address, port, throwable);
+            throw throwable;
         } finally {
             stop();
         }
@@ -105,7 +137,7 @@ public class WebSocketServer implements Runnable {
      * Stops the web socket server and removes all listeners.
      */
     private void stop() {
-        LOG.debug("Stopping the web socket server instance on port {}", port);
+        LOG.info("Stopping the web socket server instance on port {}", port);
         Notificator.removeAllListeners();
         if (bossGroup != null) {
             bossGroup.shutdownGracefully();