Quantcast
Channel: Learning the code way
Viewing all articles
Browse latest Browse all 231

Server-Sent Events - How to do it in Sevlets ?

$
0
0
In the past few posts I have seen some techniques to pull of Push Notifications. HTML5 has introduced a couple of new methods - one of them is Server -Sent Events. In this post I am trying to build one such Servlet based implementation.
One of the prime points to note is that I do not need Servlet 3.x to pull this off. I can do with old style Servlet. What I do need is an HTML5 compatible web browser.
I decided to build a servlet that tells me the mood of a famous personality at any given time. The code is nothing but overuse of Randomness to pull of the statements:
publicclass MoodServlet extends HttpServlet {

privatefinal List<String> celebrities;
privatefinal List<String> activities;
privatefinal List<String> cities;
privatefinal List<String> companions;

{
celebrities = Arrays.asList("Amitabh Bachchan", "Tom Cruise", "Steve Buscemi",
"Madhuri Dixit", "Mary Kom", "Sachin Tendulkar");
activities = Arrays.asList("reading News", "watching Tennis", "out for a walk",
"at a bar", "working ", " taking a pleasant nap");
cities = Arrays.asList("Mumbai", "Pune", "Goa", "Kerala", "Jammu", "Ladakh");
companions = Arrays.asList("Family", "Friends", "dog", "Colleages", "kids", "spouse",
"neighbors");
}

@Override
protectedvoid doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int waitTimeBetweenPosts = (int) (Math.random() * 5);
String statement1 = getCelebrityMood();
String statement2 = getCelebrityMood();
// content type must be set to text/event-stream
resp.setContentType("text/event-stream");

// encoding must be set to UTF-8
resp.setCharacterEncoding("UTF-8");
PrintWriter writer = resp.getWriter();
writer.write("data: wait time - " + waitTimeBetweenPosts + " seconds " + "\n");
writer.write("data:" + statement1+ "\n");
try {
Thread.sleep(waitTimeBetweenPosts * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
writer.write("data: " + statement2+ "\n");
writer.write("\n");
writer.flush();
writer.close();
}

privateString getCelebrityMood() {
return celebrities.get((int) (Math.random() * celebrities.size()))
+ " : I wish I was " + activities.get((int) (Math.random() * activities.size()))
+ " at " + cities.get((int) (Math.random() * cities.size())) + " with my "
+ companions.get((int) (Math.random() * companions.size()));
}

}
The interesting parts in the code is :
  1. The class is a normal HttpServlet. 
  2. The content type however distinguishes this as server side events - "text/event-stream"
  3. Each write to the stream is prefixed with "data:" and ended with as "\n"
  4. The end of message is indicated by a "\n". 
So a sample message would be of the form
data: wait time - 2 seconds 
\ndata: Tom Cruise : I wish I was reading News at Goa with my spouse\n
data: Madhuri Dixit : I wish I was watching Tennis at Goa with my spouse\n\n
This whole is one single message. This message will now be processed at our client:
<!DOCTYPE HTML>
<html>
<body>
<b> What's trending on Page 3 </b>:
<div id="messages"></div>
<br/><br/>

<button onclick="start()">GetMessaged</button>

<script type="text/javascript">

function start() {
if (!!window.EventSource) {
var eventSource = new EventSource("mood");

} else {
alert("Your client does not suport server sent events !")
}

eventSource.onmessage = function(event) {
var value = document.getElementById('messages').innerHTML;
document.getElementById('messages').innerHTML = value
+ "<br/>" + event.data;
};
}
</script>
</body>
</html>
The above message as interpreted by the browser would be:
wait time - 2 seconds Tom Cruise : I wish I was reading News at Goa with my spouse Madhuri Dixit : I wish I was watching Tennis at Goa with my spouse
The page looks as follows:
If we look at Firebug, we can see that the browser sent requests at regular intervals to this page:
 The cool thing about server sent events is that we can associate an event with our data. I made a small change to the servlet code:
String[] events = newString[] {"red","blue","green"};
writer.write("event: " + events[(int) (Math.random()*events.length)] +"\n");
writer.write("data: wait time - " + waitTimeBetweenPosts + " seconds " + "\n");
writer.write("data: " + statement1 + "\n");
pause(waitTimeBetweenPosts);
//Failed to create two events in a single message
// writer.write("event: " + events[(int) (Math.random()*events.length)] +"\n");
writer.write("data: " + statement2 + "\n");
writer.write("\n");
We have introduced three new events - "red","green","blue". Here we preceded our message with information about the event type. Along the lines of
event: X \n
data: Y \n
data: Z \n\n
Then some change in the browser to listen for different events:
function start() {
if (!!window.EventSource) {
var eventSource = new EventSource("mood");

} else {
alert("Your client does not suport server sent events !")
}


eventSource.addEventListener('green', function(event) {
var value = document.getElementById('messages').innerHTML;
document.getElementById('messages').innerHTML = value
+ "<br/> <font color='green'>" +event.data+"</font>";

}, false);
eventSource.addEventListener('red', function(event) {
var value = document.getElementById('messages').innerHTML;
document.getElementById('messages').innerHTML = value
+ "<br/> <font color='red'>" +event.data+"</font>";

}, false);
eventSource.addEventListener('blue', function(event) {
var value = document.getElementById('messages').innerHTML;
document.getElementById('messages').innerHTML = value
+ "<br/> <font color='blue'>" +event.data+"</font>";

}, false);
eventSource.onerror( function(event) {
alert("Failed to execute the event");

}, false);

}
The output looks like below:
 I tried to included multiple events in a single message but that did not work.
Also there is an onError event available in java script to process any failures in the code.

Viewing all articles
Browse latest Browse all 231

Trending Articles