技術研究所の (あ) です。
HTTP でコネクションを張って双方向通信を行う WebSocket というのがありますよね。
技術研究所の作った、ブラウザで動いているとあるデモアプリがサーバとの通信に WebSocket を使っているのですが、そのデモの動きを改良したくなりました。
私はちょこちょことプロトタイピングするのによく Java を使うので、例によって Java アプリとして作ってみました。

 

そんなわけで、初めての WebSocket クライアント作成 (Java で) の簡単な記録です。
環境は、Windows 7 + Java 1.8.0_25 です。

準備、というか下調べ

まずは「きっと Java用の WebSocket ライブラリってあるよね」ということで検索してみます。
お、出てくる出てくる…と思ったら多くは
「Java で WebSocket を使ったサーバアプリを実装する」という話でしたorz。
まあ、クライアントはブラウザで JavaScript で動いたほうが便利な場合が多いですからね…。
検索ワードに「クライアント」を追加しても引っかかるのはほとんどそっちの話でしたが、埋もれかかってる中から何とか情報を引っ張りだしたところ

「Java EE に javax.websocket.* というのがあって(Java EE 7 以降)、それを使えばできる」

ということが判りました。

Java EE をインストール?

Java EE というのは Java SE の拡張機能セットのようなものですが、「仕様」として策定されているものなので「Java EE SDK」を Oracle 社のダウンロードページから入手すると、実際の中身は glassfish という Java EE 準拠のアプリケーションサーバです。
そんなわけで、入手した java_ee_sdk-7u2.zip を展開すると作られるフォルダ名が glassfish4 だったりするので、初心者にはなかなかの混乱ポイントとなりそうです。

で、しかも、今回使いたいクライアント側の実装は含まれていないようで (ひょっとしたらもっと探すとあるのかな…)、別途探してくる必要があります (多段トラップですね^^;)。
Tyrus Project ( https://tyrus.java.net/ ) というプロジェクトで参照実装を作っている、ということで、プロジェクトのウェブサイトのページから tyrus-standalone-client-1.9.jar をダウンロードしてきました (この記事を書いている時点ではバージョン 1.12 が最新のようです)。
ダウンロードした jar ファイルに CLASSPATH を通せば、WebSocket API を使ってクライアントプログラムが組めるはず、です。

WebSocket API を使う

WebSocket API を使うには、EndPoint クラスを継承する方法と、アノテーションを使う方法の二つがあるとのこと。見つけたサンプルがアノテーションを使っていたので、そっちを使ってみました。

import javax.websocket.*;


import java.net.*;

@ClientEndpoint

public class WebSocketTest
{
  static boolean connected = false;

  // - - - - - - -
  @OnError
  public void onError(Session session, Throwable cause) {
    // エラー
    System.out.println("error : " + session.getId() + ", " + cause.getMessage());
  }

  // - - - - - - -

  @OnMessage
  public void onMessage(String msg, Session session) {
    // 文字列を受け取る
    System.out.println("onMessage: " + msg);
  } 

  // - - - - - - -
  @OnClose
  public void onClose(Session session, CloseReason closeReason) {
    // 接続が閉じられた
    System.out.println("closed");
    connected = false;
  }

  // - - - - - - -
  @OnOpen
  public void onOpen(Session session) {
    // 接続した
    System.out.println("opened");
  }

  // - - - - - - -
  public static void connect(String url) {
    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    Class<?> c = WebSocketForSignage.class;

    // 接続
    try (Session session = container.connectToServer(c, URI.create(url))) {
      connected = true;

      while (connected) {
        // 接続中

        // 文字列を送る
        session.getBasicRemote().sendText("message");
  
        (その他送信側の処理いろいろ)
      }
    } catch (Exception e) {
      System.err.println(e);
    }
  }
}

このように、@ClientEndPoint をつけたクラスで、メッセージの受信は @OnMessage をつけたメソッドで、という感じで書くとクライアントのできあがり。簡単ですね。
あとはアプリケーションの目的に合わせてメッセージのやりとりなど捌けるようにすれば完成です。

まとめ

以上、さらっと書きましたが、実際はいろいろ調べて試行錯誤を重ねつつの道のりでした。Java で WebSocket クライアントを書きたい、という需要は多くないのか(笑)、そこから出発するとあまりまとまった情報がみつからない、という印象です。
判ってしまえば、tyrus-standalone-client を使えばよいだけなのでとても簡単なんですけどねー。

ちらっと試しただけなので、上述の内容には間違いがあるかもしれませんし、まだまだ足りない部分も多いと思います。また何か解ったら適宜、補足・修正したいと思います。