TyrusのStandalone Modeは0.0.0.0以外をListenすることはできない

## 結論
* Tyrus1.12のStandalone Modeでは、WebSocketサーバーのListen Addressが0.0.0.0から変更できない。
* つまり、(ファイヤーウォールがなければ)どこからでもアクセスし放題
* 制限をかけるには
 * ファイヤーウォールを適切に設定する
 * Jettyを使う

##  Tyrus in Standalone Modeは0.0.0.0をListenする
スタンドアロンのアプリにWebSocketサーバを組み込みたかったので、調べていたら、Tyrus1.12のドキュメントに[Tyrus in Standalone Mode](https://tyrus.java.net/documentation/1.12/user-guide.html#standalone-mode)という項目を見つけたので試してみました。。

すると、確かに動くのですが、0.0.0.0をlistenしているのが気になりました。スタンドアロンアプリという性質上、localhost以外をlistenしたくなかったのです。

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/29682/bdd93a6b-66a4-6cec-598e-59ccf3c3cf84.png)


## 制御不可
きっとどこかに設定があるのだと思いドキュメントを探しましたがどうも見当たりません。なので仕方なくソースを追ってみました。

まずはサンプルのソースコードを眺めます。

~~~java
・・・
public void runServer() {
    Server server = new Server("localhost", 8025, "/websockets", null, EchoEndpoint.class);

    try {
        server.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Please press a key to stop the server.");
        reader.readLine();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        server.stop();
    }
}
・・・
~~~

``org.glassfish.tyrus.server.Server``クラスを``start``しているようです。見てみましょう。

[github Server.java#L20](https://github.com/tyrus-project/tyrus/blob/cc0cd3ba86ecb6fea454ff36871926ef091d54a8/server/src/main/java/org/glassfish/tyrus/server/Server.java#L208)

~~~java
・・・
/**
 * Start the server.
 */
public void start() throws DeploymentException {
    try {
        if (server == null) {
            server = ServerContainerFactory.createServerContainer(properties);

            for (Class<?> clazz : configuration) {
                server.addEndpoint(clazz);
            }

            server.start(contextPath, port);
            LOGGER.info("WebSocket Registered apps: URLs all start with ws://" + this.hostName + ":" + this.port);
            LOGGER.info("WebSocket server started.");
        }
    } catch (IOException e) {
        throw new DeploymentException(e.getMessage(), e);
    }
}
・・・
~~~

``org.glassfish.tyrus.spi.Server.ContainerFactory``クラスの``createServerContainer``メソッドを呼んでいるようなので更に潜ります。

[github ServerContainerFactory.java#L70](https://github.com/tyrus-project/tyrus/blob/cc0cd3ba86ecb6fea454ff36871926ef091d54a8/spi/src/main/java/org/glassfish/tyrus/spi/ServerContainerFactory.java#L70)

~~~java
・・・
private static final String CONTAINTER_CLASS =
            "org.glassfish.tyrus.container.grizzly.server.GrizzlyServerContainer";
・・・
public static ServerContainer createServerContainer(final Map<String, Object> properties) {
    ・・・
    if (factory == null) {
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Class factoryClass = (classLoader == null)
                    ? Class.forName(CONTAINTER_CLASS)
                    : classLoader.loadClass(CONTAINTER_CLASS);
            factory = (ServerContainerFactory) factoryClass.newInstance();
        } catch (ClassNotFoundException ce) {
            throw new RuntimeException(ce);
        } catch (InstantiationException ie) {
            throw new RuntimeException(ie);
        } catch (IllegalAccessException ie) {
            throw new RuntimeException(ie);
        }
    }
    return factory.createContainer(properties);
}
・・・
~~~

どうやら``org.glassfish.tyrus.container.grizzly.server.GrizzlyServerContainer``クラスが実体のようです。見てみます。

[github GrizzlyServerContainer.java#L172](https://github.com/tyrus-project/tyrus/blob/cc0cd3ba86ecb6fea454ff36871926ef091d54a8/containers/grizzly-server/src/main/java/org/glassfish/tyrus/container/grizzly/server/GrizzlyServerContainer.java#L172)

~~~java
・・・
@Override
public void start(final String rootPath, int port) throws IOException, DeploymentException {
    contextPath = rootPath;
    server = new HttpServer();
    final ServerConfiguration config = server.getServerConfiguration();

    final NetworkListener listener = new NetworkListener("grizzly", "0.0.0.0", port);  // ★！！！★
    ・・・
}
・・・
    
~~~

うげ！おもいっきり``"0.0.0.0"``ってハードコードしてあるし！

ということで、0.0.0.0をlistenしてしまうのは変更不可のようです。


## 代替案
どうすればよいのでしょうか。

### ファイヤーウォールを正しく設定する。
「どうすればよいのでしょうか」といってもどうにもできないので、ちゃんとファイヤーウォールを設定しましょうというのが結論でしょう。不正なリクエストは受け付けないようにすればいい話です。とはいえ、自分用のアプリならいいとして、いろいろな人に配るようなアプリの場合「設定してね」と言う以上のことはできません。設定してくれるかどうかは利用者次第です・・・


### 別の実装を使う
tyrusの実装がこうなっているというだけなので、tyrusじゃない別の実装を使うというのも良い選択でしょう。ただし、現時点ではドキュメントが少ないですね・・・

ちなみに私はJettyを使いました。

[JavaSEでJettyを使ってWebSocket(JSR-356)サーバーを立てた](http://qiita.com/tatesuke/items/bd6b23053aa5629f8434)