Server-Sent Events using GlassFish (TOTD #179)
- by arungupta
Bhakti blogged
about Server-Sent Events on GlassFish and I've been planning to try
it out for past some days. Finally, I took some time out today to
learn about it and build a simplistic example showcasing the touch
points.
Server-Sent Events
is developed as part of HTML5 specification and provides push
notifications from a server to a browser client in the form of DOM
events. It is defined as a cross-browser JavaScript API called EventSource.
The client creates an EventSource by requesting a
particular URL and registers an onmessage event
listener to receive the event notifications. This can be done as
shown
var url = 'http://' + document.location.host + '/glassfish-sse/simple';eventSource = new EventSource(url);eventSource.onmessage = function (event) { var theParagraph = document.createElement('p'); theParagraph.innerHTML = event.data.toString(); document.body.appendChild(theParagraph);}
This code subscribes to a URL, receives the data in the event
listener, adds it to a HTML paragraph element, and displays it in
the document. This is where you'll parse JSON and other processing
to display if some other data format is received from the URL.
The URL to which the EventSource is subscribed to is
updated on the server side and there are multipe ways to do that.
GlassFish 4.0 provide support for Server-Sent Events and it can be
achieved registering a handler as shown below:
@ServerSentEvent("/simple")public class MySimpleHandler extends ServerSentEventHandler { public void sendMessage(String data) { try { connection.sendMessage(data); } catch (IOException ex) { . . . } }}
And then events can be sent to this handler using a singleton
session bean as shown:
@Startup@Statelesspublic class SimpleEvent { @Inject @ServerSentEventContext("/simple") ServerSentEventHandlerContext<MySimpleHandler> simpleHandlers; @Schedule(hour="*", minute="*", second="*/10") public void sendDate() { for(MySimpleHandler handler : simpleHandlers.getHandlers()) { handler.sendMessage(new Date().toString()); } }}
This stateless session bean injects ServerSentEventHandlers
listening on "/simple" path. Note, there may be multiple handlers
listening on this path. The sendDate method triggers every 10
seconds and send the current timestamp to all the handlers. The
client side browser simply displays the string.
The HTTP request headers look like:
Accept: text/event-streamAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3Accept-Encoding: gzip,deflate,sdchAccept-Language: en-US,en;q=0.8Cache-Control: no-cacheConnection: keep-aliveCookie: JSESSIONID=97ff28773ea6a085e11131acf47bHost: localhost:8080Referer: http://localhost:8080/glassfish-sse/faces/index2.xhtmlUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5
And the response headers as:
Content-Type: text/event-streamDate: Thu, 14 Jun 2012 21:16:10 GMTServer: GlassFish Server Open Source Edition 4.0Transfer-Encoding: chunkedX-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 4.0 Java/Apple Inc./1.6)
Notice, the MIME type of the messages from server to the client is text/event-stream
and that is defined by the specification.
The code in Bhakti's
blog can be further simplified by using the
recently-introduced Twitter
API
for Java as shown below:
@Schedule(hour="*", minute="*", second="*/10") public void sendTweets() { for(MyTwitterHandler handler : twitterHandler.getHandlers()) { String result = twitter.search("glassfish", String.class); handler.sendMessage(result); }}
The complete source explained in this blog can be downloaded
here and tried on GlassFish
4.0
build 34. The latest promoted build can be downloaded from
here and the complete source code for the API and
implementation is here.
I tried this sample on Chrome Version 19.0.1084.54 on Mac OS X 10.7.3.