I've browsed a lot of Web Socket examples, presentation slides and they are mostly concentrated on a rather simple scenarios in which client-server communication is initiated by the client.
I am interested in another scenario, which seems to be equally practical: pure server push to client.
Example I have in mind is an application that updates stocks value on a website. Imagine there is an external system stock exchange system, which is sending a JMS message for every subscribed stock value change.
I would like to know how to translate such incoming JMS event into a server push and to it efficiently and idiomatically from a Java EE 7 point of view.
As far as I can understand the spec, I am supposed to write a web socket endpoint
@ServerEndpoint("/demo")
public class WSEndpoint {
private static final Logger LOG = Logger.getLogger(WSEndpoint.class);
@OnMessage
public void onMessage(String message, Session session) {
LOG.info("Received : " + message + ", session:" + session.getId());
}
@OnOpen
public void open(Session session) {
LOG.info("Open session:" + session.getId());
}
@OnClose
public void close(Session session, CloseReason c) {
log.info("Close session:" + session.getId());
}
}
Everything is easy when I am getting a message from the frontend, I can do whatever I like in the @OnMessage
method. But in my example I will not get any message from the client, I'll get an event from some external system.
There are a few approaches. For instance I can create a thread in an @OnOpen
method, as demonstrated in this blog. In practice that approach might show a shortcoming since for every client I would need to create a new, potentially long living thread.
One can do better using NIO channels with selectors, but this would demand some kind of "hand made" channels management. Doable, but rather cumbersome.
Another solution would be to ping some other system for updates, but again it would be kind of ugly. In addition I am also not sure if an @OnOpen
method is meant to be used in that way.
Ideally an incoming JMS message would trigger a Web Socket push to the client. Any ideas how to implement something like this nicely?
Probably this is not most elegant way but just to demonstrate idea. Method broadcast() will send message to all connected clients.
@ServerEndpoint("/echo")
public class ServerEndPoint {
private static Set<Session> userSessions = Collections.newSetFromMap(new ConcurrentHashMap<Session, Boolean>());
@OnOpen
public void onOpen(Session userSession) {
userSessions.add(userSession);
}
@OnClose
public void onClose(Session userSession) {
userSessions.remove(userSession);
}
@OnMessage
public void onMessage(String message, Session userSession) {
broadcast(message);
}
public static void broadcast(String msg) {
for (Session session : userSessions) {
session.getAsyncRemote().sendText(msg);
}
}
}