WebSocket(JSR 356)を使ってみる。その3

これまでに引き続きWebSocketを試してみる。

APIをみるとgetOpenSessions()というメソッドがあり、そのセッションに紐付くセッションが取れるとのこと。また、OnMessageアノテーションの説明によるとPOJOのメソッド引数にSessionをオプショナルな引数として渡せるとのこと。

下のように引数にセッションを追加してやって、そのセッションからgetOpenSessionsを呼んでやれば対向のエンドポイントにメッセージを送れた。

package hp.co.epea.first;

import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/hello")
public class HelloWorld {

/* 
 * sessionOfEndPointとsessionOfClientEndPointという名前になっているけど
 * 勘違いしていたことによるよくない名前。
 * 引数のSessionはリクエストを出したPeerと受け取ったPeer間のSessionなので
 * sessionOfCurrentReqみたいなもの。
 * getOpenSessionsで取得できるのはそのsessionが持つendPointに紐付くやつなので
 * sessionOfRelatedみたいなものが本来
 */
    @OnMessage
    public void onMessage(String message,Session sessionOfSvEndPoint) {
        Set<Session> sessionsOfClientEndPoint = sessionOfSvEndPoint.getOpenSessions();
        System.out.println("sessionsOfClientEndPoint.size():" +sessionsOfClientEndPoint.size());
        System.out.println("message[" + message + "]");
        for (Session s : sessionsOfClientEndPoint) {
            s.getAsyncRemote().sendText(message);
        }
    }

    @OnOpen
    public void open(Session sess) {
        System.out.println("開始します:" + sess.getId());
    }

    @OnClose
    public void close(Session sess) {
        System.out.println("終了します:" + sess.getId());
    }

    @OnError
    public void error(Session sess, Throwable t) {
        System.out.println("エラーです:" + sess.getId());
        t.printStackTrace();
    }
}

他の方が書いている記事を発見

対向のエンドポイントが閉じられた場合(こちらのOnCloseが終わったら?)そのエンドポイントはないものと扱われている。

(3つ開いている)
情報: 開始します:07d672db-af64-435c-a272-2698528927f1
情報: 開始します:91202881-63ac-45b8-a3a1-d53e7bdc2008
情報: 開始します:628fc0c0-9cde-4812-a12b-d2ce52cc146e
情報: sessionsOfClientEndPoint.size():3 <-開いている数
情報: message[あああ]
(1つ閉じて2個にする)
情報: 終了します:628fc0c0-9cde-4812-a12b-d2ce52cc146e
情報: sessionsOfClientEndPoint.size():2 <-開いている数
情報: message[いいい]

ただこのやり方だとsessionOfSvEndPoint.getOpenSessions()してからfor文が回っている間にコネクションが閉じられるとコネクションクローズ済みエラーが飛んでしまう。前の書き方のほうがいいのかな。

情報: 開始します:68d4f179-7c99-4118-b829-f48f7fc9d670
情報: 開始します:83ccdfea-f0b8-4dc5-8cc3-3d9bddebc658
情報: sessionsOfClientEndPoint.size():2 <-セッションのコピーをとる
情報: message[a]
情報: 終了します:83ccdfea-f0b8-4dc5-8cc3-3d9bddebc658 <-for文の前に(or途中で)閉じる
情報: エラーです:68d4f179-7c99-4118-b829-f48f7fc9d670 <- OnErrorの引数で入ってくるのは実際に例外の原因となったものでなくてOnmessageを呼んだSessionの模様。
重大: java.lang.IllegalStateException: The connection has been closed.
    at org.glassfish.tyrus.core.SessionImpl.checkConnectionState(SessionImpl.java:343)
    at org.glassfish.tyrus.core.SessionImpl.getAsyncRemote(SessionImpl.java:180)
    at hp.co.epea.first.HelloWorld.onMessage(HelloWorld.java:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.tyrus.core.AnnotatedEndpoint.callMethod(AnnotatedEndpoint.java:431)
    at org.glassfish.tyrus.core.AnnotatedEndpoint.access$100(AnnotatedEndpoint.java:83)
    at org.glassfish.tyrus.core.AnnotatedEndpoint$WholeHandler$1.onMessage(AnnotatedEndpoint.java:518)
    at org.glassfish.tyrus.core.SessionImpl.notifyMessageHandlers(SessionImpl.java:389)
    at org.glassfish.tyrus.core.EndpointWrapper.onMessage(EndpointWrapper.java:495)
    at org.glassfish.tyrus.server.TyrusEndpoint.onMessage(TyrusEndpoint.java:174)
    at org.glassfish.tyrus.websockets.DefaultWebSocket.onMessage(DefaultWebSocket.java:156)
    at org.glassfish.tyrus.websockets.frametypes.TextFrameType.respond(TextFrameType.java:66)
    at org.glassfish.tyrus.websockets.DataFrame.respond(DataFrame.java:102)
    at org.glassfish.tyrus.servlet.TyrusHttpUpgradeHandler.onDataAvailable(TyrusHttpUpgradeHandler.java:113)
    at org.apache.catalina.connector.InputBuffer$ReadHandlerImpl.processDataAvailable(InputBuffer.java:488)
    at org.apache.catalina.connector.InputBuffer$ReadHandlerImpl.onDataAvailable(InputBuffer.java:453)
    at org.glassfish.grizzly.http.io.InputBuffer.append(InputBuffer.java:855)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:222)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
    at java.lang.Thread.run(Thread.java:724)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です