Pushlets: Send events from servlets to DHTML client browsers

Discover how pushlets, a servlet-based notification mechanism, enables server-side Java objects to call back JavaScript code within a client browser.

These days, developers increasingly turn to servlets and JavaServer Pages (JSPs) as Web-based frontends that integrate backend databases, Enterprise JavaBeans, or legacy applications. It is, however, difficult to keep client Web browsers up-to-date when the state of backend application data changes after the client has loaded the HTML page. For example, how do you keep one user up-to-date when she views the contents of a database table in her browser while another user simultaneously updates that same table on the server?

Indeed, applications such as live stock feeds, flight-arrival information, or weather-condition updates, in which the server streams or pushes live data, are difficult to create with servlets or JSPs.

How can we ensure these applications will be capable of notifying the browser after HTML page loading? Or, how can we selectively update parts of a page, such as updating only the stock whose price has changed? As seasoned Java developers, we often reflexively think of applets that use sockets or RMI/CORBA as the only server-to-client notification solution.

In this article we'll look at a solution that may better serve our purpose. First, I describe the current solutions for server-to-Web client notification. Next, I introduce pushlets as an alternative -- and possibly unconventional -- notification mechanism and then present a simple pushlet framework with some sample applications. Finally, I discuss some of the advantages and disadvantages of applying pushlets.

Note: This article's examples and complete source code can be viewed and downloaded from http://www.fluidiom.com:8080

Server-to-Web client notification: Current solutions

Before we delve into the pushlet concept, let's review the existing server-to-Web client solutions. Assume we have a Java Web or application server from which we want to notify client browsers. Possible solutions can be categorized as HTML refresh, server-side callbacks, and messaging.

HTML refresh

The simplest notification solution is the HTML refresh. By using <meta> tags in the header of the HTML document, the page automatically reloads every n seconds. If something has changed on the server since the last reload, we get the new content; otherwise, we get the original page. The following simple line, placed between <head> and </head> in an HTML page, does the trick:

   <META HTTP-EQUIV="Refresh" CONTENT="4;URL=http://www.justobjects.nl">

While this solution is simple, we must still ask, how long should we make the refresh interval?

Server-side callbacks

In server-side callbacks, a server object calls back a Java-applet client using RMI (Remote Method Invocation) or CORBA (Common Object Request Broker Architecture). Usually the client first passes a remote reference of an RMI or CORBA object to the server. The server keeps a list of those references and calls them sequentially at the time of notification. This solution has been discussed in detail in other JavaWorld articles (see Resources).

Messaging

In messaging, an applet is a client of a messaging server that pushes messages over a TCP/IP connection (java.net.Socket) or sends connectionless UDP messages (java.net.DatagramSocket), the latter possibly even with multicast (java.net.MulticastSocket). You can use messaging middleware (MOMs), such as SoftWired's iBus, IBM's MQSeries, and BEA Systems' WebLogic Events, or develop your own custom messaging with java.io.ObjectStream on top of TCP or UDP sockets. The Java Messaging Service (JMS) is an important standard for messaging.

Each of the above solutions has its advantages and disadvantages in complexity, security, performance, scalability, browser Java compatibility, and restrictions such as firewalls. The optimal solution strongly depends on the requirements of your application. For example, when users require a direct interaction with the state, such as in a shared whiteboard, server-side callbacks or messaging can be a powerful technique.

But we are still working within the confines of a browser. Unless the applet constitutes the entire client application, it is difficult to integrate the HTML content with the updates coming from the server. Considering this, how can we alter the content from within the applet when it gets the callback or message? A frequent solution is to refresh the page by calling AppletContext.showDocument(URL) within the callback method. This instructs the browser to change the page with the new URL.

Enter pushlets

Since HTML is a powerful layout language, wouldn't it be nice to be able directly to alter parts of the HTML content with incremental data coming from the server? This would be an ideal scheme for Web applications where content on the server changes dynamically and the required user-to-server interaction -- for example, that driven by HTML forms.

The pushlet mechanism I developed is lightweight and thin on the client; it requires no applets or plug-ins, directly integrates with scripting and HTML, and uses standard HTTP connections; and it can be deployed (in theory!) in any Java-servlet server. It is certainly not meant to replace the traditional solutions outlined above. On the contrary, pushlets may be another option in your toolbox. As a Java architect or developer, you can determine the trade-offs and choose what is best for your particular application.

Pushlet basics

So what are a pushlet and how does it work? In its basic form a pushlet is extremely simple. I will show the basics through a few examples. It's also time to see some code!

HTTP streaming

Pushlets are based on HTTP streaming, a technique sometimes used in multimedia viewing applications such as QuickTime or RealAudio. Instead of closing the HTTP connection after fetching an HTML page, the connection remains open while fresh data is pushed to the client.

Taking the idea of HTTP streaming, we could develop a JSP or servlet that continuously sends new HTML content back to the client in a timer loop, as seen in the example below:

<HTML> <HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> </HEAD> <BODY BGCOLOR="blue" TEXT="white"> <% int i = 1;

try { while (true) { out.print("<h1>"+(i++)+"</h1>"); out.flush();

try { Thread.sleep(3000); } catch (InterruptedException e) { out.print("<h1>"+e+"</h1>"); } } } catch (Exception e) { out.print("<h1>"+e+"</h1>"); } %> </BODY> </HTML>

To see this example in action, from the Pushlets page, click on Examples, then Basics. Then click Run from the HTML Push section. The above example is not terribly useful, since the pushed content is continuously appended to the page while our intention was to alter the loaded content (that is, to show only the actual value of the counter).

In our next example, we jump right into the pushlet mechanics. Again from the Pushlets Examples-Basics page, click Run from the JavaScript Push section. Notice that the page refreshes every 3 seconds. How is that done?

The JavaScript Push example consists of three files: push-js-stream.html, push-js-stream-pusher.jsp, and push-js-stream-display.html. The main page, push-js-stream.html, contains each of the two other files in HTML frames. Let's just follow the route of the events.

When requested, push-js-stream-pusher.jsp, a JavaServer Page, executes on the server. The file's main body is listed below:

  7: <%
  8:   /** Start a line of JavaScript with a function call to parent frame. */
  9:   String jsFunPre = "<script language=JavaScript >parent.push('";
 10:
 11:   /** End the line of JavaScript */
 12:   String jsFunPost = "')</script> ";
 13:
 14:   int i = 1;
 15:   try {
 16:
 17:     // Every three seconds a line of JavaScript is pushed to the client
 18:     while (true) {
 19:
 20:        // Push a line of JavaScript to the client
 21:        out.print(jsFunPre+"Page "+(i++)+jsFunPost);
 22:        out.flush();
 23:
 24:        // Sleep three secs
 25:        try {
 26:             Thread.sleep(3000);
 27:        } catch (InterruptedException e) {
 28:             // Let client display exception
 29:             out.print(jsFunPre+"InterruptedException: "+e+jsFunPost);
 30:        }
 31:      }
 32:    } catch (Exception e) {
 33:             // Let client display exception
 34:             out.print(jsFunPre+"Exception: "+e+jsFunPost);
 35:    }
 36: %>

In line 21 above, we see a timer loop that prints HTML to the browser every 3 seconds. But wait, it's pushing JavaScript, not HTML! What does this mean? Effectively, it pushes a line such as <script language=JavaScript >parent.push('Page 4')</script>.

What does it mean for the browser? The browser, with its JavaScript engine running, obediently executes each line coming in. It calls the parent.push() JavaScript function. Now the parent is the parent of the frame it is in, which is the push-js-stream.html file:

<script LANGUAGE="JavaScript"> var pageStart="<HTML><HEAD></HEAD><BODY BGCOLOR=blue TEXT=white><H2>Server pushes: <P>"; var pageEnd="</H2></BODY></HTML>";

// Callback function with message from server. // This function is called from within the hidden JSP pushlet frame function push(content) {

// Refresh the display frame with the content received window.frames['displayFrame'].document.writeln(pageStart+content+pageEnd); window.frames['displayFrame'].document.close(); }

</script> </HEAD>

<FRAMESET BORDER=0 COLS="*,0"> <!-- frame to display the content pushed by the pushlet --> <FRAME SRC="push-js-stream-display.html" NAME="displayFrame" BORDER=0 SCROLLING=no>

<!-- Hidden frame with the pushlet that pushes lines of JavaScript--> <FRAME SRC="push-js-stream-pusher.jsp" NAME="pushletFrame" BORDER=0 SCROLLING=no> </FRAMESET>

The push() function called from within the JSP frame (pushletFrame) writes whatever it gets passed in its content argument into the displayFrame. The function push(content) illustrates some dynamic HTML: you can refresh the content of a frame or window by calling writeln of its document object. So the displayFrame is the real view where the content is displayed. It initially displays "Wait..." until the server pushes the first content.

<HTML>
<BODY BGCOLOR=black TEXT=white>
<H1>WAIT...</H1>
</BODY>
</HTML>

The example above demonstrates the whole idea of pushlets: we stream in lines of JavaScript from a servlet (or JSP in the example above) into a hidden frame. The browser executes the lines and may do something interesting. So effectively we have a callback from Java in the server to JavaScript in the client browser! Phew, that was easy!

The example above demonstrates the mechanics, but a couple of issues still have to be solved and features have to be added. For that reason I've built a simple event framework that supports pushlets -- but first I will pull you off the Java track with something called dynamic HTML.

Not just Java: Dynamic HTML

Long gone (in Internet time) are the days when a Website could be produced by the local sysop who scanned in some images from the company's brochure and knew a few HTML tags. The possibilities for manipulating content and user interaction within the browser are expanding through dynamic HTML (DHTML). As a Java programmer using servlets and JSPs, you should make DHTML part of your toolkit. Be aware that you will often have to make trade-offs when you divide functionality among the servlets or JSPs and the DHTML pages executed in the client browser. That is often not an easy decision, but knowing the advantages and disadvantages of DHTML will help you make a better one.

Dynamic HTML refers to a combination of HTML, Cascading Style Sheets (CSS), JavaScript, and the browser's Document Object Model (DOM). Traditionally, a page could be altered only by reloading a new page from the server. DHTML allows full control of an HTML document within a browser after the page has been loaded. You may have seen such examples as image rollovers, pop-up content, and collapsible menus. Most browsers at version 4.0 and later support DHTML, albeit with some differences in standards (see below).

From a programmer's point of view, the entire document in the browser -- its frames, images, paragraphs, tables, and so on -- is represented as a hierarchical object model, the DOM (not to be confused with the XML DOM). Through JavaScript you can manipulate the elements of the DOM and thereby change the content or appearance of the document. Moreover, you can capture user events such as mouse moves and form submissions, and subsequently process those events to modify DOM elements. For example, a mouse moving over an image may produce a mouseover event that, when processed, changes the image by popping up explanatory text. It sounds great, doesn't it? We just need to get familiar with the DHTML standard and off we go! Hmm, but who defines the DHTML standard?

1 2 3 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more