Socket to them!

Tutorial: Pushing browser updates using WebSockets in Glassfish

SteveMillidge
glassfish

Steve Millidge gives us a WebSocket taster using a combination of languages and a popular Java server.

Steve Millidge gives us a WebSocket taster using a
combination of languages and a popular Java server, in this
tutorial from February’s JAX Magazine.

WebSockets are new in HTML5 and provide the capability to
establish a full duplex connection between the web server and the
web browser. This means for the first time we can write
applications to push updates to the browser directly from the
server without having to use complex hacks like long polling, Comet
or third party plugins like Flash.

In this tutorial I’ll demonstrate pushing stock “updates” to a
browser over Websockets to asynchronously update a stock price
graph purely using the push capabilities inherent in Websockets.
I’ll also use GlassFish in this tutorial as this has out of the box
Websockets support in the latest production GlassFish 3.1.2.2 and
can therefore be built and deployed now. However WebSocket support
is not enabled out of the box. WebSocket support can be enabled via
the administration console, but the simplest way is to use an
asadmin command;

asadmin set
configs.config.server-config.network-config.protocols.protocol.http-listener-1.http.websockets-support-enabled=true

To keep things short, in this tutorial, our application will
just spawn a thread to create random updates to the Stock price.
However in a real application, it would be simple to hook our
application to a data feed via JMS or some other mechanism.

Side bar?

The Java API for Websockets is
being standardised in the JCP under JSR 356. Currently
application servers use a proprietary api to unlock Websockets
functionality and the GlassFish api here is specific to GlassFish.
Tomcat and other servers have a different API. If you are
interested in the proposed JEE7 Websockets API head over to
the JCP page to take a look.

Websocket is supported in GlassFish thanks to the Grizzly
library. The key classes in the Grizzly Websocket API we need are
shown in Figure 1.

Figure 1: Key classes in the
Grizzly Websocket API

StockSocket class

Working from the bottom up, first we must create
a derived class of the Grizzly WebSocket class. This class will
implement the protocol between the browser and GlassFish. As we’ll
see later one instance of this class is created for each client
browser. In our class, we will implement Runnable, spawn a Thread
and send updates to the browser. In this code (shown in
Listing 1), we will take advantage of the Grizzly
provided DefaultWebSocket class. This implements all the methods of
the WebSocket interface with no-ops, so we can just override the
methods we are interested in.

Listing 1

public class StockSocket extends DefaultWebSocket implements Runnable
{
        private Thread myThread;
        private boolean connected = false;
public StockSocket(ProtocolHandler protocolHandler, WebSocketListener... listeners) {
        super(protocolHandler, listeners);

 

In the onConnect method (which is called when a client browser
connects to the server) we need to create a new Thread and pass the
Websocket instance as the Runnable, as shown in Listing
2.

Listing 2: onConnect 

@Override     public void onConnect() {         myThread = new Thread(this);        connected = true;
  myThread.start();         super.onConnect();     }

 

In the run method (Listing 3), we will
periodically call our custom sendUpdate method using a random value
for a Stock. Our Stock class is a simple Serializable POJO DTO with
three attributes, name, description and price.

Listing 3: Run

public void run() {
while(connected) {
           Stock stock = new Stock("C2B2","C2B2",Math.random() * 100.0);
           int sleepTime = (int)(500*Math.random() + 500);               Thread.currentThread().sleep(sleepTime);
sendUpdate(stock);
  }
}

 

In the sendUpdate method (Listing 4), we
serialize the Stock object using the Jackson library into a JSON
string. We then send this to the browser over WebSockets by calling
the Grizzly base class’ send method which writes the JSON string
down to the browser.

Listing 4: sendUpdate

 public void sendUpdate(Stock stock) {
        // CONVERT to JSON
        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();
        try {
            mapper.writeValue(writer, stock);
        } catch (IOException ex) {
        }
        String jsonStr = writer.toString();
        // SEND down the Websocket 
        send(jsonStr);
    }

 

Finally in our onClose method (Listing 5) we
will notify the thread to stop by setting connected to false.

Listing 5: onClose

@Override
    public void onClose(DataFrame frame) {
        connected = false;
        super.onClose(frame);
    }
}

StockApplication class

To hook our derived StockSocket class into the GlassFish server,
we need to create a derived WebsocketApplication class, shown
below;

public class
StockApplication extends WebSocketApplication

{

In this class there are two methods we need to override. The
first is isApplicationRequest which is called by GlassFish when a
client browser connects to GlassFish over the Websocket protocol
(Listing 6). Our application needs to check the
request and decide whether it wants to accept the connection. In
this case, we will check whether the context path of the Websocket
request contains the string “/stocks”. If so we need to tell
GlassFish that the request is for us by returning true.

Listing 6:isApplicationRequest

  @Override
    public boolean isApplicationRequest(Request request)
    {
        if (request.requestURI().toString().endsWith("/stocks"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

 

The second method is createWebSocket (Listing
7
). Here, we need to create and return an instance of our
StockSocket class described above. The createWebSocket method is
called by GlassFish when a client browser connects to our
application and we have accepted the request.  

Listing 7: createWebSocket

  @Override
    public WebSocket createWebSocket(ProtocolHandler protocolHandler, WebSocketListener... listeners)
    {
        return new StockSocket(protocolHandler, listeners);
    }

StockServlet Class

The final class we need to write is a simple servlet. This
servlet only exists to ensure we register our derived
StockApplication class with Grizzly’s WebSocketEngine.

Listing 8:
StockServlet

@WebServlet(name = "StockServlet", urlPatterns =

{

"/stocks"

}, loadOnStartup = 1)

public class StockServlet extends HttpServlet {

private StockApplication pushApp;

 

We do this in the init method of our servlet and to ensure our
servlet is created on deployment, we must specify that an instance
should be created on startup, in the annotations as shown
above.

@Override

public void init(ServletConfig config)
throws ServletException {

super.init(config);

pushApp = new
StockApplication();

WebSocketEngine.getEngine().register(pushApp);

}

We also need to override the destroy method to ensure our
StockApplication is unregistered from the WebSocketEngine on
undeployment.

@Override

public void destroy()

{

super.destroy();

WebSocketEngine.getEngine().unregister(pushApp);

}

}

HTML5 & Javascript

Once we have written our Java servlet and the classes to use
Grizzly’s WebSocket API, we need to turn our mind to the HTML and
Javascript code. For our demonstration we are going to use a
Javascript library called Highcharts which is free for
non-commercial use. This Javascript library can render very sexy
Charts purely by using HTML5.

For our browser we will create a simple JSP page which uses the
Websocket Javascript API to connect to GlassFish over the Websocket
protocol and then receives our JSON stock updates which it feeds to
HighCharts to graph.

The first thing you need to do in the WebSockets Javascript API
is to connect to the GlassFish server, using the Websocket
protocol. To do this, we need to create a URL of the form
ws://<host>:<port>/<context> and pass this to the
constructor of the WebSocket class.

<script
type=”text/javascript”>

var wsUri = “ws://” + location.host +
“${pageContext.request.contextPath}/stocks”;

websocket = new
WebSocket(wsUri);

Once we have our Websocket object, we then must set up the call
back functions. These Javascript functions are called by the
browser when Websocket events occur, for example, when the socket
is opened (onOpen), closed (onClose) or there is an error
(onError). For simplicity, we will set these as empty
functions.

websocket.onopen
= function(event) { };

websocket.onclose
= function(event) { };

websocket.onerror
= function(event) { };

The most important callback is onmessage. This is triggered when
the browser receives data from the server over the Websocket, and
in our case will be called when we receive the JSON string
representing the stock object. So we will parse the JSON string and
create a new datapoint in HighCharts for this Stock price
update.

websocket.onmessage = function(event)
{

var object =
JSON.parse(event.data);

var x = (new
Date()).getTime();

var y = object.price;

document.chart.series[0].addPoint([x,y],true,true,false);

}

</script>

The initialisation of the HighCharts chart is
done in the head of the document, a snippet of which is shown
below.

Listing 9: HighCharts

 

<script type="text/javascript">
$(document).ready(function() {
        Highcharts.setOptions({
                global: {
                        useUTC: false
                }
        });
        var chart;
        document.chart = new Highcharts.Chart({
       …
});
</script>

 

The JSP page should be packaged up into a war file, with the
servlet and Java Grizzly code shown above and deployed to your
GlassFish server in the usual way.

Final View

Once the code is deployed successfully, you can navigate to it
using your usual browser and you should see an updating chart.

Figure 2: Updating
Chart 

Building push applications using the standard WebSocket
Javascript API and modern application servers like GlassFish is
very easy to do. Hopefully this tutorial has whetted your appetite
and inspired you to explore WebSockets in your applications.
 

Steve Millidge is the director and
founder of C2B2 Consulting Limited, he has used Java extensively
since pre1.0 and has been a field based professional service
consultant for over 10 years. Through C2B2 he now focuses on the
configuration of JEE and SOA infrastructure for maximum
Scalability, Performance, Availability, Recoverability,
Manageability and Security. Having worked for and on behalf of
Oracle, BEA and Red Hat professional services he has extensive
experience of deploying large scale production systems. Steve has
spoken at a number of events including Java One, Jax London, UK
Oracle User Group Conference, The Server SOA, Cloud & Service
Technology Symposium, JBoss World; he is the main organiser of the
London JBoss User Group and regularly presents brown bag technical
sessions for C2B2’s customer base. 

This article first appeared in JAX Magazine: Socket to
them!
in February 2013. Download that issue and others
here.
 

Image courtesy of cote

Author
SteveMillidge
Steve Millidge is the director and founder of C2B2 Consulting Limited, he has used Java extensively since pre1.0 and has been a field based professional service consultant for over 10 years. Through C2B2 he now focuses on the configuration of JEE and SOA infrastructure for maximum Scalability, Performance, Availability, Recoverability, Manageability and Security. Having worked for and on behalf of Oracle, BEA and Red Hat professional services he has extensive experience of deploying large scale production systems. Steve has spoken at a number of events including Java One, Jax London, UK Oracle User Group Conference, The Server SOA, Cloud & Service Technology Symposium, JBoss World; he is the main organiser of the London JBoss User Group and regularly presents brown bag technical sessions for C2B2's customer base.
Comments
comments powered by Disqus