Java Websocket API With Custom Decoder

Java JEE7 now support Websocket with realtime bidirection communication from server to clients. The websocket API provide extendsible API to build custom decoder to decode message from client.

In this post, you will learn how to use java websocket API to build custom decoder.

Java WebSocket Maven Dependencies

I use maven to manage dependencies, the following pom.xml show the dependencies that I used:

<dependencies>
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-web-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
    </dependency>

    <!-- optional -->
    <dependency>
      <groupId>org.glassfish</groupId>
      <artifactId>javax.json</artifactId>
      <version>1.0</version>
      <scope>runtime</scope>
    </dependency>

</dependencies>

The example is using the coordinate of the mouse clicks and will send as JSON to server, the POJO class:

public class Coordinate {

    private int x;
    private int y;

    public void setX(int x) {
        this.x = x;
    }

    public int getX() {
        return x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getY() {
        return y;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Coordinate{");
        sb.append("x=").append(x);
        sb.append(", y=").append(y);
        sb.append('}');
        return sb.toString();
    }
}

Decoders to Convert WebSocket Messages into Java Objects

To implement decoder, the following interface should be used:

  • Decoder.Text<T> for text messages
  • Decoder.Binary<T> for binary messages

Here is the example convert JSON string to Coordinate object:

import javax.json.Json;
import javax.json.JsonObject;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import java.io.StringReader;

public class CoordinateDecoder implements Decoder.Text<Coordinate> {

    /**
     * convert {"x":x, "y": y} to Coordinate POJO
     */
    @Override
    public Coordinate decode(String s) throws DecodeException {
        JsonObject json = Json.createReader(new StringReader(s)).readObject();
        Coordinate coordinate = new Coordinate();
        coordinate.setX(json.getInt("x"));
        coordinate.setY(json.getInt("y"));
        return coordinate;
    }

    /**
     *  whether the given String can be decoded into an object of type T
     */
    @Override
    public boolean willDecode(String s) {
        return true;
    }

    @Override
    public void init(EndpointConfig endpointConfig) {

    }

    @Override
    public void destroy() {

    }
}

After implemented custom decoder, now is time to implement the websocket server side endpoint:

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

@ServerEndpoint(value = "/ws", decoders = {CoordinateDecoder.class})
public class WebsocketDecoderExampleServer {

    private static final Logger LOGGER = Logger.getLogger(WebsocketDecoderExampleServer.class.getName());


    @OnOpen
    public void onOpen(Session session) {
        LOGGER.log(Level.INFO, "New connection with client: {0}",
                session.getId());
    }

    @OnMessage
    public String onMessage(Coordinate coordinate, Session session) throws IOException, EncodeException {
        LOGGER.log(Level.INFO, "New message from Client [{0}]: {1}",
                new Object[] {session.getId(), coordinate});
        return "Server received [" + coordinate + "]";
    }

    @OnClose
    public void onClose(Session session) {
        LOGGER.log(Level.INFO, "Close connection for client: {0}",
                session.getId());
    }

    @OnError
    public void onError(Throwable exception, Session session) {
        LOGGER.log(Level.INFO, "Error for client: {0}", session.getId());
    }

}

The following code is for client side:

<html>
<head>
  <title></title>
  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css"/>
  <style type="text/css">
    .canvas {
      width: 500px;
      height: 500px;
      border: 2px solid #ADFFA6;
    }
    .server {
      border-top: 1px solid #a2a2a2;
      border-left: 1px solid #a2a2a2;
      border-right: 1px solid #a2a2a2;
      border-bottom: 1px solid  #FFA6A6;
      padding: 5px;
    }

    #output {
      height: 500px;
      overflow-y: scroll;
    }
  </style
</head>
<body
<div class="container"
  <div class="row">
    <div class="col-lg-6">
      <div class="canvas"></div>
    </div>
    <div class="col-lg-6">
      <div id="output"></div>
    </div>
  </div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
  $(function() {
    var chatClient = new WebSocket("ws://localhost:8080/ws");

    chatClient.onmessage = function(e) {
      var p = document.createElement("p");
      p.setAttribute("class", "server");
      p.innerHTML = "Server: " + e.data;
      var container = document.getElementById("output");
      container.insertBefore(p, container.firstChild);
    }

    $(".canvas").click(function(e) {
      var posX = $(this).position().left,
          posY = $(this).position().top;
      var coordinate = {
        x: (e.pageX - posX),
        y:(e.pageY - posY)
      };
      chatClient.send(JSON.stringify(coordinate));
    });
  });
</script>
</body>
</html>

Running Java Websocket App with Custom Decoder

When run the app and browse to localhost, click on the green area. Here are the screenshots for example app:

Initial load page

Server reply message

Console logs:

Oct 27, 2013 10:44:56 AM WebsocketDecoderExampleServer onOpen
INFO: New connection with client: websocket-1
Oct 27, 2013 10:47:08 AM WebsocketDecoderExampleServer onMessage
INFO: New message from Client [websocket-1]: Coordinate{x=111, y=13}
Oct 27, 2013 10:47:12 AM WebsocketDecoderExampleServer onMessage
INFO: New message from Client [websocket-1]: Coordinate{x=315, y=19}
Oct 27, 2013 10:47:13 AM WebsocketDecoderExampleServer onMessage
INFO: New message from Client [websocket-1]: Coordinate{x=552, y=21}

Filed under java

Search

Find Me