Introduction
We are going to look at the new HTML5 eventSource capability. Adapting the articles (posted here) and (posted here) I am goign to show you how to send data from the server to your XPage without using ajax to initiate the communication. I have the feeling there is a lot to learn in this area and we are just scratching the surface.
Browser Support
Yep – it is HTML5 which means no IE right now – Chrome should support this but my copy does not – so right now this demonstration is only tested and working in the latest version of FireFox.
Demonstration
The results of this article are demonstrated here, and I strongly suggest you use some kind of plugin to watch the traffic as the values chance – quite fascinating. Right click – View Source and see for yourself – no ajax! no jQuery, nothing fancy, just HTML5 in action!
http://demo.xomino.com/xomino/xPlay.nsf/xHTML5ServerSent.xsp
Server output
I have modified Stephan Wissel’s xAgent XSnippet to create a simple data stream using server-side output. Calling this xAgent through the web generated the following simple data output as seen here through Firefox HTTPFox plugin.
The thing to highlight is the Content-Type text/event-stream

<?xml version="1.0" encoding="UTF-8"?> <!-- XPage which is not rendered but returns data like XML, JSON, etc. --> <!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn --> <xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false"> <xp:this.afterRenderResponse> <![CDATA[#{javascript: var externalContext = facesContext.getExternalContext(); var writer = facesContext.getResponseWriter(); var response = externalContext.getResponse(); // set content type, e.g. ... response.setContentType("text/event-stream"); response.setHeader("Cache-Control", "no-cache"); // read parameters, e.g. ... var param = context.getUrlParameter("myParam"); // write HTML output e.g. ... writer.write("data: the number is "+@Random()); writer.endDocument(); }]]> </xp:this.afterRenderResponse> </xp:view>
HTML5 JavaScript
In our xPage we create some JavaScript to instantiate and then listen to the eventSource
First of all we test to see if the EventSource is supported in this browser
if(typeof(EventSource)!=="undefined") { else { dojo.byId("#{id:serverData}").innerHTML="Whoops! Your browser doesn't receive server-sent events."; }]]>
Using the following code we subscribe to the EventSource (xSendHTML5Data_1.xsp is the xPage described above)
var eSource = new EventSource("xSendHTML5Data_1.xsp");
And then when we receive a message from the server we act on it
eSource.onmessage = function(event) { //write the received data to the page dojo.byId("#{id:serverData}").innerHTML = event.data; };
This all comes together as the following ScriptBlock in the page
<xp:scriptBlock id="scriptBlock1"> <xp:this.value><![CDATA[//check for browser support if(typeof(EventSource)!=="undefined") { //create an object, passing it the name and location of the server side script var eSource = new EventSource("xSendHTML5Data_1.xsp"); //detect message receipt eSource.onmessage = function(event) { //write the received data to the page dojo.byId("#{id:serverData}").innerHTML = event.data; }; } else { dojo.byId("#{id:serverData}").innerHTML="Whoops! Your browser doesn't receive server-sent events."; }]]> </xp:this.value> </xp:scriptBlock>
Stopping the source
We are able to stop the source using eSource.close() that will stop the data being sent. I added mine in a button
<xp:button id="button1" value="Stop the Source"> <xp:eventHandler event="onclick" submit="false"> <xp:this.script><![CDATA[eSource.close()]]></xp:this.script> </xp:eventHandler></xp:button>
Changing the refresh time
We are able to change the refresh time by returning the retry value in millisecond along with our data
writer.write("retry: 2000\ndata: the number is "+@Random());

Specifying an event name
This mercilessly ripped directly from the article – I have not done anything with the event listeners yet, but here the next thing I want to look at….using the data returned from the server to trigger events in the browser without having to parse the return string and take action on it – that’s a huge performance gain and distributes the tasks….more to come on that in the near future….
For example, the following server output sends three types of events, a generic ‘message’ event, ‘userlogon’, and ‘update’ event:
data: {"msg": "First message"}\n\n event: userlogon\n data: {"username": "John123"}\n\n event: update\n data: {"username": "John123", "emotion": "happy"}\n\n With event listeners setup on the client: source.addEventListener('message', function(e) { var data = JSON.parse(e.data); console.log(data.msg); }, false); source.addEventListener('userlogon', function(e) { var data = JSON.parse(e.data); console.log('User login:' + data.username); }, false); source.addEventListener('update', function(e) { var data = JSON.parse(e.data); console.log(data.username + ' is now ' + data.emotion); }, false);
Enjoy 🙂
Demonstration
http://demo.xomino.com/xomino/xPlay.nsf/xHTML5ServerSent.xsp
Interesting but, as far as I know, current domino http / java server side stack is not tailored to scale with such technologie (same for websocket). It works but it can not scale. As far as I know, we need some special server side stuff (Node.js, Jetty etc…) to really take advantage of those new web requests models
That is a very good point – but then we are talking Domino Servers here – and scalability has never been the driving factor. It is good though to start the conversation early so that if necessary IBM keep an open mind to it in the future
This post leaves me with the feeling I first had when I realized (or had explained to me) what xmlhttprequest could do. What other strange and wonderful creatures are going to come out of the HTML5 woodwork over the next years as developers like you push its capabilities? By the way, you’ve got a really great blog and I’ll be following it. Nice to meet you Wed. at the DCLUG.
Thanks for the support Harris 🙂 – good to meet you too. I plan to be more involved in DCLUG than I was in the past.
As far as HTML5 goes, it has been around for 2 years now but there really hasn’t been the browser support for it. It is so much fun to get inside it and play – so much to learn and so little time to do it 🙂
To get this working in Chrome you need to end every line in which you send the data with two ‘\n’ characters:
writer.write(“data: the number is “+@Random() + “\n\n”);
thanks Mark !! added to the example and now it works in Chrome – genius!
How do you update the stream from the server ?
For example, my user A save a new document on my database A
In my database A exist the “xSendHTML5Data_1.xsp”.
How do you do so that the Xpage (“xSendHTML5Data_1.xsp”) make the calculation about if there is a change -aka a new document-?
so that it can change the message and send the update over the stream to the browser (a mobile device in reality).
-The Xpage will have to be asking to the server ALL the time if there is a change ?
-Server will be loaded with the extra work of checking if there is a change all the time ?
-Is it usable in production conditions ?
I mean in my case the server handle many NSF and I do not want that 10 users overload the http task with infinite loop of checking
Thanks for sharing
Thanks for the comment Dominique 🙂
Having had multiple discussions with people since I wrote the article I think it is something to be consigned to the “interesting but not helpful bin”. You are right there is nothing in the domino stack to know that there is a change and send it without constant polling.
We have been actively pushing the DDE development team to add websockets to the product and I think/hope they are starting to listen. Once we have that then we go from interesting to practical.
In the mean time here is an interesting stackoverflow comparison between the two
http://stackoverflow.com/questions/5195452/websockets-vs-server-sent-events-eventsource
I am about to check if we can use one variable with application scope level from the xpages.
So the xpage who sent the data will check that.
And the workflow will rely on on the variable and a sleep function
state 1: global variable – no update – the xpage does not send data
state 2: the user trought agent change the value of the global variable – send data
the xpage send data
then an agent with a sleep function, change the global variable to “no update” after 10 to 30 seconds (value to test).