3. サーバー側のエンドポイントの実装
環境が構築できたら、早速WebSocketを利用したアプリケーションを作成してみよう。まず手始めに、クライアントから送信されたメッセージをそのまま返送するアプリケーションを作ってみる。プロジェクトの種類は通常のWebアプリケーションと同様に「動的Webプロジェクト」でよい。
プロジェクト名は「WebSocketSample」とする。ターゲット・ランタイムには「WebSphere Application Server Liberty Profile」を指定しておく。
プロジェクトが作成されたら、まずはサーバー側のエンドポイント(接続の一端となるサーバー側のコンポーネント)を作成する。WebSocket用プラグインを導入している場合、ウィザードを使ってエンドポイントのひな形を作成できるようになっている。新規作成ウィザードの[Web]カテゴリーに図3.3のように[WebSocket Endpoint]が追加されているので、これを選択すれば図3.4のようなウィザードが立ち上がる。
Java API for WebSocketでWebSocketエンドポイントを作るには2つの方法が用意されており、一つは抽象クラスのjavax.websocket.Endpointクラスを継承して独自に実装する方法、もう一つはアノテーションを使って定義する方法となる。今回はより手軽な後者の方法を利用する。
この場合、ウィザード下部の[Implementation Optios]で[Create an Annotated Server Endpoint]をチェックすればサーバーエンドポイントが定義できる。[URL]には、クライアントからアクセスする際に使用する識別子を設定する。今回は「Hello」とした。
なお、クライアント側のエンドポイントをJavaを使って作りたい場合は[Create an Annotated Client Endpoint]を、Endpointクラスを継承して自前でエンドポイントを実装したい場合には[Create a Programmatic Endpoint]をチェックしておけばよい。
一連の設定を入力したら、[完了]をクリックすれば図3.5のようにクラスのひな形が作成される。ポイントはクラスに対して@ServerEndpointアノテーションが指定されていることである。URLに指定した識別子は引数として設定される。また、プロジェクトツリーにWebSocketsの枝が追加されている点にも注目しよう。ここには作成したWebSocketエンドポイントの一覧が表示される。
Java API for WebSocketにはエンドポイントのイベントハンドラを定義するための以下の4つのアノテーションが用意されている。なお、ここで重要なのはアノテーションなので、メソッド名は任意に指定してよい。
これを踏まえて、クライアントから受け取ったメッセージをそのまま返送するようなエンドポイントは、次のようなコードで書くことができる。まず接続が確立した際には@OnOpenを指定したOnOpen()メソッドが呼び出されるので、ここでセッションを保存しておく。メッセージを受信した場合は@OnMesssageを指定したreceiveMessage()メソッドが呼び出されるので、受け取ったメッセージの先頭に「Hello」の文字列を付加して返信する。
クライアントへメッセージを送信するには、SessionオブジェクトからRemoteEndpointオブジェクトを取得した上で、それに対してsendText()メソッドを実行すればよい。RemoteEndpointオブジェクトには同期型のRemoteEndpoint.Basicと非同期型のでRemoteEndpoint.Asyncの2種類があり、それぞれSession.getBasicRemote()メソッドおよびSession.getAsyncRemote()メソッドで取得できる。ここでは同期型のRemoteEndpointを使用している。
@ServerEndpoint("/Hello") public class HelloEndpoint { // 現在のセッションを記録 Session currentSession = null; /* * 接続がオープンしたとき */ @OnOpen public void onOpen(Session session, EndpointConfig ec) { this.currentSession = session; } /* * メッセージを受信したとき */ @OnMessage public void receiveMessage(String msg) throws IOException { //メッセージをクライアントに送信する this.currentSession.getBasicRemote().sendText("Hello " + msg + "."); } /* * 接続がクローズしたとき */ @OnClose public void onClose(Session session, CloseReason reason) { //... } /* * 接続エラーが発生したとき */ @OnError public void onError(Throwable t) { //... } }