Skip to main content

Server Sent Events Sample with Glassfish

Posted by bhaktimehta on April 21, 2012 at 12:34 AM PDT

Introduction

Server-Sent Events (SSE) is a standard describing how servers can initiate data transmission towards clients once an initial client connection has been established.
It is commonly used to send message updates or continuous data streams to a browser client and designed to enhance native, cross-browser streaming through a JavaScript API called EventSource, through which a client requests a particular URL in order to receive an event stream.

Sample

The sample demonstrates a simple example of SSE. Here we have a servlet which periodically polls for Twitter information and pushes the data to the clients using Server Sent Events. This samples showcases a JavaEE6 application that uses CDI,ServerSentEventHandler and ServerSentEventHandlerContext apis along with twitter search apis and javascript client code. 

Code Snippets

Here is the code for the ServletContextInitializer. There is a Timer which gets the feeds periodically

public class SSEServletContextListener implements ServletContextListener {

    @Inject
    TwitterFeedBean tfs;

    private final int time = 60;

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext();
        try{
            // create the timer and timer task objects
            Timer timer = new Timer();

            TwitterTimerTask task = new TwitterTimerTask(tfs);

            timer.schedule(task, 0, 1000 * time);

            // save our timer for later use
            servletContext.setAttribute ("timer", timer);
        } catch (Exception e) {
            servletContext.log ("Problem initializing timer task every "+ time +" seconds: "
                    + e.getMessage ());
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext();

        Timer timer = (Timer)servletContext.getAttribute ("timer");

        if (timer != null)
            timer.cancel();

        servletContext.removeAttribute ("timer");
    }

    class TwitterTimerTask extends TimerTask {
        TwitterFeedBean bean;
        TwitterTimerTask(TwitterFeedBean  t)   {
            this.bean = t;
        }

        public void run() {
            try {
                bean.getFeeds();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

Here is the TwitterHandler which is a ServerSentEventHandler

/**
* TwitterHandler class which will send messages using Server Sent Events
*
* @author Bhakti Mehta
*/
@ServerSentEvent("/twittersse")
public class TwitterHandler extends ServerSentEventHandler {


    @Override
    public void onConnected(ServerSentEventConnection client) {
        super.onConnected(client);

    }

    public void sendMessage(String data) {
        System.out.println("Handler="+this+" Sending data="+data);
        try {
            connection.sendMessage(data);
        } catch(IOException ioe) {
            // May be client is already disconnected. Just close it
            try {
                connection.close();
            } catch(Exception e) {
                //ignore if the connection close threw an exception
            }
        }

    }

Here is the TwitterFeedBean which gets the data from the Twitter search url
@Named
@ApplicationScoped
public class TwitterFeedBean {

    @Inject @ServerSentEventContext("/twittersse")
    ServerSentEventHandlerContext sc;


    final private String SEARCH_URL =
            "http://search.twitter.com/search.json?q=glassfish&rpp=5&include_entities=true" +
                    "&with_twitter_user_id=true&result_type=mixed";


    public TwitterFeedBean() {
    }

    public void getFeeds() throws IOException {

        for(TwitterHandler handler : sc.getHandlers()) {
            handler.sendMessage(composeMessage());
        }

    }

    private  String composeMessage() {
        return getFeedData();
    }

    private  String getFeedData() {
        StringBuilder sb = new StringBuilder();
        try {
            URL twitter = new URL(SEARCH_URL);
            URLConnection yc = null;

            yc = twitter.openConnection();


            BufferedReader in = new BufferedReader(
                    new InputStreamReader(
                            yc.getInputStream()));
            String inputLine;

            while ((inputLine = in.readLine()) != null) {
                System.out.println("Input line" + inputLine);
                sb.append(inputLine)  ;

            }
            in.close();

            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new String("Error in getting data from the feeds ") ;
    }



}

Finally here is the app.js which will create the EventSource. It also parses the JSON feeds

var network = function (eventSource) {
    return {
        initialize: function() {
            var url = 'http://' + document.location.host
                + '/sse-twitter-sample/twittersse';
            eventSource = new EventSource(url);


            eventSource.onmessage = function (event) {
                var feeds = event.data.toString();
                console.log(feeds);
                var theNewParagraph = document.createElement('p');

                var theBreak = document.createElement('br');
                theNewParagraph.setAttribute('title','The feeds');
                var data = JSON.parse(feeds);
                var theText;

                var divTag ;
                var tweetInfo  ;

                // Before we continue we check that we got data
                if(data !== undefined) {
                    for (var k = 0;k<5;k++) {
                        tweetInfo = data.results[k];


                        divTag = document.createElement("div");
                        divTag.id = "div"+k;
                        divTag.setAttribute("align","left");
                        divTag.style.margin = "0px auto";
                        divTag.className ="outerDiv";


                        divTag.innerHTML =
                            ''+ tweetInfo.text+'<\/a>'+

                                 ' Created on '  + tweetInfo.created_at  ;


                        document.body.appendChild(divTag);
                        document.body.appendChild(theBreak);

                    }


                }
                  document.body.appendChild(theNewParagraph);

            };
        },
        send: function(commandn) {
            eventSource.send(command);
        }
    }
};

var APP = {
    network: network(null),

    initialize: function () {
        APP.network.initialize();
    }
};

window.onload = APP.initialize;

To run the sample deploy the sse-twitter-sample.war to the latest nightly of glassfish 4.0 and you can run
http://localhost:8080/sse-twitter-sample/ You may have to wait for a minute before the feeds start appearing. Also since this is a sample to stop the timer you should undeploy the application otherwise it will keep getting the tweets..
Jitu has another sample here
Note this is a work in progress so apis may change.

AttachmentSize
sse-twitter-sample.zip18.65 KB
Related Topics >>