Java Developer | Technical Teacher | Author of "Java Mimarisiyle Kurumsal Çözümler" Rahman has posted 11 posts at DZone. You can read more from them at their website. View Full User Profile

HTML 5 Server Sent Events on Glassfish 4

12.13.2013
| 845 views |
  • submit to reddit

SSE (Server Sent Events) is a Web Pushing technology that was developed under HTML 5 technology. So, what is Pushing?

Pushing

It is a transmission of data sets that are sent at regular intervals or in any time through the server application, in the direction of server – – – > browser, without the need for any request of web browser. Serving Twitter updates currently in the web page at regular intervals, appearance of Facebook shares on screen when a new share is available, serving instant financial data (exchange rate of dollar, parity etc.) immediately to users’ screen can be given as examples for pushing scenerio.

Server Sent Events is not a unique technique used for pushing of http resource, in theprevious article, we mentioned how to provide data transmission to the web browser by LongPolling technique. I think this sequencing about Push technologies would not be wrong generally in this order;

Polling –> LongPolling –> ServerSentEvents –> WebSocket

ServerSent Events is a technology that its developments is already continues, such as WebSocket technology. For this reason, I would like to mention that it is not useable in every web browser and that’s for sure it is supported by new generation web browsers.

SSE technology has a few additional features unlike other ones, such as automatic connection recovery when the connection is lost, routing the message to an certain function in event/resource broadcasts. For example, you can take a look at to the discussion about the comparison of SSE and WebSocket from the entry in StackOverFlow.

How the SSE works?

The logic of operation of SSE technology can be seen in the picture illustrated below. Ahandshake request is sent to SSE supported server by the web browser and server system returns a handshake response which is “text/event-stream” MIME type. After the handshake committed among web browser and SSE service, SSE service may send any amout of data at any time. jaxrs-sse

JaxRS 2 standard under the technology umbrella of Java EE 7 provides support for SSE (Server Sent Events) technology with its second version. And now, let’s practice a Jax-RS 2 application together by using Twitter REST API which searches a word and then broadcasts the results to all clients in a certain interval. Dependencies Jax-RS 2 is under the Java EE 7 spesification and Jersey 2 library is the reference implementation of it. So, if the application is desired to be run in Glassfish 4 application server, in the following Maven dependency element must be added pom.xml that is Maven configuration file.

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>

SSE technology can be added to applications as an external feature of Jersey 2 library. It means that there is not any SSE feature in javaee-api (but glassfish contains inside), so it should be added as a provided dependency in the form of a plug-in/feature. 

<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

We will use Json-P technology in the application which is a standard under the Java EE 7, for the purpose of managing the JSON objects and arrays easily. Because of that, “javax.json” dependency should be added inside the pom.xml. 

<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0.3</version>
<scope>provided</scope>
</dependency>

Because this application will make a Twitter search, it must use Twitter REST API version 1.1. for this reason (1.0 deprecated), you can benefit from Twitter4j library which elasticizes the usage of Twitter REST API. 

<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>3.0.5</version>
</dependency>

If the application is desired to be run in some lightweight Servlet Container platforms such as Jetty or Tomcat apart from application servers, “jersey-container-servlet” dependency can be added inside the pom.xml.

<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.0</version>
</dependency>

Configuration

A REST Endpoint class should be added inside the application for an entry point to Jax-RS server.

@ApplicationPath("/search")
public class SearchEndpoint extends Application {

@Override
public Set<Class<?>> getClasses() {

   Set<Class<?>> classes=new HashSet<>();
   classes.add(SearchResource.class);
   return classes;
}

@Override
   public Set<Object> getSingletons() {
   Set<Object> singletons=new HashSet<>();
   singletons.add(new SseFeature());
   return singletons;
}
}

If you pay attention to Application#getClasses() method, you can see that a Java class by the name of SearchResource is configured as a RESTful resource, and a new SseFeature is declared to RESTful application in the Application#getSingletons() method.

SearchResource as a RESTful resource

A Java class namely SearchResource is a REST resource which enables the handshake between the web browser and server. In addition, SearchResource broadcasts the Twitter searches made on the server to the users.

@Path("/")
public class SearchResource {

private static final SseBroadcaster BROADCASTER = new SseBroadcaster();
private static final ScheduledExecutorService sch = Executors.newSingleThreadScheduledExecutor();

static {

 sch.scheduleWithFixedDelay(
      new SearchTwitTask(BROADCASTER)
      ,0 // Start instantly
      ,30 //  Run SearchTwitTask's run() in every 30 seconds
      ,TimeUnit.SECONDS);

}

@GET
@Produces("text/event-stream")
@Path("/hang")
public EventOutput getMessages() {

	EventOutput eventOutput = new EventOutput();
	BROADCASTER.add(eventOutput); // Added to broadcast list
	return eventOutput;
}

}

If data broadcasting is desired through the SSE technology with Jax-RS, a SseBroadcaster object must be created. If this SseBroadcaster object is added, every client that makes request to the server can make data broadcasting to all users through the SseBroadcaster#broadcast(..) method.

SseBroadcaster class contains within itself each unique user along with EventOutput object. For example, an EventOutput object is being created when a user makes RESTful request to SearchResource#getMessages method. This EventOutput object remains as a broadcasting object which represents the current user’s session. If created EventOutput object attached to SseBroadcaster object then BROADCASTER can send any data to relevant user. When created EventOutput object sent to user, server sends a “text/event-stream” resource, so web browser starts to retrieve data from the server after it takes “text/event-stream” type Handshake data.

Make a search in every 30 seconds and then broadcasting to users

public class SearchTwitTask implements Runnable {
private SseBroadcaster broadcaster;

public SearchTwitTask(SseBroadcaster broadcaster) {
this.broadcaster = broadcaster;
}

@Override
public void run() {

JsonArrayBuilder jsonArray = Json.createArrayBuilder();
JsonObjectBuilder jsonObject = Json.createObjectBuilder(); 

ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
    .setOAuthConsumerKey("kkkkkkkkkkkkk")
    .setOAuthConsumerSecret("sssssssssssssss")
    .setOAuthAccessToken("ttttttttttttttttttttt")
    .setOAuthAccessTokenSecret("tttttttttttttttttttsssssssssssss");

Twitter twitter = new TwitterFactory(cb.build()).getInstance();

QueryResult result = null;
try {
// Searching Java EE twits
result = twitter.search(new Query("Java EE")); 

// Every records added to Json Array as a Json Object
for (Status status : result.getTweets()) { 
	jsonObject.add("created_at", 
	       status.getCreatedAt().toString());
	jsonObject.add("from_user_name",
	       status.getUser().getScreenName());
	jsonObject.add("profile_image_url",
	       status.getUser().getProfileImageURL());

	jsonArray.add(jsonObject.add("text",   
	       status.getText()));
}
} catch (TwitterException e) {
e.printStackTrace(); 
}
// Gets result as a Json String
String twitJsonArray= jsonArray.build().toString(); 

// Creates a SSE Event object,,,
OutboundEvent.Builder b = new OutboundEvent.Builder();
// in application/json format
b.mediaType(MediaType.APPLICATION_JSON_TYPE);

// Search results are broadcasting to all members
broadcaster.broadcast(b.data(String.class,twitJsonArray).build());

}
}

SearchTwitTask is a task class which is type of Runnable interface and is being run in every 30 seconds with SchedulerExecutorService object. Of course EJB’s Timer Feature or Concurrent Utility version of (Managed)SchedulerExecutorService can be used here, but for portability reason, Java SE SchedulerExecutorService is used here. Firstly, Twitter records are being searched in which “Java EE” expression is mentioned and then the results are got as JsonArray object with Json-P library in the @Override Runnable#run method, respectively.

Broadcast operations done with Jax-RS 2 can be forwarded to users as OutboundEvent object which will be created by the developer. In the SearchTwitTask class, String type twitJsonArray data which is identified as MIME type “application/json”is being broadcasted to all application consumers through the broadcast method of SseBroadcasterclass.

SSE HTML side

<!DOCTYPE html>
<html class=" js no-touch svg inlinesvg svgclippaths no-ie8compat js no-touch svg inlinesvg svgclippaths no-ie8compat">
<head>
<title></title>
<meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="http://cdn.jsdelivr.net/foundation/4.0.4/css/foundation.min.css">
<link type="text/css" rel="stylesheet" href="http://cdn.jsdelivr.net/foundation/4.0.4/css/normalize.css">
</head>
<body>

<!-- Header and Nav -->
<div class="row">
<div class="large-12 columns">
<div class="panel">
<div class="row">
<div class="large-6 columns">
	<h1>Twitter Search Broadcaster</h1>
</div>
<div class="large-6 columns" >
	Pushes new data searhed for Java EE in every 30 seconds.
</div>
</div>
</div>
</div>
</div>

<!-- End Header and Nav -->
<div class="row" id="alertbox" style="display: none;">
<div class="large-12 columns">
<span class="alert-box alert">Your browser doesn not support HTML 5 SSE <img src="http://kodcu.com/wp/wp-includes/images/smilies/icon_sad.gif" alt=":(" class="wp-smiley"> </span>
</div>
</div>

<div class="row">
<!-- Feed Placeholder -->
<div id="feeds" class="large-12 columns"></div>

</div>

<!-- Footer -->
<footer class="row">
<div class="large-12 columns">
<hr>
<div class="row">
<div class="large-12 columns">
<p>© Twitter Search Broadcaster | kodcu.com</p>
</div>
</div>
</div>
</footer>

<script type="text/x-mustache-template" id="feedTemplate">
{{#.}}
<!-- Feed Entry -->
<div class="row">
<div class="large-1 columns small-3"><img style="min-height: 60px;min-width: 60px;" src="{{profile_image_url}}">
</div>
<div class="large-11 columns">
<div class="row">
<div class="large-12 columns">
	<p><strong>{{from_user_name}} said:</strong> {{text}}</p>
</div>
<div class="large-12 columns">
	<p><strong>Created date:</strong> {{created_at}}</p>
</div>
</div>

</div>
</div>
<!-- End Feed Entry -->

<hr>
{{/.}}
</script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.min.js"></script>
<script type="text/javascript" src="resources/jaxrs-sse.js"></script>
</body>
</html>

The following technologies are used in the HTML side of the application where Twitter search is being made:

SSE Javascript side

(function () {

if((typeof EventSource)==="undefined")
{
   // if SSE is not supported by current browser 
   $("#alertbox").css("display","");
   return;
}

// Connecting to SSE service
var eventSource = new EventSource("search/hang");

// After SSE handshake constructed
eventSource.onopen = function (e) {
 console.log("Waiting message..");
};

// Error handler
eventSource.onerror = function (e) {
 console.log("Error");
 console.log(e);
};

// Message handler
eventSource.onmessage=function (e) {
   console.log(e);
   var feedTemplate = $("#feedTemplate").html();
  // Renders the template with Json Array returned SSE service 
   var feeds = Mustache.render(feedTemplate, $.parseJSON(e.data));
   
   $("#feeds").html(feeds);
};
})();

Javascript sided main object of the HTML 5 SSE technology is EventSource. Just as EventSource object is created, it makes a request to SSE service with an URL and operates Callback functions dependent to onopen, onerror, onmessage areas which of them are available for the management of session, error and getting message cases.

Running the application

Twitter search application can be run in two ways:

1. Way (With embedded jetty plug-in)

> mvn clean package jetty:run-war

2. Way (With Glassfish 4 application server)

> mvn clean package

> asadmin start-domain

> asadmin deploy JaxRS-SSE-1.0.war

You can access to the application which are run one of these methods from this address http://localhost:8080/JaxRS-SSE

A Live Example: http://discoverjavaee.com/JaxRS-SSE/

You can Access to application’s codes from http://en.kodcu.com/2013/11/jaxrs-2-html-5-server-sent-events-on-glassfish-4/

Hope to see you again.

Published at DZone with permission of its author, Rahman Usta.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)