1. Technical aspects of the WebSocket protocol
  2. WebSockets in a Java EE 7 application
  3. JSF 2.3 and WebSocket

As mentioned before, I divided part two into a couple of sub parts. Today I’ll finish with WebSockets in a Java EE 7.

If we want the user to choose a different chat room which is operated on the same endpoint, or if we want to show the user’s name, we need a way to pass this information to our endpoint.

One solution would be to provide information about the room by the endpoint URI. Let’s assume, the room is identified by a name, then the code might look like the following excerpt.

@ServerEndpoint("/simplechat/{room}")
public class SimpleChat {

@OnOpen
 public void onOpen(Session peer) {
 String class = peer.getRequestParameterMap().get("room").get(0);
 [...]
 }

[...]

}

This is quite the style Java EE supports by JAX-RS (Java API for RESTful Web Services): parts of the URI are variable and will be accessible by the request parameter map as shown in the onOpen method. Really easy, isn’t it?

The WebSocket connection is a channel between the client and the server. As an upgrade from HTTP the first request is initiated by the client. What happens, if the user fakes the URI and chooses a different classroom? And, we want to include the user within each message. Do you like somebody to spoof the user? Regardless the approach shown above is really simple, it might not fit our requirements in matters of security. And why should the client provide information, the server already knows?

With these thoughts in mind, we need to prefer a different approach. User and classroom are well known at server side, and thus they will be injected into the endpoint.

Let’s assume, we hold this information within a class called UserController:

public class UserController implements Serializable {

private Account _account;
 private FinalYear _finalYear;

[Getter/Setter and other fields omitted for brevity]
}

It seems to be easy to inject this user controller into our endpoint:

@Inject UserController _userController;

We simply replace

sendObject(message);

by

String namedMsg = _userController.GetAccount().getDisplayName() 
                  + ": " + message;sendObject(namedMsg);

The first message might be send correctly, but with the next message a null pointer exception occurs. Why?

The reason is quite simple: The endpoint will be created within that request when the user enters the classroom. The injected user controller contains all the values we expect. CDI does not really inject an instance of the class UserController, but a proxy pointing to the active user controller object of the current request. The WebSocket channels is opened by an upgrade from HTTP. The request terminates normally whilst the channel remains open. Now, if the user enters a message, it is send via the WebSocket channel, not by a new HTTP request. Since there is no HTTP request at that time, the CDI proxy cannot refer to any bean, albeit the user controller is of session scope. Thus the proxy resolves to `null`.

To tackle this challenge we use a constructor injection and store the injected object into an object attribute (field). By this, we “conserve” the original session controller.

Now we are able to use it as expected.

@ServerEndpoint("/simplechat")
public class SimpleChat {
  UserController _userController;
  public SimpleChat(UserController userController){
    _userController = userController;  }
 [...]}

Today’s article is a simplified version of the relevant chapter of my book. Next will be JSF 2.3 and WebSocket.

Stay tuned!