Click here to Skip to main content
15,124,353 members
Articles / Programming Languages / Java
Posted 25 Jan 2016

Tagged as


17 bookmarked

A Single Room Chat Program with Websocket

Rate me:
Please Sign up or sign in to vote.
4.97/5 (13 votes)
25 Jan 2016CPOL5 min read
This is an example to use Websocket to create a simple chat program.


This is an example to use Websocket to create a simple chat program.


This is an example to use Websocket to create a simple chat program. In order to give enough focus on Websocket, the example is kept as simple as possible to support only a single chat room. Since this is a simple chat room, a user does not need a password to log into the room. Although the back-end is created by Java on a Tomcat server, it should have some reference value to the people who use other platforms such as .Net or Node.js.

The attached is a Maven web project. I have tested it with Java 1.8.0_65 and Tomcat 7.0.54. I used Eclipse Java EE IDE for Web Developers Mars.1 Release (4.5.1) as my development IDE. I also deployed it on an Amazon EC2 Ubuntu instance and tested it with Chrome, Firefox, and a couple of mobile devices.

The Server Environment Setup

No special environment setup is needed in order to use Websocket on Tomcat 7 and above. At least there is no need on Tomcat 7.0.54. There is no special configuration for the Websocket in the "web.xml" file either. The following is the "pom.xml" file in the attached Maven project.

<project xmlns=""
        <!-- Dependency needed by the Web-socket -->
        <!-- Tomcat has it, so no need to package into the war file -->
        <!-- Used to serialize the message from the browser -->
        <!-- Sevlet jars for compilation, provided by Tomcat -->


  • The "javax.websocket-api" dependency is only needed to compile the code. Since Tomcat 7 and above have the Websocket support by default, we do not need to package this dependency into the war file;
  • The "jackson-databind" dependency is used to serialize/de-serialize the messages from the web browsers. If you do not need the serialization or you want to use other serialization methods, you do not need to add it as a dependency.

The Message Between the Server and the Clients

For the simple chat room, the message is also simple. It has only a message type and a message content, which is implemented in the "" file.


public class ChatMessage {
    private MessageType messageType;
    private String message;

    public void setMessageType(MessageType v) { this.messageType = v; }
    public MessageType getMessageType() { return messageType; }
    public void setMessage(String v) { this.message = v; }
    public String getMessage() { return this.message; }

The "MessageType" is implemented as an "enum" in the "" file.


public enum MessageType { LOGIN, MESSAGE }

We have only two message types in this example. One is used for the requests to log into the chat room, the other is used to send messages to be broadcasted in the room.

The Server End Point

In order for the browsers to communicate with the server through Websocket, we need to create a class annotated by "@ServerEndpoint".


import java.util.Map;
import java.util.logging.Logger;

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

import com.fasterxml.jackson.databind.ObjectMapper;

@ServerEndpoint(value = "/chat")
public class ChatEndpoint {
    private Logger log = Logger.getLogger(ChatEndpoint.class.getSimpleName());
    private Room room = Room.getRoom();

    public void open(final Session session, EndpointConfig config) {}

    public void onMessage(final Session session, final String messageJson) {
        ObjectMapper mapper = new ObjectMapper();
        ChatMessage chatMessage = null;
        try {
            chatMessage = mapper.readValue(messageJson, ChatMessage.class);
        } catch (IOException e) {
            String message = "Badly formatted message";
            try {
                session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, message));
            } catch (IOException ex) { log.severe(ex.getMessage()); }
        } ;

        Map<String, Object> properties = session.getUserProperties();
        if (chatMessage.getMessageType() == MessageType.LOGIN) {
            String name = chatMessage.getMessage();
            properties.put("name", name);
            room.sendMessage(name + " - Joined the chat room");
        else {
            String name = (String)properties.get("name");
            room.sendMessage(name + " - " + chatMessage.getMessage());

    public void onClose(Session session, CloseReason reason) {
        room.sendMessage((String)session.getUserProperties().get("name") + " - Left the room");

    public void onError(Session session, Throwable ex) {"Error: " + ex.getMessage()); }
  • The "@ServerEndpoint" annotation indicates that the "ChatEndpoint" is a Websocket end point. The url to access this end point should be "ws://server-address:port-number/single-room-chat/chat";
  • The "@OnOpen" annotation indicates that the "onOpen" method will be called when a new Websocket connection is requested;
  • The "@OnMessage" annotation indicates that the "onMessage" method will be called when a new message arrives. The message can be a request for login or a message to broadcast a message to the room;
  • The "@OnClose" annotation indicates that the "onClose" method will be called when a client closes the Websocket connection. This method will be called even when the closing of the connection is not voluntary, which can be closures due to the lost of the internet connection or an error condition;
  • The "@OnError" annotation indicates that the "onError" method will be called when an error occurs

The "ChatEndpoint" class is not a singleton in the Tomcat environment. It has a session scope, which is instantiated for every Websocket connection session from the client. Once a connection is established, the session instance will be used for all the messages until the connection session is closed. The "" implements the chat room, which handles broadcasting the messages to all the active Websocket connections.


import java.util.ArrayList;
import java.util.List;

import javax.websocket.Session;

public class Room {
    private static Room instance = null;
    private List<Session> sessions = new ArrayList<Session>();

    public synchronized void join(Session session) { sessions.add(session); }
    public synchronized void leave(Session session) { sessions.remove(session); }
    public synchronized void sendMessage(String message) {
        for (Session session: sessions) {
            if (session.isOpen()) {
                try { session.getBasicRemote().sendText(message); }
                catch (IOException e) { e.printStackTrace(); }

    public synchronized static Room getRoom() {
        if (instance == null) { instance = new Room(); }
        return instance;
  • Since the application is a single chat room, the "Room" class is a singleton;
  • Since there will be many users in the room, all the methods are synchronized to avoid conflicts and race conditions.

The Client Side

The client side html layout is implemented in the "index.jsp" file.

<div id="container">
    <div id="loginPanel">
        <div id="infoLabel">Type a name to join the room</div>
        <div style="padding: 10px;">
            <input id="txtLogin" type="text" class="loginInput"
                onkeyup="proxy.login_keyup(event)" />
            <button type="button" class="loginInput" onclick="proxy.login()">Login</button>
    <div id="msgPanel" style="display: none">
        <div id="msgContainer" style="overflow: auto;"></div>
        <div id="msgController">
            <textarea id="txtMsg" 
                title="Enter to send message"
                style="height: 20px; width: 100%"></textarea>
            <button style="height: 30px; width: 100px" type="button"

The Javscript to create the Websocket and communicate to the server is implemented in the "chatroom.js" file.

var CreateProxy = function(wsUri) {
    var websocket = null;
    var audio = null;
    var elements = null;
    var playSound = function() {
        if (audio == null) {
            audio = new Audio('content/sounds/beep.wav');
    var showMsgPanel = function() {
   = "none";
   = "block";
    var hideMsgPanel = function() {
   = "block";
   = "none";
    var displayMessage = function(msg) {
        if (elements.msgContainer.childNodes.length == 100) {
        var div = document.createElement('div');
        div.className = 'msgrow';
        var textnode = document.createTextNode(msg);
        elements.msgContainer.scrollTop = elements.msgContainer.scrollHeight;
    var clearMessage = function() {
        elements.msgContainer.innerHTML = '';
    return {
        login: function() {
            var name = elements.txtLogin.value.trim();
            if (name == '') { return; }
            elements.txtLogin.value = '';
            // Initiate the socket and set up the events
            if (websocket == null) {
                websocket = new WebSocket(wsUri);
                websocket.onopen = function() {
                    var message = { messageType: 'LOGIN', message: name };
                websocket.onmessage = function(e) {
                websocket.onerror = function(e) {};
                websocket.onclose = function(e) {
                    websocket = null;
        sendMessage: function() {
            if (websocket != null && websocket.readyState == 1) {
                var input = elements.txtMsg.value.trim();
                if (input == '') { return; }
                elements.txtMsg.value = '';
                var message = { messageType: 'MESSAGE', message: input };
                // Send a message through the web-socket
        login_keyup: function(e) { if (e.keyCode == 13) { this.login(); } },
        sendMessage_keyup: function(e) { if (e.keyCode == 13) { this.sendMessage(); } },
        logout: function() {
            if (websocket != null && websocket.readyState == 1) { websocket.close();}
        initiate: function(e) {
            elements = e;

The "CreateProxy" function is used in the "DOMContentLoaded" event in the "index.jsp" file.

var proxy = CreateProxy(wsUri);

document.addEventListener("DOMContentLoaded", function(event) {
        loginPanel: document.getElementById('loginPanel'),
        msgPanel: document.getElementById('msgPanel'),
        txtMsg: document.getElementById('txtMsg'),
        txtLogin: document.getElementById('txtLogin'),
        msgContainer: document.getElementById('msgContainer')

You may want to pay a little attention to the "login" function in the "chatroom.js" file. It is the place where the Websocket is created at the client side. You should also notice that it also sets up the "onopen", "onmessage", "onclose", and "onerror" events that are similar to the server side end-point. In my experience, the "onerror" method may not always reliably fire, but the "onclose" event always fires, even though the closure is due to the lost of the internet connection or shutting down the web server.

Run the Application

The attached is a Maven project. You can build it through "mvn clean install" and deploy the war file to a Tomcat server to run it. You can also import it into Eclipse to run it. If you are not sure how to import a Maven project into Eclipse, you can take a look at this link. When the application starts, you can see the login page that asks you to type in any user name to log into the chat room.

After logging into the room, you can then send and receive messages. You can try to open the web page in more than one browser windows to see if the messages are reliably broadcasted in the room.

Points of Interest

  • This is an example to use Websocket to create a simple chat program;
  • It is a little rudimentary, but it is simple enough so the focus is on Websoket;
  • Whenever we talk about socket, we will need to take a good look into its reliability because of the internet is inherently not reliable. I have deployed this example on an Amazon EC2 Ubuntu instance and tested it with a few mobile devices while I went for shopping through the mobile internet connections;
  • Although this example is on Tomcat, it should have some reference value if your platform is .Net or Node.js;
  • I hope you like my postings and I hope this example can help you one way or the other.


First Revision - 1/25/2016


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Dr. Song Li
United States United States
I have been working in the IT industry for some time. It is still exciting and I am still learning. I am a happy and honest person, and I want to be your friend.

Comments and Discussions

Questiongetting error Pin
Member 1492264625-Aug-20 8:40
MemberMember 1492264625-Aug-20 8:40 
GeneralGeneral Pin
Member 148569258-Jun-20 22:35
MemberMember 148569258-Jun-20 22:35 
Questionhow to login to the app? Please reply me as soon as possible. Pin
Member 1377385911-Apr-18 2:29
MemberMember 1377385911-Apr-18 2:29 
QuestionCan't log in? Pin
Max Sun22-Jan-18 1:33
MemberMax Sun22-Jan-18 1:33 
AnswerRe: Can't log in? Pin
esa tahtinen11-Mar-18 12:11
Memberesa tahtinen11-Mar-18 12:11 
GeneralMy vote of 5 Pin
DrABELL25-Nov-17 10:52
professionalDrABELL25-Nov-17 10:52 
Excellent article in both practical/didactic aspects. Thanks for sharing and 5*
GeneralWell Explained,Thanks. Pin
Member 1299706615-Feb-17 18:46
MemberMember 1299706615-Feb-17 18:46 
QuestionMy vote of 5 Pin
Farhad Reza24-Oct-16 7:22
MemberFarhad Reza24-Oct-16 7:22 
Questionrecording to code Pin
Member 126771149-Aug-16 1:24
MemberMember 126771149-Aug-16 1:24 
GeneralMy vote of 5 Pin
Prasad Khandekar26-Jan-16 22:31
professionalPrasad Khandekar26-Jan-16 22:31 
GeneralMy vote of 5 Pin
raddevus25-Jan-16 15:45
mvaraddevus25-Jan-16 15:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.