Kotlin WebSocket Chat using SparkJava

Video Tutorial Showing the Creation of this Chat Application

I have been using Kotlin for a little while now, but in a small way. I have been flitting between Java, Scala and Kotlin for a few years, but with the announcement from Google of now officially supporting Kotlin for Android, I decided to jump back in again.
My typical use case when exploring new languages is a web application that I have been building on and off for a few years, which is essentially a Single Page App (JavaScript, usually Angular) on the front end, and a REST back end that doesn’t have to make me work too hard.
I have used a number of frameworks in the past, but for Scala I have always stayed pretty loyal to Play Framework. For Java, I have used SparkJava (or Play!), and for Kotlin, I went searching…Very quickly I decided that SparkJava was still a good solution to my use case.

My intention is to write a series of blogs on using SparkJava and Kotlin with associated other technologies to make a complete end to end solution.

To demo WebSockets, I am going to build a simple Chat application, using Kotlin, SparkJava and native browser WebSockets (no shims, frameworks etc). I am also going to only use JQuery, rather than a SPA framework like Angular, as not distract from the WebSockets.

All the code for this demo can be found on GitHub here → https://github.com/codemwnci/kotlinwschat

Setup

Assuming you already have Kotlin up and running (I have used IntelliJ), first we will create a POM file. If you are using intelliJ, then create a Maven project, and copy the following code.

The items to not on here is that we have included dependencies for SparkJava, Jackson (for JSON processing), and SLF4J (which is used by Spark to output logger info).

If you have set up the project as a Maven project, then you will have a standard maven directory structure. We will need to create two further directories.

  1. We need to create a directory called public inside of src\main\resources\
  2. We need to create a directory to put our package structure in. So, inside of src\main\java we need to put a package. I have chosen codemwnci.

If you have chosen the same approach as me, you will now have a directory structure like the following

Let’s Start Coding

I am not going to go into much detail on the normal REST approach to SparkJava. You can read that on their website, or you can watch the video at the top of this page if you are interested. Instead, we are going to jump straight into the configuration of SparkJava for WebSockets. So, let’s create a new Kotlin file, called ChatController.kt

Copy the following code

We don’t need much more at the moment. This code just imports a few things we will need now and later, and then starts a main function to configure SparkJava with the following attributes.

  1. Running on port 9000
  2. Pointing to the the publicdirectory that we set up in our resources directory
  3. Configuring the /chat URL to work websockets
  4. Starting up the SparkJava server

If we run this code now, it doesn’t do much other than starting the server. If we navigated to any URL on port 9000 we would get a 404 — Not Found error, as we have put no further routes in our code, nor put in any html files in our public directory.

So let’s fix that, and create our index.html file in the /resources/public directory.

This code starts off by including JQuery and Bootstrap, and then using Bootstrap to add a few DIVs to create two rows and two columns on each. The script then executes and carries out the following activities

  1. Opens a websocket connection to our /chat URL
  2. Creates a function that calls the receiveMsg function when a message is received from the server.
  3. Creates a function that handles a socket close (disconnect from the server), that outputs a simple alert.
  4. Creates a function that handles the socket open event. Here we ask the user to input their name, and then sends this to the server as a JSON message via the sendMessage function that is created in point 6.
  5. Next we create a click event (on send button click) and button press event (to capture an enter key). Both send a JSON message with the text that was entered in the text box.
  6. The sendMessage function sends a JSON object via the websocket to the server, and then clears the text box.
  7. Finally the receiveMessage function that handles websocket messages is created. This deals with a “say” request, by adding a new paragraph to the chat window. The “join” request adds a new list item to the list of users. The “users” request iterates through all the users in the array and adds them to the list of users. Finally, the “left” request removes a user from the list.

Now if we restart the server, we should see the chat window, but still won’t see anything happening because we haven’t completed our server-side code. So, let’s finish off that code.

First off, we create two data classes User and Message to represent the JSON objects that we send back to the HTML file that we have just completed.

Inside of the websocket handler, we start by creating some state for our chat application, with a list of users and their associated Sessions. The Sessions are the objects that keep hold of the TCP connection, and will be used later when communicating to the websockets.

We then create 3 annotation to deal with open, close and message events.

Open: we don’t really need this for our chat application, so we simply println that a user has connected.

Close: for this event, we simply remove the session from our list of users in the chat room and then broadcast the message that this user has left to all remaining users. Warning: Don’t forget the Nullable ? String reason of the disconnect function. If you miss this, the OnWebSocketClose function will not be triggered, but you won’t necessarily get an error message to explain why!

Message: for this event, we deal with two types of messages. A “say” event, or a “join” event. Here we make use of Kotlin’s great where . When a “say” event is received, we simply broadcast this to all users in the chat room. When a “join” event is received, we create a new User object (also getting and incrementing the ID), add the user to the list of users, send all the User objects to the client who just joined, and then sends a “join” message to all other sessions.

Finally, to finish off, we create the 3 functions that we have just used in the Close / Message functions to broadcast to all, send to one (emit), and send to all others (broadcastToOthers). These are all very similar functions, so we will explain each in turn.

emit: this is the basis for all our broadcast functions, and serves as a function to send a message to a single websocket Session. The code picks up the connection via the remote property, and then calls sendString, passing in a JSON string that has been converted via the JacksonObjectMapper.

broadcast: this function simply calls the forEach function on the HashMap of users, which gives us access to each websocket Session object. From this, the emit function (described above) is called for each one.

broadcastToOthers: this function is a slight variation on the broadcast function described previously. in that the forEach is only called once a filter is executed which excludes the passed in Session object, to ensure that only the other Sessions are sent the message.

And, that folks, is it. WebSockets, with no magic, and no trickery. Just Kotlin and SparkJava.

If you would like more in-depth explanations of anything, please leave a comment. If you like the YouTube video, I’d also appreciate it if you could subscribe to the channel. I hope you have found this interesting and informative!

Software Architect; Author of Introducing the Play Framework; Technologist.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store