Tuesday, October 29, 2013

HTML5 Server-Sent Events With Java Servlets Example

html5-image
Since the dawn of modern web applications, push notifications have gained significant traction in industry. Instead of pooling data from server it has now become common that server should notify client.
Ajax is so pervasive these days it is almost seen on every web page we visit. This is all good if you want to refresh a part of page every few seconds. But things get ugly if you want tens or hundreds of requests a second. Pooling webserver is too expensive in such cases. With that in mind HTML5 has introduced a nifty cool feature “Server-Sent Events”.

1. Introduction to Server-Sent Events

The Server-Sent Events are the new APIs for opening an HTTP connection for receiving push notifications from a server in the form of DOM events. Consider below javascript code:
//...
var eventSource = new EventSource("/some/data.html");
 
eventSource.onmessage = function(event) {
 
    alert(event.data);
 
};
//...
The above code can be executed in any modern browser (ofcourse the server side script /some/data.html needs to be implemented first). We create an object of class EventSource. We pass a server URL which implements Server-sent events protocol. And finally we add a handler function on .onmessage. Every time server sends a message, the handler is called and the event object will have the data.
No need for pooling. The javascript handler will be asynchronously called.
The server needs to specific. First the response content type must be set to text/event-stream. And the data needs to be sent in following format.
...
data: This is some data
 
data: a quick brown fox
 
data: jumps over a lazy dog.
...
You got the idea. Lets quickly create a Java Servlet based application with Client code for Server-sent event.

2. Server-Sent Events, Hello World Servlet

For our hello world example, we create an html page that has a button to start server-sent event. The server will send us a timestamp every second which we just display on page.
index.jsp
    Time: "foo">
     
    
    
 
    
In above javascript code we created an event source for “/HelloServlet” path. On each message we just prints the data in span “foo”.
Now lets check Servlet code which sents the Server-Sent Events.
HelloServlet.java
package net.viralpatel.servlets;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class TestServlet extends HttpServlet {
     
 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
     
        //content type must be set to text/event-stream
        response.setContentType("text/event-stream");  
 
        //encoding must be set to UTF-8
        response.setCharacterEncoding("UTF-8");
 
        PrintWriter writer = response.getWriter();
 
        for(int i=0; i<10; i++) {
 
            writer.write("data: "+ System.currentTimeMillis() +"\n\n");
 
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        writer.close();
    }
}
The servlet is quite simple. Content type must be set to “text/event-stream” and the character encoding must be UTF-8.
Also each message that we send must ends with \n\n.
web.xml
xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>ServerSentEvent_HttpServlet_example</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <servlet>
        <display-name>HelloServlet</display-name>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>net.viralpatel.servlets.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/HelloServlet</url-pattern>
    </servlet-mapping>
</web-app>
Output
html5-server-sent-events-java-servlet

3. Multiple Events in Server-Sent Events

In above example we tracked a single event. The servlet sent only single data entity. In real world, you might want to send a number of events and want to track same on client side.
For example, consider below Javascript snippet.
var eventSource = new EventSource("HelloServlet");
 
 
eventSource.addEventListener('up_vote', function(event) {
     
        document.getElementById('up').innerHTML = event.data;
         
    }, false);
 
 
eventSource.addEventListener('down_vote', function(event) {
     
        document.getElementById('down').innerHTML = event.data;
         
    }, false);
In above code we used addEventListener() method of EventSource to add a handler function. We added handler to event “up_vote” and “down_vote”. Whenever any of this event changes, we need to update the count on html page.
The server must send the data in format:
...
event: up_vote
data: 10
 
event: down_vote
data: 5
 
event: up_vote
data: 12
 
event: down_vote
data: 9
 
...
The Java Servlet code for this example should be:
HelloServlet.java
package net.viralpatel.servlets;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class HelloServlet extends HttpServlet {
 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        response.setContentType("text/event-stream");
        response.setCharacterEncoding("UTF-8");
 
        PrintWriter writer = response.getWriter();
        int upVote = 0;
        int downVote = 0;
        for (int i = 0; i < 20; i++) {
 
            upVote = upVote + (int) (Math.random() * 10);
            downVote = downVote + (int) (Math.random() * 10);
 
            writer.write("event:up_vote\n");
            writer.write("data: " + upVote + "\n\n");
 
            writer.write("event:down_vote\n");
            writer.write("data: " + downVote + "\n\n");
 
            writer.flush();
             
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        writer.close();
    }
 
}
In above servlet code, we randomly incremented two ints upVote and downVote. Also we sent these ints to client with:
writer.write("event:up_vote\n");
writer.write("data: " + upVote + "\n\n");
Notice single \n in event and double \n\n in data.
You should get following output when the servlet is executed.
custom-event-server-sent-events-servlet

3.1. The EventSource API

In the examples above we used the onmessage event to get messages. But other events are also available:
EventsDescription
onopenWhen a connection to the server is opened
onmessageWhen a message is received
onerrorWhen an error occurs

4. Browser compatibility

As of Oct 2013 – Internet explorer is your enemy :) Server-sent events are supported in all major browsers (Firefox, Opera, Chrome, Safari.) except for Internet Explorer.

References

  1. W3C Specification: Server-Sent Events
  2. Mozilla Development Center: Using server-sent events
  3. Server-Sent Events – W3Schools

Other useful HTML5 APIs

2 comments:

raybanoutlet001 said...

ray ban sunglasses outlet
adidas nmd
nike huarache sale
michael kors outlet online
tiffany jewelry
kobe shoes
adidas nmd
michael kors outlet
yeezy boost 350
chrome hearts
http://www.cheapairjordan.us
nike zoom kobe
tiffany and co outlet online
kobe basketball shoes
cheap tiffanys
tiffany and co outlet
adidas tubular
christian louboutin outlet
kobe sneakers
kobe byrant shoes
ralph lauren online,cheap ralph lauren

jeje said...

Air Jordan 14 Chaussures Beaucoup de raisons basket air max nike homme 2017 peuvent être obtenues pour les individus à choisir la asics femme en solde colle Loctite GO2 dans les types de colle offerts air max jordan femme pas cher sur le marché. La fleur de sampaguita est air jordan homme paris un single avec la fleur la plus 2015 nike air max huarache homme camouflage jungle chaude à travers le pays non seulement en raison chaussures nike la mode de son odeur, mais aussi principalement en the og nike air flight huarache raison de sa signification dans l'histoire des Philippines. nike basket basse femme Les personnes qui commandent Loctite GO2 Glue peuvent l'utiliser sans basket nike air max 95 enfant problème, principalement parce que c'est un produit extrêmement convivial.