コンテナーは、クライアント接続ごとにエンドポイントの個別のインスタンスを作成するため、実行しようとしていることができません。しかし、あなたがしようとしているのは、イベントが発生したときにすべてのアクティブなクライアント接続にメッセージを送信することだと思います。これはかなり簡単です。
このjavax.websocket.Session
クラスには、そのセッションに関連付けられたエンドポイントを表すインスタンスgetBasicRemote
を取得するメソッドがあります。RemoteEndpoint.Basic
を呼び出して開いているすべてのセッションを取得し、Session.getOpenSessions()
それらを反復処理できます。ループは、各クライアント接続にメッセージを送信します。簡単な例を次に示します。
@ServerEndpoint("/myendpoint")
public class MyEndpoint {
@OnMessage
public void onMessage(Session session, String message) {
try {
for (Session s : session.getOpenSessions()) {
if (s.isOpen()) {
s.getBasicRemote().sendText(message);
}
} catch (IOException ex) { ... }
}
}
しかし、あなたのケースでは、おそらく CDI イベントを使用して、すべてのクライアントへの更新をトリガーしたいと思うでしょう。その場合、Websocket エンドポイント クラスのメソッドが監視する CDI イベントを作成します。
@ServerEndpoint("/myendpoint")
public class MyEndpoint {
// EJB that fires an event when a new article appears
@EJB
ArticleBean articleBean;
// a collection containing all the sessions
private static final Set<Session> sessions =
Collections.synchronizedSet(new HashSet<Session>());
@OnOpen
public void onOpen(final Session session) {
// add the new session to the set
sessions.add(session);
...
}
@OnClose
public void onClose(final Session session) {
// remove the session from the set
sessions.remove(session);
}
public void broadcastArticle(@Observes @NewArticleEvent ArticleEvent articleEvent) {
synchronized(sessions) {
for (Session s : sessions) {
if (s.isOpen()) {
try {
// send the article summary to all the connected clients
s.getBasicRemote().sendText("New article up:" + articleEvent.getArticle().getSummary());
} catch (IOException ex) { ... }
}
}
}
}
}
上記の例の EJB は次のようになります。
...
@Inject
Event<ArticleEvent> newArticleEvent;
public void publishArticle(Article article) {
...
newArticleEvent.fire(new ArticleEvent(article));
...
}
WebSocketsおよびCDI Eventsに関する Java EE 7 チュートリアルの章を参照してください。
編集:@Observer
イベントをパラメーターとして使用するようにメソッドを変更しました。
編集 2: @gcvt ごとに、broadcastArticle のループを同期でラップしました。
編集 3: Java EE 7 チュートリアルへのリンクを更新しました。よくやった、オラクル。おいおい。