Ajax (Asynchronous JavaScript and XML) is a term coined to represent a set of technologies that enable creation of Rich Internet Applications. Using these technologies you can create Web applications that have responsive and rich user interfaces similar to desktop applications. They enable your Web applications to retrieve data asynchronously in the background without affecting the page being displayed, as well as just requesting the data and not the entire HTML page. You use the XmlHttpRequest or equivalent object that modern browsers provide for this asynchronous background communication.
IBM WebSphere Application Server Community Edition v2.1.x (hereafter referred to as Community Edition) comes packaged with a few popular frameworks for developing and hosting Ajax-enabled applications. In this article we investigate how to configure and use three of these frameworks, namely:
- The Dojo Toolkit
- Direct Web Remoting (DWR)
- Tomcat Comet Support
We also develop a simple Web application that uses these technologies to provide an improved user experience. To follow along you need WebSphere Application Server Community Edition v2.1.x.
Dojo is an open-source DHTML toolkit written in JavaScript. Dojo solves some of the problems that are associated with using JavaScript, including handling browser-specific behaviors. These behaviors have been abstracted from the user via the Dojo toolkit.
It also provides a set of configurable widgets which can be used to rapidly develop
dynamic and browser independent Web pages. The Dojo toolkit comprises of a set of
JavaScript APIs, and is included in WebSphere Application Server Community Edition v 2.1. It can be accessed via the context root /dojo. Dojo also provides APIs for making asynchronous XMLHttpRequest calls for fetching data from the server without refreshing the page.
DWR allows a developer to expose server-side Java™ objects to the client via JavaScript proxies. It creates proxies for all the exposed Java™ objects that can then be invoked from the client. In turn DWR invokes the corresponding Java methods in the server and returns the response back to the invoker script in JSON (JavaScript Object Notation) format.
You can configure DWR to call the server synchronously or asynchronously in the background. Therefore, it can avoid the page refreshes associated with the normal HTTP request-response model.
DWR also provides Reverse Ajax, which is a mechanism to send information asynchronously from the server to a browser. This lets the server publish responses to clients at periodic intervals, in the following ways:
- Polling: Client keeps polling the server at regular intervals.
- Comet: When the client makes a request, the server keeps a handle to the response and into which it keeps writing. In this case the client need not poll.
- Piggy back: Responses are clubbed and sent with the response to the next request that the client makes.
Comet is a term coined by Alex Russel of the Dojo Foundation to describe an event-driven, server-push mechanism over the HTTP protocol. In normal HTTP communication, the client always initiates the data transfer by opening a connection to the server and sending a request. The server processes this request, sends a response on the same connection, and then closes the connection. Thus the connection is relatively short lived. In Comet, the server keeps that connection open and keeps on writing data whenever a relevant event occurs. Tomcat provides this support via the NIO and APR connectors. The BIO connector does not provide Comet support.
By default Community Edition does not come with a pre-installed NIO connector. We need to create and start a new NIO connector from the administrative console before we can run applications that use the Comet protocol. We will first delete the BIO connector that runs on port 8080, and then create a new NIO connector to run on the same port.
Follow these steps to create the NIO connector:
-
Start Community Edition, and open
https://localhost:8443/console/in your browser. -
Enter
systemfor the user name andmanagerfor the password. Click Login, which brings up the Welcome page in the administrative console. -
In the left navigation pane, click the Web Server link to bring up the Web Server Manager page, as Figure 1 shows:
Figure 1. Web Server Manager
Delete the connector named TomcatWebConnector.
-
In the Add New section, click the Tomcat NIO Connector link, which brings up the screen shown in Figure 2.
Figure 2. Adding a new Tomcat NIO connector
-
Fill in the uniqueName field with the value
TomcatNIOConnectorand click Save, which creates and starts the NIO connector. Your window should now look like Figure 3.
Figure 3. TomcatNIOConnector added to network listeners
Developing the Web Application
We are now all set to develop the Web application. It will be a stock ticker
application that updates every 5 seconds with the latest quotes. We will use DWR's
Reverse Ajax functionality over the Comet implementation provided by Tomcat. To
display the quotes we will use a ready-made Dojo widget from the Dojo toolkit, the dojox.Grid widget. We will also write a servlet that uses the Comet support in Tomcat to print the stock information.
Apache Tomcat provides the org.apache.catalina.CometProcessor interface, which all the servlets that you write can implement to use Comet support. This interface defines a single method, namely public void event(CometEvent event)to implement in our servlet. Listing 1 shows the two main methods of this servlet:
Listing 1: Comet Servlet
public void init() throws ServletException {
super.init();
Runnable r = new Runnable() {
public void run() {
while (!stop) {
synchronized (openConnections){
List<Stock> stocks = new StockService().getStocks();
for (HttpServletResponse response : openConnections) {
try {
PrintWriter pw = response.getWriter();
for (Stock stock : stocks) {
pw.println(stock.getSymbol() + ":"
+ stock.getPrice());
}
pw.flush();
} catch (IOException e) {
e.printStackTrace(System.out);
}
}
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace(System.out);
}
}
}
};
Thread stockThread = new Thread(r);
stockThread.setDaemon(true);
stockThread.start();
}
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
synchronized (openConnections){
openConnections.add(response);
}
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
synchronized (openConnections){
openConnections.remove(response);
}
} else if (event.getEventType() == CometEvent.EventType.END) {
synchronized (openConnections){
openConnections.remove(response);
}
} else if (event.getEventType() == CometEvent.EventType.READ) {
}
}
|
In the init method we instantiate a thread that gets the stock quotes and writes it to all the clients that are listening, i.e all the response objects in the openConnections list. The event method is triggered when any of the four events (BEGIN, ERROR, END, READ) occurs. We get the response from the org.apache.catalina.CometEvent object that is passed as a parameter. For the BEGIN event, add the response to the collection. For the ERROR and END events, we remove the response from the list.
The BEGIN event represents the beginning of processing for
that connection, so we add the response to the list of responses. The END and ERROR events represent the end of
the connection or the occurrence of an error. For more information on what these
events mean, see the Apache Tomcat documentation .
The application has a hard-coded set of stocks that it displays. The values of the stocks are randomly updated by the com.dev.trade.service.StockQuoteGenerator class. Listing 2 shows the relevant part of the source code for this class.
Listing 2: Class that generates stock prices
package com.dev.trade.service;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Collections;
import com.dev.trade.bo.Stock;
public class StockQuoteGenerator {
private StockService ss = new StockService();
private List<Stock> stocks = null;
private static StockQuoteGenerator generator = new StockQuoteGenerator();
private Set<QuoteListener>
listeners = Collections.synchronizedSet(new HashSet<QuoteListener> ());
private volatile boolean contextDestroyed = false;
private StockQuoteGenerator() {
Runnable r = new Runnable() {
public void run() {
try {
while (!contextDestroyed) {
update(generateStockQuotes());
Thread.sleep(5000);
}
}catch (Exception e) {
e.printStackTrace(System.out);
}
}
};
Thread t = new Thread(r);
t.setDaemon(true);
t.start();
}
public static StockQuoteGenerator getInstance() {
return generator;
}
public void setContextDestroyed(boolean cd) {
this.contextDestroyed = cd;
}
public void addListener(QuoteListener listener) {
listeners.add(listener);
}
private void update(List<Stock> stocks) {
for (QuoteListener listener : listeners) {
listener.updateStockQuotes(stocks);
}
}
private List<Stock> generateStockQuotes() {
stocks = ss.getStocks();
return stocks;
}
}
|
In the constructor of StockQuoteGenerator class, which is a singleton class, we are
starting a new thread and assigning a Runnable object to that thread. So the run method of this object keeps on executing until the contextDestroyed variable is set to true. This variable is set to true only when the application context is going to be destroyed. For this we will be registering a context listener in the web.xml , namely com.dev.trade.listener.ServletContextListener.
The generateStockQuotes method invokes the getStocks method of StockService to get the generated stock quotes . You use the addListener method to add listeners. These listeners implement the com.dev.trade.service.QuoteListener interface, and thus the method updateStockQuotes.
The listeners are all instances of com.dev.trade.service.StockQuoteListenerImpl. This class in its constructor initializes an instance of the org.directwebremoting.WebContext class provided by DWR, and then registers itself with StockQuoteGenerator's list of listeners. Listing 3 shows the updateStockQuotes method of this class.
Listing 3: Code for pushing data to different clients
public void updateStockQuotes(List<Stock> stocks) {
ScriptBuffer script = new ScriptBuffer();
script.appendScript("updateStocks(").appendData(stocks).appendScript(
");");
Collection<ScriptSession> sessions = wctx.getAllScriptSessions();
for (ScriptSession session : sessions) {
if(!session.isInvalidated()){
session.addScript(script);
} else {
wctx.getAllScriptSessions().remove(session);
}
}
}
|
This method propagates a JavaScript function call to all the open clients. It calls the function updateStocks and passes the values of stocks. This JavaScript method actually updates the model of the Dojo grid widget that we will be displaying and then calls its update method so that the grid displays with the new data. DWR creates script sessions for each open stock ticker page.
Note that for this to work the StockQuoteListenerImpl class's constructor should be called by the same thread DWR code is executing in. For this we will need to configure DWR to instantiate the objects of StockQuoteListenerImpl. For this configuration we create a dwr.xml file that we place in the WEB-INF directory of the application. Listing 4 shows this file.
Listing 4: dwr.xml
<dwr>
<allow>
<create creator="new" javascript="Ticker" scope="application">
<param name="class" value="com.dev.trade.service.StockQuoteListenerImpl"/>
</create>
<create creator="new" javascript="StockService" scope="application">
<param name="class" value="com.dev.trade.service.StockService"/>
</create>
<convert converter="bean" match="com.dev.trade.bo.Stock"/>
</allow>
</dwr>
|
Note that the StockQuoteListenerImpl has been exposed in the dwr.xml via a creator. We set the scope of this object to application, as only one instance is needed per application. The other class that we expose to JavaScript is the com.dev.trade.service.StockService, which provides us with a method getStocks to get the list of stocks. We also need to add the DWRServlet to the web.xml of our application so that DWR is initialized and exposes proxies of the above configured objects to JavaScript. Listing 5 shows the web.xmlfile.
Listing 5: web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4"
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>brokerage</display-name>
<listener>
<listener-class>
com.dev.trade.listener.DwrContextListener
</listener-class>
</listener>
<servlet>
<display-name>DWR Servlet</display-name>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>initApplicationScopeCreatorsAtStartup</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/stocks.html</welcome-file>
</welcome-file-list>
</web-app>
|
The activeReverseAjaxEnabled property is set to true so that DWR uses Comet for enabling Reverse Ajax. If it is set to false, then DWR will be using the piggy-back option.
The initApplicationScopeCreatorsAtStartup is for initializing all the application scoped objects at startup of DWR.
Now at the client side we need to import two script files: the DWR client-side engine and the JavaScript proxy that DWR creates for the exposed object com.dev.trade.service.StockService. Listing 6 shows the code for this import.
Listing 6: Accessing on the client
<script type="text/javascript" src="dwr/engine.js"></script> <script type='text/javascript' src='/brokerage/dwr/interface/StockService.js'></script> |
We also need to configure the DWR client side engine to use active Reverse Ajax, so we need to call dwr.engine.setActiveReverseAjax(true).
We can invoke the getStocks method of StockService to initially populate the Dojo grid widget that we will be displaying, using StockService.getStocks({callback:getModel,async:false}). The parameter getModel refers to a JavaScript method that will be called with the result of this call passed as a method parameter.
The method shown in listing 7 returns the model for the dojo grid that we will be displaying.
Listing 7: Web Remoting
function getModel(stocks) {
var data = new Array();
for ( var i = 0; i < stocks.length; i++) {
var subData = new Array();
subData[0] = stocks[i].symbol;
subData[1] = stocks[i].companyName
subData[2] = stocks[i].price
subData[3] = stocks[i].eps
data[i] = subData;
}
updatedModel = new dojox.grid.data.Table(null, data);
return updatedModel;
}
|
Community Edition comes bundled with the Dojo JavaScript library. It uses Dojo for some of the administrative console portlets. Dojo is bundled as a Web application that is available at the context root /dojo. To use Dojo in our HTML client page, we need to import the dojo.js script, using the scripts shown in listing 8.
Listing 8: Import dojo.js
<script type="text/javascript" src="/dojo/dojo/dojo.js" djConfig="isDebug:false, parseOnLoad: true"></script> |
When the Dojo script is imported we can import the remaining dependencies via dojo.require calls. The dojox.Grid widget that we are going to create needs a model and a structure. The model represents the data to be displayed, and the structure represents how we are going to display it. The model is actually an array of arrays. Listing 9 shows the structure definition:
Listing 9: Model definition
var view1 = {
noscroll :false,
cells : [ [ {
name :'Symbol',
width :'auto'
}, {
name :'Company Name',
width :'auto'
}, {
name :'Price',
width :'auto'
}, {
name :'Earnings Per Share',
width :'auto'
} ] ]
};
var gridLayout = [ {
type :'dojox.GridRowView',
width :'20px'
}, view1 ];
<div class="tundra" id="stock_grid" dojoType="dojox.Grid" model="updatedModel"
structure="gridLayout" elasticView="1" defaultHeight="37em"></div>
|
In this listing we see that the div with id="stock_grid" encapsulates the actual grid. The structure is defined by the gridLayout object, which is an array that contains view1.
The view1 variable is also an array, containing the cells property that provides the details of how all the columns should display in the grid.
Build and deploy the Web Application
To build the application you will need Apache Maven2. Install Maven2 and follow these steps to build the application:
-
Extract the
ticker.ziparchive, which creates a directory calledticker. -
Open the command shell and change the current directory to
ticker. -
Run
mvn install. This will build the application and place the output WAR file intargetdirectory underticker. The name of the WAR file isticker.war. - Open the Community Edition console in your browser and navigate to the Deploy New portlet.
-
In the Archive text box, enter the path to the generated
ticker.warand click Install.
-
Open http://localhost:8080/ticker in your Web browser to bring up the stock ticker, as shown in Figure 4.
Figure 4. Stock ticker running in the browser
-
Open http://localhost:8080/ticker/comet in your Web browser to see the output of the Comet servlet, as shown in Figure 5.
Figure 5. Comet servlet output
We created and configured the NIO connector of the Tomcat instance that is embedded in Community Edition via the administrative console. We also developed a Java EE Web application that uses DWR's Reverse Ajax functionality to push data from the server to the browser over the Comet support built into the NIO connector. Finally, we saw how to implement Tomcat's CometProcessor interface to write a servlet that exposes its Comet functionality.
Thanks to Phani Madgula and Ashish Jain for reviewing this material.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample source code | ticker.zip | 8KB | HTTP |
Information about download methods
Learn
- developerWorks Ajax
Resource Center
- Direct Web Remoting (DWR)
- The Dojo Toolkit
- JavaScript Object Notation (JSON)
- What’s new in WebSphere Application Server Community Edition V2.1
- Developing
JPA Applications with WebSphere Application Server Community Edition
- WebSphere Application Server Community Edition support site
- WebSphere Application Server Community Edition documentation
- WebSphere
Application Server Community Edition samples
- Apache Geronimo site
- Develop applications on all the Java EE5 APIs
-
Get to know Java EE 5
-
WebSphere Application Server Community Edition Technical Support offerings
-
WebSphere Application Server Community Edition resources
- developerWorks Open Source zone
- developerWorks Web development zone
Get products and technologies
Discuss
- developerWorks WebSphere Application Server Community Edition and Apache Geronimo forum
- developerWorks Open Source forum

Manu T. George is a Staff Software Engineer at IBM India Software Labs in Bangalore, India. He is a committer on Apache Geronimo and Apache OpenEJB projects, and is a part of the IBM WebSphere Application Server Community Edition Level 3 Support Team. He received his Bachelor of Technology in Applied Electronics from the College of Engineering Trivandrum in the year 2001.

Vamsavardhana Reddy Chillakuru , a.k.a Vamsi, is an Advisory Software Engineer at IBM India Software Labs in Bangalore, India. He is a committer on Apache Geronimo and Apache Tuscany projects, a member of the Apache Geronimo Project Management Committee, and is part of the IBM WebSphere Application Server Community Edition Level 3 Support Team. He received his Bachelor of Statistics (Hons.) and Master of Statistics degrees from Indian Statistical Institute, Kolkata, India in the years 1994 and 1996 respectively.
Comments (Undergoing maintenance)





