Java EE HTML5 WebSockets with multiple clients example

22 August 2013
By Gonçalo Marques
In this tutorial we will implement a message broadcast sample application using only HTML5 websockets. The server-side will be implemented with Java EE ServerEndpoint.

Introduction

In the previous tutorial - Java EE HTML5 WebSocket example - we have implemented a simple Java EE WebSockets enabled application where the client sent a simple message to the server over a websocket and then received a sequence of responses from the server over the same channel.

In this tutorial we will implement an application where clients will interactively send messages to each other through the server. This way we will have an application where clients are in fact publishing and receiving events to/from the server over HTML5 websockets.

This tutorial considers the following environment:

  1. Ubuntu 12.04
  2. JDK 1.7.0.21
  3. Glassfish 4.0

Note: WebSockets support was introduced in Java EE 7

WebSocket server endpoint

Let's define a Java EE websocket server endpoint:

WebSocketTest.java

package com.byteslounge.websockets;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

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 WebSocketTest {

  private static Set<Session> clients = 
    Collections.synchronizedSet(new HashSet<Session>());
  
  @OnMessage
  public void onMessage(String message, Session session) 
    throws IOException {
    
    synchronized(clients){
      // Iterate over the connected sessions
      // and broadcast the received message
      for(Session client : clients){
        if (!client.equals(session)){
          client.getBasicRemote().sendText(message);
        }
      }
    }
    
  }
  
  @OnOpen
  public void onOpen (Session session) {
  // Add session to the connected sessions set
    clients.add(session);
  }

  @OnClose
  public void onClose (Session session) {
    // Remove session from the connected sessions set
    clients.remove(session);
  }

}

Similarly to what we have done in the previous tutorial - Java EE HTML5 WebSocket example - we are defining a ServerEndpoint that will be - as the name states - the server endpoint listening from client websocket connections.

We have a static Map that will hold all connected client sessions. This way we may broadcast received messages to other clients (method onMessage). Note that when we receive a message we broadcast it to all connected clients except the one who originated the message in the first place.

Methods onOpen and onClose are called when a client connects or disconnects from the server endpoint respectively. So we add or remove them from the sessions Map accordingly.

Note that when the parameter of type Session is included in the annotated ServerEndpoint methods the container will inject the session that corresponds to the client which originated the event.

Client side

Now we need to write the client-side of our websocket test application:

page.html

<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
  <div>
    <input id="inputmessage" type="text" />
  </div>
  <div>
    <input type="submit" value="Broadcast message" onclick="send()" />
  </div>
  <div id="messages"></div>
  <script type="text/javascript">
    var webSocket = 
      new WebSocket('ws://localhost:8080/byteslounge/websocket');

    webSocket.onerror = function(event) {
      onError(event)
    };

    webSocket.onopen = function(event) {
      onOpen(event)
    };

    webSocket.onmessage = function(event) {
      onMessage(event)
    };

    function onMessage(event) {
      document.getElementById('messages').innerHTML 
        += '<br />Received message: ' + event.data;
    }

    function onOpen(event) {
      document.getElementById('messages').innerHTML 
        = 'Connection established';
    }

    function onError(event) {
      alert(event.data);
    }

    function send() {
      var txt = document.getElementById('inputmessage').value;
      webSocket.send(txt);
      return false;
    }
  </script>
</body>
</html>

This page contains a simple input text where a user may write a message and a button to publish the message to the server over the established websocket channel.

Every time we receive a message from the server we write it into the page.

For more information about the websocket connection definition and the respective events please refer to Java EE HTML5 WebSocket example.

Testing

We may now test our application by accessing the testing page from two distinct web browser instances:

http://localhost:8080/byteslounge/page.html

We will see the Connection established message as expected:

http://localhost:8080/byteslounge/page.html - browser 1
Websocket - Established connection


http://localhost:8080/byteslounge/page.html - browser 2
Websocket - Established connection 2nd browser

Now we write a simple message (ex: "hello") in one of the clients and click the "Broadcast message" button:

Broadcast message
Websocket - Broadcast message

The other connected client will receive the published message. Note that the message will be published to every connected client except the one who published the message in the first place (as we defined in the server endpoint):

Receiving message
Websocket - Receive message

Conclusion

We have developed a sample application where clients use websockets in full extent to communicate with a Java EE application server, ie. publishing and receiving events.

In our case the received events are sent by other clients. One can easily use a similar approach to enable periodic message sending from server to clients in order to notify them of some arbitrary event occurrence.

Downloadable sample

The example source code is available for download at the end of this page. The test was executed in Glassfish 4 (you will need a Java EE 7 compliant application server).

Download source code from this article

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: https://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: