Websockets in Java EE

With the JSR-356 spec websockets can be easily created and run within a Java EE container. I am using TomEE as a very lightweight and easy to install and deploy container but every Java EE 7 container should work, thanks to the EE specs.

I’m showing some easy to understand example of the Java POJO and some Javascript example code, together with some explanation about what is does and how it should work.

Annotations

With annotations it is very easy to decorate a POJO that should act as an websocket backend class. When a websocket connection is started a new instance of the class will be created and kept in memory until the connection is closed.

@ServerEndpoint("/websocket") 
public class WebSocketDemo   {
  @OnMessage
  public String onMessage(String message) {
  }

  @OnOpen
  public void onConnect(Session session) {
  }

  @OnClose
  public void myOnClose (CloseReason reason) {
  }
}
  • @ServerEndpoint gives the container instructions to handle this POJO as a websocket class, it also defines the endpoint path.
  • @OnMessage this method will be called when a message is received.
  • @OnOpen this method is called when the connection is started. A Session object is added as parameter.
  • @OnClose when the connection is lost or closed this method is called with the relevant CloseReason. The result of CloseReason.getCode() will a value of the CloseReason.CloseCodes enum.

The getCloseCode() can be used as in this very simple example. A normal closure is a direct disconnect from the client as any of the other closures is a timeout or something else (there are a lot of other codes, see the enum for all of them).

  @OnClose
  public void myOnClose (CloseReason reason) {
      if (reason.getCloseCode() == CloseReason.CloseCodes.NORMAL_CLOSURE) {
          System.out.println("normal closure");
      } else {
          System.out.println("other closure");
      }
  }

Javascript

The Javascript to connect to this endpoint looks something like this. Notice the ws:// protocol that is needed to indicate this is a websocket connection and not a “normal” HTTP connection.

var s = new WebSocket("ws://localhost:8080/websocket");

s.onopen = function(event) {
  console.log(event);
};
s.onerror = function(event) {
  console.log(event);
};

Keeping state

The websocket class is kept in memory for the complete lifetime of the class. So it is possible for example to store a variable and create a counter. The class will look like the following example with an integer counter that will be incremented on every message.
The method annotated with @OnOpen also receives a session object that contains some valuable information about the current session. This session instance will be kept alive until the connection is aborted.

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

@ServerEndpoint("/websocket") 
public class WebSocketDemo   {
  private int counter;

  @OnMessage
  public int onMessage(String message) {
     counter++;
     return counter;
  }

  @OnOpen
  public void onConnect(Session session) {
     counter = 0;
  }

  @OnClose
  public void myOnClose (CloseReason reason) {
  }
}

On every message that is received the counter will be increased by one and the new number is returned. When using the echo test on www.websocket.org this looks as follows:

websocket_echo_test

Further readings

For more information and other examples take a look at the following pages: