At the second JavaDay in Skopje in 2013, I talked about WebSockets and how to do them in Java. As a base for explaining, I’ve created a simple chat room application along with three different WebSocket implementations: JavaWebSocket, JavaEE7 and Spring4.

The application prompts for a username on start, shows all the present users in the room, provides basic chat functionality and does automatic log out when the browser tab/window is closed.

The slides of the presentation are available at SlideShare.

The talk is available (in Macedonian only) at Parleys.

The whole source code (explained in short below) is avalable at Github.

Client application

The client application is built with jQuery 1.10.2 and Bootstrap 3.0.3. For the first two examples, native WebSocket API is used for the communication.

At the start, a bootstrap modal dialog is shown for entering the desired nickname. When it’s confirmed, the whole application is being initialized, the communication procedure is started up, the events are bound and the jQuery assisted DOM manipulation is defined.

The JavaScript WebSocket API is quite simple and it involves just creating a web socket connection and binding the four communication events:

onOpen – when the connection has been successfully opened

onMessage – when a server sent message has been received

onClose – when the connection has been properly closed

onError – when a communication error has occured and the connection has been severed

The basic shape of a javascript WebSocket handler is:

var socket = new WebSocket(webSocketURL); socket.onopen = function() { //event handler when the connection has been established }; socket.onmessage = function(message) { //event handler when data has been received from the server }; socket.onclose = function() { //event handler when the socket has been properly closed } socket.onerror = function() { //event handler when an error has occurred during communication } //for sending data to the server socket.send(someTextData); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var socket = new WebSocket ( webSocketURL ) ; socket . onopen = function ( ) { //event handler when the connection has been established } ; socket . onmessage = function ( message ) { //event handler when data has been received from the server } ; socket . onclose = function ( ) { //event handler when the socket has been properly closed } socket . onerror = function ( ) { //event handler when an error has occurred during communication } //for sending data to the server socket . send ( someTextData ) ;

In the implementation, the messages that the client sends to the server are pure text. By convention, the first message sent is the username, while every next one is a message that the user is sending to everyone else.

For better manipulation, the messages that are being received from the server are placed in JSON objects. There are three types of messages that the server can send:

addUser message – a message that has only one field ‘addUser’ containing the username to be added to the list, i.e. a new user joins the chat

removeUser message – a message that has only one field ‘removeUser’ containing the username to be removed from the user list, i.e. a user closed the chat

message message – a message that has two fields: nickname and message, describing a sent chat message from the user ‘nickname’ and contents ‘message’

There is no logout option, since the tab/window closing automatically closes the WebSocket and the server gets this event.

JavaWebSocket implementation

One of the simplest ways to start-up a WebSocket server is by using a standalone implementation like the Java WebSocket (github link).

In order to use it, you need to create a standard Java7 application, which defines an extension of the WebSocketServer class, instantiates it and starts in the main routine (or anywhere applicable). The WebSocket server will run as a background thread as long as it is not explicitly stopped or the application is terminated.

The class that resembles the WebSocket server should pass a proper base constructor for the target IP and port, and override the four methods that are basically the event handlers in the WebSocket communication life cycle:

public class Main extends WebSocketServer { public Main() { super(new InetSocketAddress(8887)); } @Override public void onOpen(WebSocket conn, ClientHandshake handshake) { //Handle new connection here } @Override public void onMessage(WebSocket conn, String message) { //Handle client received message here //send a message back: conn.send(“A message”); } @Override public void onClose(WebSocket conn, int code, String reason, boolean remote) { //Handle closing connection here } @Override public void onError(WebSocket conn, Exception exc) { //Handle error during transport here } public static void main(String[] args) { Main server = new Main(); server.start(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class Main extends WebSocketServer { public Main ( ) { super ( new InetSocketAddress ( 8887 ) ) ; } @Override public void onOpen ( WebSocket conn , ClientHandshake handshake ) { //Handle new connection here } @Override public void onMessage ( WebSocket conn , String message ) { //Handle client received message here //send a message back: conn . send ( “ A message ” ) ; } @Override public void onClose ( WebSocket conn , int code , String reason , boolean remote ) { //Handle closing connection here } @Override public void onError ( WebSocket conn , Exception exc ) { //Handle error during transport here } public static void main ( String [ ] args ) { Main server = new Main ( ) ; server . start ( ) ; } }

Several notes here:

There is just one instance of the WebSocket server. It handles all the connections and the communication.

The WebSocket server implements the very same methods / event handlers as present in the client side: onOpen, onClose, onMessage and onError, having now, the onMessage is triggered when a message is received from some client.

For every opened websocket connection, there is a single WebSocket object instantiated. That object will remain the same and present until the connection is closed somehow. It can be referenced anywhere from the code and used as the WebSocket handler for that specific connection.

In my example, I store every WebSocket object in a set, and map them in a Map to their nickNames for future usage. When a connection is opened, the WebSocket instance is stored in the set, and when the nickname is passed, in the Map as well. When a message is received, the set is being iterated and the messages is sent to all active clients. In case if a connection closes or it’s being terminated by an error, the WebSocket instance is removed from the map and the set, and the ‘removeUser’ message is sent to all other clients.

For more details, see the JavaWebSocket sample in the source code. In order to run this sample, you need just a Java7 runtime. Start the server as a Java application and then open the chat.html file with your browser. (note: this is an Eclipse project)

JavaEE implementation

JSR 356 defines how the Java API should look like in the enterprise application servers in order to provide server side and Java client side WebSocket functionality. It is already implemented in the most popular application servers.

Apache Tomcat originally implemented JSR 356 and dropped its own WebSocket implementation in Tomcat 8. After a while though, the same functionality was back-ported to Tomcat 7.0.43. It’s usage again is bound by using Java 7.

There are two ways of how a WebSocket server can be defined in JavaEE7. As in many of the other Java APIs, there’s the annotation driven approach, which provides very simple means for creating basic server side constructions. There’s also the extension (interface based) approach by extending the base WebSocket classes and overriding the methods implementations.

A very basic annotation driven WebSocket implementation in Tomcat is comprised by using the following annotations:

– @ServerEndpoint(path) – for defining a class as a WebSocket endpoint at the specified relative path

– @OnOpen(Session), @OnClose(Session, CloseReason), @OnMessage(String), @OnError(Session, Throwable) – for defining the methods handlers for the four events in the WebSocket communication lifecycle.

Sending message back to the client is performed by getting a remote object from the session, and sending data through it. E.g.: session.getBasicRemote().sendText(text);

@ServerEndpoint(“/address”) public class EEWebSocketEndpoint { @OnOpen public void onOpen(Session session) { //Handle new connection here session.getBasicRemote() .sendText(“Connected!”); } @OnMessage public void onMessage(String message) { //Handle client received message here } @OnClose public void onClose(Session session, CloseReason reason) { //Handle closing connection here } @OnError public void onError(Session session, Throwable throwable) { //Handle error during transport here } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @ServerEndpoint ( “ / address ” ) public class EEWebSocketEndpoint { @OnOpen public void onOpen ( Session session ) { //Handle new connection here session . getBasicRemote ( ) . sendText ( “ Connected ! ” ) ; } @OnMessage public void onMessage ( String message ) { //Handle client received message here } @OnClose public void onClose ( Session session , CloseReason reason ) { //Handle closing connection here } @OnError public void onError ( Session session , Throwable throwable ) { //Handle error during transport here } }

The session object is unique and persistent for one client throughout it’s communication life-cycle. It can be stored and used in any other place your application.

On client side, everything is the same, except that now the port is 8080 (the same port at which Tomcat is configured to listen).

For more details, see the EESockets sample in the source code. In order to run the sample, you’ll need a Java7 Runtime along with a newer version of Tomcat 7 (> 7.0.43). It is again an eclipse project, so you may need to fine-tune the settings.

Spring 4 implementation

The freshly out Spring4 framework comes with it’s own and improved out of the box WebSockets implementation. It comprises of both well connected server and client side modules which provide native WebSocket communication and give a seamless fallback if no such option is possible.

In order to use the WebSockets implementation in spring, the context configuration needs to enable both SpringWebMVC and WebSocket, afterwards to define the beans for the WebSocketHandlers and register them. If the spring configuration is done by Java code, it should look something like this:

@Configuration @EnableWebMvc @EnableWebSocket public class WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(aWebSocketHandler(), “/address”).withSockJS(); } @Bean public WebSocketHandler aWebSocketHandler() { return new PerConnectionWebSocketHandler(AWebSocketHandler.class); } @Override public void configureDefaultServletHandling(DefaultServerHandlerConfigurer configurer) { configurer.enable(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Configuration @EnableWebMvc @EnableWebSocket public class WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { public void registerWebSocketHandlers ( WebSocketHandlerRegistry registry ) { registry . addHandler ( aWebSocketHandler ( ) , “ / address ” ) . withSockJS ( ) ; } @Bean public WebSocketHandler aWebSocketHandler ( ) { return new PerConnectionWebSocketHandler ( AWebSocketHandler . class ) ; } @Override public void configureDefaultServletHandling ( DefaultServerHandlerConfigurer configurer ) { configurer . enable ( ) ; } }

Several things are important here:

– A web socket server endpoint in Spring is a implementation of a kind from WebSocketHandler

– PerConnectionWebSocketHandler is an extensions which basically says that a new instance from the WebSocketHandler class will be created for each WebSocket client.

– .withSockJS() says that this endpoint should be enabled for, and expect calls from the SockJS client library.

The WebSocket server implementation is done by extending and overriding the WebSocketHandler class. There is a small hierarchy already present in Spring, so e.g.: if only textual data needs to be interchanged, then the implementation class should extend TextWebSocketHandler, since there the encoding/decoding stuff is already handled:

public class AWebSocketHandler extends TextWebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) { //Handle new connection here session.sendMessage(“Connected!”); } @Override public void handleTextMessage(WebSocketSession session, TextMessage message) { //Handle message.getPayload() here } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { //Handle closing connection here } @Override public void handleTransportError(WebSocketSession session, Throwable exception) { //Handle error during transport here } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class AWebSocketHandler extends TextWebSocketHandler { @Override public void afterConnectionEstablished ( WebSocketSession session ) { //Handle new connection here session . sendMessage ( “ Connected ! ” ) ; } @Override public void handleTextMessage ( WebSocketSession session , TextMessage message ) { //Handle message.getPayload() here } @Override public void afterConnectionClosed ( WebSocketSession session , CloseStatus status ) { //Handle closing connection here } @Override public void handleTransportError ( WebSocketSession session , Throwable exception ) { //Handle error during transport here } }

Again here, the same four methods are being overridden, and similar pattern is used for sending data back to the client. The WebSocketSession object is again unique and persistent, and can be saved and used throughout the application.

One crucial difference now is the JavaScript client side implementation. Since the WebSocketHandler is sockJS enabled, the same library can be used for interfacing with it. The difference is minimal: instead of instantiating a WebSocket, include the Sock.JS JavaScript client library, make a SockJS object and bind the same functions to it:

//I can now fallback to longpoll and do IE9!!! var socket = new SockJS(”http://” + document.domain + “:8080/springsockets/address”); socket.onopen = function() { //event handler when the connection has been established socket.send(nickname); }; socket.onmessage = function(message) { //event handler when data has been received from the server alert(message.data); }; socket.onclose = function() { //event handler when the socket has been properly closed } socket.onerror = function() { //event handler when an error has occurred during communication } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //I can now fallback to longpoll and do IE9!!! var socket = new SockJS ( ” http : //” + document.domain + “:8080/springsockets/address”); socket . onopen = function ( ) { //event handler when the connection has been established socket . send ( nickname ) ; } ; socket . onmessage = function ( message ) { //event handler when data has been received from the server alert ( message . data ) ; } ; socket . onclose = function ( ) { //event handler when the socket has been properly closed } socket . onerror = function ( ) { //event handler when an error has occurred during communication }

What happens now is, that SockJS will first check if a WebSocket communication can be established (by polling a info sub-path first). If successful, then it is resumed as such. If not, then a fallback option is applied (e.g.: http long polling) and the communication is abstracted on top of it. At the end, only one WebSocket like handler is needed for defining the whole communication. Like this, regardless of the client browser, only one code base is needed to handle all types of communication protocols.

Please note that now when passing the address, “http” and not “ws” is used. This is not an error, since SockJS will try to upgrade the connection afterwards.

For more details, see the springsockets sample in the source code. In order to run the sample, you’ll need a Java7 Runtime along with a newer version of Tomcat 7 (> 7.0.43). It is again an eclipse project, so you may need to fine-tune the settings. In the maven settings, the proper repositories are also added, so if you’re behind a local nexus mirror, please make sure that they will be accessible. Also, I’m using Spring 4.0.0.RC2 here. You can change it to the most recent Spring version.