Create a dynamic Ajax-based Web application with the WebSphere Application Server Feature Pack for Web 2.0

The IBM® WebSphere® Application Server Feature Pack for Web 2.0 provides a rich set of components that enable developers to easily and more efficiently build powerful Ajax-based applications. This article explains how you can build a Web application that features dynamic charts using the Feature Pack for Web 2.0. You will also see how you can combine major Web 2.0 facilities (like Dojo, Web remoting, Web messaging, JSON4J, and so on) to create a solution with a rich user experience, as well as how to integrate existing back-end services into the Ajax-style architecture.

Li Long Chen (chenlil@cn.ibm.com ), Associate I/T Architect, IBM

Li Long Chen is working as Associate I/T Architect for IBM Managed Business Process Services solution assets.



Ravi Mani (ravimani@us.ibm.com), Executive I/T Architect , IBM

Ravi Mani is working as an Executive I/T Architect for IBM Global Technology Services solutions.



Elaine Zhan (ezhan@cn.ibm.com), Adviosory Software Engineer, IBM

Elaine Zhan is working as an Advisory Software Engineer for IBM Managed Business Process Services solution assets.



Chuan Yang (chuahy@cn.ibm.com), Staff Software Engineer, IBM

Chuan Yang is working as a Staff Software Engineer for IBM Managed Business Process Services solution assets.



Lin Zhi Zou (zoulz@cn.ibm.com), Staff Software Engineer, IBM

Lin Zhi Zou is working as a Staff Software Engineer for IBM Managed Business Process Services solution assets.



23 September 2009

Also available in Chinese Russian Portuguese

Introduction

Technologies that are relevant to Web 2.0, such as Asynchronous JavaScript™ XML (Ajax), Web remoting, Web messaging, and others, have become increasingly prevalent in today’s Web applications. Compared with traditional Web applications, Ajax-based applications make it possible to provide much more responsiveness and interactivity. In those Web applications incorporating Ajax architecture, users don’t need to wait for the entire Web page to be reloaded before seeing new results from the server, and they can often complete tasks with fewer steps on a single Web page that is presented in an incremental or on-demand fashion.

To address the growing need for rapid development and delivery of Ajax-enabled solutions, the IBM WebSphere Application Server Feature Pack for Web 2.0 provides a rich set of components that enables you to build Ajax-based applications easily and efficiently. It also provides an open standards-based framework for integrating existing services or solution assets into rich Internet applications.

The major components of the feature pack include:

  • Ajax client/proxy runtime
  • RPC (Remote Procedure Call) adapter
  • Web messaging service
  • JSON4J (JavaScript Object Notation for Java) library
  • IBM SOAP library
  • IBM Atom library
  • IBM OpenSearch library
  • IBM Gauge widget.

This article describes the steps for building an Ajax-based chart application using the Web 2.0 feature pack. By following this example, you will be able to see how the components included in the feature pack can be used together to construct a complete Web 2.0 solution with a rich user experience.

Prerequisites

This exercise assumes a fundamental knowledge of Web application development and familiarity with Eclipse or IBM Rational® Application Developer. To follow these steps, you will need to have the WebSphere Application Server Feature Pack for Web 2.0 installed successfully in a properly operating WebSphere Application Server (V6.0, 6.1 or 7.0) environment.


About the sample dynamic application

The sample application included with this article is intended to demonstrate possible ways you can use the major components of the Web 2.0 feature pack to build an Ajax-based application while still being able to address changing business requirements. This sample application uses dynamic charts to report the sales quantities of automobile brands within a give time period (in a bar chart), and also lets users select a specific brand to view the sales distribution by area (in pie chart). Further, when the back-end data changes, the updated data is automatically presented to users in these charts.

The sample application, DynamicCharts, has these features:

  • Provides a chart view for car sales of multiple automobile brands.
  • Provides a chart view for drilling down to sales distribution by region for a specific brand.
  • Updates charts displayed in a Web browser automatically at a configurable interval (initially 15 seconds).
  • Provides a flexible layout that enables users to adjust the size of both the master view and the detail view.

The DynamicCharts application is built with these feature pack facilities:

  • Ajax client runtime
  • RPC adapter
  • Web messaging service
  • JSON4J.

Figure 1 illustrates the major functions of the DynamicCharts application, and Figure 2 depicts the application's overall structure and flow.

Figure 1. Functions of DynamicCharts example
Figure 1. Functions of DynamicCharts example
Figure 2. Overall structure and flow of DynamicCharts example
Figure 2. Overall structure and flow of DynamicCharts example

In Figure 2, you can see that the client logic implemented by the Ajax client runtime:

  • Retrieves the data from the facade interface of the chart data service -- which could be an existing service or solution asset -- and is exposed by the RPC adapter.
  • Creates or updates the charts.
  • Handles the events triggered by users and by the Web messaging service.

The invocations from client to RPC adapter are all based on JSON RPC, and the returned data is encapsulated in JSON objects, which can be parsed on the client side very quickly. The chart data updater simulates other applications or services that will update the chart data under certain circumstances, publishing the data change event to clients through the WebSphere Application Server Service Integration Bus (SIBus) and the Web messaging service. Both the chart data service and the chart data updater depend on the chart data accessor to load data from or store data to a data store. (For the purpose of this article, the chart data accessor in the sample application does not connect to an actual data store.)

The next sections will walk you through the process to create the DynamicCharts application. The major steps involved will be to:

  1. Import essential components
  2. Create the chart application using the Dojo Toolkit
  3. Expose ChartService to JavaScript clients via the RPC adapter
  4. Publish data updates to the Web browser with Web messaging

The entire sample application, including WAR and source files, and included with this article for you to download and deploy.


Import essential components

  1. Create a Dynamic Web Project and EAR named "DynamicCharts" in your development environment (meaning Eclipse or Rational Application Developer). Figure 3 shows the project directory structure.
    Figure 3. DynamicCharts project directory structure
    Figure 3. DynamicCharts project directory structure
  2. If you are using Eclipse, import the Ajax client runtime and utility JARs to the WebContent folder.
  3. Implement a set of Java™ classes in the dataservice package.
  4. Create the dynamic-chars.html page.

If you’re using Rational Application Developer V7.5 or later, then you don’t have to explicitly import the Ajax client runtime and Web 2.0 utility JARs, because they will be available in your project when you enable Web 2.0 in Project Faces.

If you’re using Eclipse to create this sample application, a few more steps will be needed:

  1. Copy the ajax-rt_1.X folder from the Web 2.0 feature pack installation root directory (usually <app_server_root>/web2fep) to the WebContent folder of your newly created project (Figure 4).
    Figure 4. Ajax client runtime
    Figure 4. Ajax client runtime
  2. Locate these five JAR files under the optionalLibraries folder in the Web 2.0 feature pack installation root directory and copy them to the WebContent/WEB-INF/lib folder of your project (Figure 5):
    • commons-logging-1.0.4.jar
    • RPCAdapter.jar
    • RPCAdapter-annotation.jar
    • retroweaver-rt-2.0.jar
    • webmsg_applib.ja
    Figure 5. Web 2.0 utility JARs
    Figure 5. Web 2.0 utility JARs

When the required libraries have been imported into your project, you can begin with your application code.


Create the chart application using the Dojo Toolkit

The Dojo Toolkit is a powerful, flexible, modular, open source Ajax software development kit that enables you to easily build dynamic capability into Web pages. The Web 2.0 feature pack incorporates Dojo Toolkit 1.1 and IBM extensions, such as the Ajax client runtime. In this section, you will see how easy it is to use the Dojo Toolkit to implement a chart page that has user interactions and back-end services.

  1. Create an HTML page and load the base Dojo script (ajax-rt_1.X/dojo/dojo.js) with the <script/> tag in the head section. This provides the core functions of Dojo and as well as the access to all other Dojo facilities.
  2. Import the Dojo styles within the <style/> tag and declare the Dojo packages that will be referred to on this Web page with dojo.require(…), as shown in Listing 1.
    Listing 1. Declaring Dojo components and themes
    <style type="text/css">
        @import "ajax-rt_1.X/dojo/resource/dojo.css";
        @import "ajax-rt_1.X/dijit/themes/tundra/tundra.css";
        @import "dynamic-charts.css";
    </style>
    
    <script type="text/javascript" src="ajax-rt_1.X/dojo/dojo.js" 
        djConfig="isDebug: false, parseOnLoad: true, usePlainJson: true"></script>
    
    <script type="text/javascript">
        dojo.require("dojox.charting.Chart2D");
        dojo.require("dijit.layout.BorderContainer");
        dojo.require("dijit.layout.ContentPane");
        dojo.require("dojo.rpc.JsonService");
        dojo.require("dojox.cometd");
        dojo.require("dojox.charting.themes.PlotKit.orange");
    </script>
  3. After that, define the page layout in the body section of the HTML file (Listing 2):
    • The Dojo layout widget dijit.layout.BorderContainer is used here for the page layout, split into two dijit.layout.ContentPanes, one for the car sale chart and the other for the distribution chart.
    • The splitter attribute of the second dijit.layout.ContentPane is set to true, which enables the user to change and adjust the widths of those two regions.
    • In each region, one or two <div> tags are embedded as the nodes where you will create a chart or radio button group.

    Be aware that the original dijit.layout.SplitContainer has been deprecated in Dojo 1.1 and that dijit.layout.BorderContainer is introduced as a replacement.

    Listing 2. Defining the chart page layout
    <div dojoType="dijit.layout.BorderContainer" design="sidebar" id="main">
        <div dojoType="dijit.layout.ContentPane" region="center" id="sale_pane">
            <p>Car Sale</p>
            <div id="car_sale_chart"></div>
        </div>
        <div dojoType="dijit.layout.ContentPane" 
            region="trailing" splitter="true" id="distribution_pane">
            <p>Choose a brand to view sale distribution by area</p>
            <div id="brand_picker"></div>
                <div id="distribution_by_area"></div>
            </div>
    </div>
  4. You are now ready to work out the JavaScript code. The JavaScript functions to be implemented are summarized in this table:
    FunctionTrigger function/eventTask description
    init()Page onload eventCall getSaleData() and register Web messaging handler
    webmsgHandler(…)Web messaging serviceProcess event triggered by Web messaging service
    getSaleData()init()Register JSON RPC handler and loading sale data
    showCarSale(…)getSaleData()Parse returned sale data and call functions to make charts
    makeSaleChart(…)showCarSale()Create sale chart
    makeBrandPicker(…)showCarSale()Create brand radio group and register onclick handler
    brandPickerHander()User’s actionIdentify selected brand and call functions to make charts
    getDistributionData(…)brandPickerHander()Register JSON RPC handler and loading distribution data
    makeDistributionChart(…)getDistributionData(…)Create distribution chart

    Next, you need to load and parse the car sales data from the back-end service. The JavaScript fragment in Listing 3 illustrates how to invoke the chart data service through the JSON RPC call and RPC adapter. You just need to create a Dojo JSON service instance with the given URL exposed by RPC adapter.

    The first parameter:

    /DynamicCharts/RPCAdapter/jsonrpc/ChartDataService/getCarSale

    means to call the getCarSale() method of the ChartDataService class (this will be explained more later) and then register the callback function showCarSale(...) to the JSON service instance, where the returned JSON-formatted data is parsed, and the brand and quantity data are put to arrays respectively.

    There is another option to perform a JSON RPC call -- using the Dojo XMLHTTPRequest wrapper (dojo.xhr) -- but that requires more coding and is not as straightforward as what is shown in Listing 3.

    Listing 3. Loading and parsing of the car sale data
    // Retrieve the sale data via JSON RPC invocation and make
    // the charts.
    function getSaleData() {
        // Call the json service to retrieve the car sale data
        var json_svc = new dojo.rpc.JsonService(
            "/DynamicCharts/RPCAdapter/jsonrpc/ChartDataService/getCarSale");
        json_svc.getCarSale().addCallback(showCarSale);
    }
    
    // Parse the sale data and create the sale chart and the brand picker
    // function showChart(data, ioArgs) {
    function showCarSale(sale_data) {
        // Parse the data returned from the server
        var sale_brands = new Array();
        var sale_quantities = new Array();
    for (var i=0;i<sale_data.length;i++) {
            sale_brands[i] = {value:(i+1), text:sale_data[i].brand};
            sale_quantities[i] = sale_data[i].quantity;
        }
    	
        // Make the auto sale chart
        makeSaleChart(sale_brands, sale_quantities);
    	
        // Make the brand picker
        makeBrandPicker(sale_brands);
    }
  5. Once the chart date is loaded and parsed, the makeSaleChart function will be invoked to create the sales chart (Listing 4). The Dojo Chart2D object usually consists of four parts: theme, plot, axis and series (data). The addPlot call determines what types of charts you’re going to produce. There are a variety of plot types available. The most commonly used are lines, bars, columns, areas, grid, markers, pie, stacked, and so on. Here, "Columns" is used as the vertical bar chart for the car sales. Both addPlot and addAxis functions take two parameters: a name and an argument array. The addSeries function accepts additional parameter: an array of data series.
    Listing 4. Creating the car sales chart
    // Create the sale chart
    function makeSaleChart(brands, quantities) {	
        if (sale_chart == undefined) {
            // Make the sale chart for the first request of a given user
            sale_chart = new dojox.charting.Chart2D("car_sale_chart");
            sale_chart.setTheme(dojox.charting.themes.PlotKit.orange);
            sale_chart.addPlot("default", {type:"Columns", gap:2});
            sale_chart.addAxis("x", {labels:brands});
            sale_chart.addAxis("y", {vertical:true, includeZero:true, max:50});
            sale_chart.addSeries("Auto Sale", 
                quantities, {stroke:{color:"black"}, fill:"lightblue"});
            sale_chart.render();	
        }
        else {
            // Update the sale chart
            sale_chart.updateSeries("Auto Sale", quantities);
            sale_chart.render();			
        }
    }

    The brand picker radio group is created in Listing 5, based on the returned brands while making the sales chart above.

    Listing 5. Creating the brand picker
    // Create the brand picker
    function makeBrandPicker(brands) {
        var picker = dojo.byId("brand_picker");
        var pickerNode = dojo.byId("picker_node");
        if (pickerNode == undefined) {
            pickerNode = document.createElement("div");
            dojo.attr(pickerNode, "id", "picker_node");
            for (var i=0;i<brands.length;i++) {
                var option;
                // Different code for IE and FF respectively
                if (dojo.isIE) {
                    option = document.createElement("<input name='auto_brand'>");
                }
                else {
                    option = document.createElement("input");
                    dojo.attr(option, "name", "auto_brand");
                }
                // Create the radio option
                dojo.attr(option, "type", "radio");
                dojo.attr(option, "id", brands[i].text);
                dojo.attr(option, "value", brands[i].text);
                dojo.attr(option, "dojoType", "dijit.form.RadioButton");
                // connect onclick to the picker handler
                dojo.connect(option, "onclick", brandPickerHandler);    
                pickerNode.appendChild(option);
                // Create the label
                var lbl = document.createElement("label");
                dojo.attr(lbl, "for", brands[i].text);
                var txt = document.createTextNode(brands[i].text);
                lbl.appendChild(txt);
                pickerNode.appendChild(lbl)
                var nl = document.createElement("br");
                pickerNode.appendChild(nl);
            }
            picker.appendChild(pickerNode);
    	}
        else {
            // if the picker node exists, just refresh the selection
            brandPickerHandler();    
        }
    }

    There are only general HTML DOM (Document Object Model) operations in the makeBrandPicker function. The only thing to be aware of is whether the brandPickerHander function is registered as the onclick handler using dojo.connect, which will locate the user selected brand and trigger the creation or update of the distribution chart, as shown in Listing 6.

    Listing 6. Processing brand selection event
    // Brand picker event handler
    function brandPickerHandler() {
        // Find out the selected brand
        var pickerNode = dojo.byId("picker_node");
        var children = pickerNode.childNodes;
        var selected_brand;
        for (var i=0;i<children.length;i++) {
            if (children[i].checked != undefined && children[i].checked == true) {
                selected_brand = children[i].value;
                // Retrieve the updated distribution data and refresh the distribution
                // chart based on the selected brand
                getDistributionData(selected_brand);
                break;
            }
        }
    }
  6. The loading of the distribution data and the creation of the distribution chart are similar to those of the sales data and chart, except that the plot type Pie is used, as shown in Listing 7.
    Listing 7. Loading the distribution data and creating the distribution chart
    // Retrieve the distribution data via JSON RPC invocation and 
    // make the distribution chart.
    function getDistributionData(brand) {
        // Call the json service to retrieve the distribution data
        var json_svc = new dojo.rpc.JsonService(
            "/DynamicCharts/RPCAdapter/jsonrpc/ChartDataService/getDistributionByArea");
        json_svc.getDistributionByArea(brand).addCallback(makeDistritubtionChart);
    }
    
    // Create the distribution chart
    function makeDistritubtionChart(dist_data) {
        // Parse the distribution data
        var dist_percentage = new Array();
        for (var i=0;i<dist_data.length;i++) {
            var data = dist_data[i]
            dist_percentage[i] = {
            y:data.percent,text:data.region+"("+Math.round(data.percent)+"%)",
            color:data.color};
        }
    
        if (dist_chart == undefined) {
            // Make the distribution chart for the first request of a given user
            dist_chart = new dojox.charting.Chart2D("distribution_by_area");
            dist_chart.setTheme(dojox.charting.themes.PlotKit.orange);
            dist_chart.addPlot("default", 
                {type:"Pie",font:"normal normal bold 6pt sans-serif",fontColor:"white"});
            dist_chart.addSeries("Area Distribution", dist_percentage);
            dist_chart.render();	
        }
        else {
            // Update the distribution chart
            dist_chart.updateSeries("Area Distribution", dist_percentage);
            dist_chart.render();
        }
    }
  7. The last part of the JavaScript implementation is to define the init function that will be called right after the page load. This function takes care of the global initialization, such as initializing the Web messaging servlet, registering the Web messaging handler, and subscribing the /charttopic topic, as well as calling other functions to load the sales data. (More on Web messaging in the next sections.)
    Listing 8. Initializing the Web messaging handler
    // Web Messaging handler.
    function webmsgHandler(msg) {
        if (msg.data == "UPD") {
            // Get the updated sale data from the backend
            getSaleData();
        }
    }
    
    // Perform initialization when loading the page.
    function init() {
        // Use the "tundra" style
        dojo.addClass(dojo.body(), "tundra");
    	
        // Get the sale data from the backend
        getSaleData();
    	
        // Initalize the web messaging client
        dojox.cometd.init("webmsgServlet");
        dojox.cometd.subscribe("/charttopic", window, "webmsgHandler");
    }

Expose ChartService to JavaScript clients via the RPC adapter

The RPC adapter (Web remoting) provides the ability for JavaScript or client-side code to directly invoke server-side logic via a JSON RPC call. That means that POJO methods can be easily invoked by Ajax applications without restructuring the existing implementations for lightweight clients.

Listing 9 shows the Java bean ChartData that will provide the chart data service exposed through the RPC adapter. Two methods are available in this Java class:

  • getCarSale() for retrieving the sales data for all automobile brands.
  • getDistributionByArea(...) for retrieving the distribution data for the selected brand through the chart data access component ChartDataAccessor.
Listing 9. Implementing the chart service
public class ChartData{
	
    private static final Logger logger = Logger.getLogger("dataservice.ChartData");
	
    /**
     * Gets the sale data of all auto brands
     * @return sale data for all brands
     */
    public CarSale[] getCarSale() {
        // Retrieve the sale data with the chart DAO.
        logger.log(Level.INFO, "Retrieving car sale data for all brands.");
        return ChartDataAccessor.getInstance().loadSaleData();
}
	
    /**
 * Gets the distribution data by area for a given auto brand.
 * @param brand
 * @return distribution data for the given brand
*/
    public AreaDistribution[] getDistributionByArea(String brand) {
        // Retrieve the distribution data with the chart DAO.
        logger.log(Level.INFO, "Retrieving distribution data for " + brand + ".");
        return ChartDataAccessor.getInstance().loadDistributionDataByBrand(brand);
    }	
}

To publish these methods to Ajax clients, you need to create the RpcAdapterConfig.xml configuration file in the WebContent/Web-INF folder in the project:

  1. If using Rational Application Developer V7.5, navigate to Project => Services => Expose RPC Adapter Service and you won’t need to manually create the configuration file. Specify <default-format /> to JSON because you want the returned data in JSON format to be processed by JavaScript directly and quickly.
  2. Set the service name and implementation to ChartDataService and dataservice.ChartData respectively, and expose the two methods getCarSale() and getDistributionByArea() in <methods />.

    In addition to defining the exposed methods in RpcAdapterConfig.xml, there is another way to expose the RPC adapter service by having the ChartData class implement the com.ibm.webphere.rpcadapter.SelfBeanInfo interface, and provide the information of exposed methods in the getBeanDescriptorInfo() method.

    Listing 10. Publishing the chart service in RpcAdapterConfig.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <rpcAdapter 
      xmlns="http://www.ibm.com/xmlns/prod/websphere/featurepack/v6.1/RpcAdapterConfig" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <default-format>json</default-format>
          <services>
              <pojo>
                  <name>ChartDataService</name>
                  <implementation>dataservice.ChartData</implementation>
                  <description>The facade for the chart data service.</description>
                  <methods>
                      <method>
                      <name>getCarSale</name>
                          <description>Gets all the car sale data.</description>
                          <http-method>GET</http-method>
                      </method>
                      <method>
                          <name>getDistributionByArea</name>
                          <description>Gets the distribution data.</description>
                          <http-method>GET</http-method>
                          <parameters>
                              <parameter>
                                  <name>brand</name>
                                  <description>a specific brand</description>
                              </parameter>
                          </parameters>
                      </method>
                  </methods>
              </pojo>
          </services>
    </rpcAdapter>
  3. The last step for publishing the chart data service is to configure the web.xml file so that the com.ibm.websphere.rpcadapter.RPCAdapter servlet is exposed under this Web address:
    http://<host>:<port>/DynamicCharts/RPCAdapter/*

    To do this, add the servlet configuration in Listing 11 to the web.xml file.

    Listing 11. Configuring RPC adapter Servlet in web.xml
    <servlet>
        <display-name>RPCAdapter</display-name>
        <servlet-name>RPCAdapter</servlet-name>
        <servlet-class>com.ibm.websphere.rpcadapter.RPCAdapter</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RPCAdapter</servlet-name>
        <url-pattern>/RPCAdapter</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>RPCAdapter</servlet-name>
        <url-pattern>/RPCAdapter/*</url-pattern>
    </servlet-mapping>
  4. You can now test the chart service via RPC adapter. Open these URLs in your Web browser and download the results:
    http://<host>:<port>/DynamicCharts/RPCAdapter/httprpc/ChartDataService/getCarSale
    http://<host>:<port>/DynamicCharts/RPCAdapter/httprpc/ChartDataService/
            getDistributionByArea?brand=BMW

Publish data updates to Web browsers with Web messaging

The Web messaging service connects a browser to the WebSphere Application Server SIBus for server-side event push via a publish/subscribe implementation, making it easy for you to build Web applications with real-time data updates, such as stock price quotes, auction bids, and automatic news updates.

Client/server communication is achieved through an HTTP-based message routing protocol called the Bayeux protocol. Cometd is a Dojo Foundation project to provide implementations of the Bayeux protocol in JavaScript and other languages. The code in Listing 8 uses Dojo Cometd to initialize the Web messaging servlet, subscribe the /charttopic topic, and register the Web message handler at the client side. There is little code that needs to be written for enabling the Web messaging service at the server side, except for some configurations of Web messaging and SIBus. (The deployment instructions in the next section explain how to set the webmsgenabled parameter and create the chartbus SIBus on the application server.

There is also a Web messaging configuration file webmsg.json in the WebContent/WEB-INF of the DynamicCharts project (Listing 12). In this file, busName is set to chartbus. For the purpose of this example, clientCanPublish is set to false because the server-side publish is sufficient here.

Listing 12. Configuring the Web messaging service in webmsg.json
{
    "WebMsgServlet": 
    {  
        "busName": "chartbus", 
        "destination": "Default.Topic.Space", 
        "clientCanPublish": false,
        "longPollTimeout": 30
    }
}

Let’s take a close look at the implementation of the chart data updater and how to publish a server event to clients with the JMS topic connection factory.

The ChartDataUpdater class implements the TimerListener interface CommonJ Timer (see Resources). When the timer expires, the timerExpired method of the ChartDataUpdater object will be run to simulate the chart data updates by other solutions or services and then publish a message to Web clients. To assist in publishing to Web messaging clients, a publishing API is provided in the Web messaging application utility library. Listing 13 demonstrates usage of the publishing API; that is, publishing the message UPD through the Bayeux channel /charttopic encapsulated in BayeuxJmsTextMsg.

Listing 13. Implementing the timerExpired interface for the chart data updater
/**
* Perform the scheduled task at the given interval, implementing 
* the interface of TimerListener.
*/
public void timerExpired(Timer timer) {
    logger.log(Level.INFO, "Entering timer listener.");
    try {
        // Update the data
        logger.log(Level.INFO, "Updating chart data.");
        ChartDataAccessor cda = ChartDataAccessor.getInstance();
        cda.storeSaleData(simulateSaleData());
        cda.storeDistributionData(simulateDistributionData());
        // Notify the clients of the chart data updates
        logger.log(Level.INFO, "Notifying Web browser clients of data updates");
        publisher.publish(new BayeuxJmsTextMsg("/charttopic", "UPD"));
    } catch (PublisherException e) {
        e.printStackTrace();
        logger.log(Level.SEVERE, e.getMessage());
    }
logger.log(Level.INFO, "Exiting timer listener.");
}

The start, schedule, and stop of the chart data updater are done by calling TimerManager of CommonJ Timer (Listing 14).

Listing 14. Implementing the start/stop methods of the chart data updater
/**
* Starts the chart data updater.
*
*/
public void startUpdater() {
    try {
        if (!timerRunning) {
            InitialContext ctx = new InitialContext();
            tmgr = (TimerManager)ctx.lookup("java:comp/env/tm/default");		
            tmgr.schedule(this, 5, UPDATE_INTERVAL);
            timerRunning = true;
            logger.log(Level.INFO, "The chart data updater is started.");
        }
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
        logger.log(Level.SEVERE, e.getMessage());
    } catch (IllegalStateException e) {
        e.printStackTrace();
        logger.log(Level.SEVERE, e.getMessage());
    } catch (NamingException e) {
        e.printStackTrace();
        logger.log(Level.SEVERE, e.getMessage());
    }		
}
	
/**
 * Stops the chart data updater.
 *
 */
public void stopUpdater() {
    if (timerRunning) {
        if (tmgr != null) {
            tmgr.stop();
            logger.log(Level.INFO, "The chart data updater is stopped.");
        }
    }
}

Additionally, you need to get the Publisher instance, initialize ChartDataUpdater with the publisher, and start ChartDataUpdater in the init method of the startup servlet. Furthermore, you need to shut down ChartDataUpdater in the servlet context listener when the servlet context is destroyed (Listing 15).

Listing 15. Implementing lifecycle management of the chart data updater
/* (non-Javadoc)
 * @see javax.servlet.GenericServlet#init()
 */
public void init() throws ServletException {
    // Call the init() of the super class
    super.init();
    // Get and initialize the instance of ChartDataUpdater (pass in the publisher)
    ServletContext servletContext = getServletConfig().getServletContext();
Publisher publisher = (Publisher) servletContext.getAttribute(
        JmsPublisherServlet.PUBLISHER_SERVLET_CONTEXT_KEY);
    ChartDataUpdater cdu = new ChartDataUpdater(publisher);
    cdu.startUpdater();
    // Keep the chart data updater, and clean it up when the context is destroyed 
    servletContext.setAttribute(ChartDataUpdater.UPDATER_KEY, cdu);
}   


/* (non-Java-doc)
 * @see javax.servlet.ServletContextListener#contextDestroyed(ServletContextEvent arg0)
 */
public void contextDestroyed(ServletContextEvent arg0) {
    // Stop the timer when context is destroyed
ChartDataUpdater cdu = (ChartDataUpdater) arg0.getServletContext()
    .getAttribute(ChartDataUpdater.UPDATER_KEY);
    if (cdu != null) {
        cdu.stopUpdater();
    }
}

Finally, put in the servlet configurations for JMS Publisher and Web messaging, and the resource references for CommonJ Timer and the JMS Topic Connection Factory (Listing 16).

Listing 16. Configuring Web messaging in web.xml
<servlet>
    <description></description>
    <display-name>Publisher</display-name>
    <servlet-name>Publisher</servlet-name>
<servlet-class>
        com.ibm.websphere.webmsg.publisher.jndijms.JmsPublisherServlet
    </servlet-class>
    <init-param>
        <description></description>
        <param-name>CONNECTION_FACTORY_JNDI_NAME</param-name>
        <param-value>java:comp/env/jms/ChartPublish</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet>
    <description/>
    <display-name>WebMsgServlet</display-name>
    <servlet-name>WebMsgServlet</servlet-name>
    <servlet-class>com.ibm.websphere.webmsg.servlet.WebMsgServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>WebMsgServlet</servlet-name>
    <url-pattern>/webmsgServlet</url-pattern>
</servlet-mapping>
<resource-ref id="ResourceRef_1224495798546">
    <description></description>
    <res-ref-name>tm/default</res-ref-name>
    <res-type>commonj.timers.TimerManager</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>
<resource-ref id="ResourceRef_1224558884500">
    <description></description>
    <res-ref-name>jms/ChartPublish</res-ref-name>
    <res-type>javax.jms.TopicConnectionFactory</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

You have completed the development of the DynamicCharts sample. The next section explains how you can export the entire WAR file, and how to deploy and run this example.


Download and deploy the example

The DynamicCharts WAR file, including the source code, is provided with this article for download. These files have been verified on both Internet Explorer and Firefox with WebSphere Application Server V6.1.0.13 with PK56881. You must be sure to import all the dependent JAR files and the Ajax runtime prior to deployment.

To install the DynamicCharts example:

  1. Verify that the WebSphere Application Server Feature Pack for Web 2.0 is installed and operating properly.
  2. Enable the Web messaging service:
    1. Log onto the WebSphere Application Server administrative console and navigate to Servers => Application servers. Select the server to which DynamicChartsEAR.ear will be deployed.
    2. Expand Web Container Settings, select Web container transport chains, and then select the WCInBoundDefault transport chain.
    3. Select Web container inbound channel and then select Customer Properties.
    4. Click New and enter webmsgenabled for the name property and true for the value.
    5. Click Apply and then Save to save the repository information.
    6. Restart the application server.
  3. Create and configure the chartbus SIBus:
    1. Log on to the admin console and navigate to Service integration => Buses.
    2. Click New and enter chartbus for the name, and accept all the remaining defaults.
    3. Click Next and then Finish.
    4. Click Bus members under Topology on the chartbus detail page.
    5. Click Add and then select the server where you want DynamicChartsEAR.ear installed. Click Next.
    6. Accept the defaults and click Next, then Next again, and then Finish.
    7. Save the changes to repository.
    8. Restart the application server.
  4. Create the topic connection factory for DynamicCharts:
    1. Log on to the admin console and navigate to Resources => JMS => Topic connection factories.
    2. Select a server level scope.
    3. Click New. Select Default messaging provider and click OK.
    4. Enter DynamicCharts for name, jms/ChartPublish for JNDI name, and chartbus for Bus name, and keep all the remaining defaults.
    5. Click Apply and then click Save to save the repository information.
  5. Install DynamicChartsEAR.ear:
    1. Log on to the admin console and navigate to Applications => Install New Application.
    2. Browse your file system and select DynamicChartsEAR.ear and click Next.
    3. Accept the defaults and click Next, then Next again, and then Finish.
    4. Click Save to save the master configuration.
    5. Start DynamicChartEAR.
    6. Launch this URL: http://<host>:<port>/DynamicCharts/dynamic-charts.html.

Conclusion

The WebSphere Application Server Feature Pack for Web 2.0 provides a full solution for the most common requirements of building Ajax-based applications. This article explained how to create dynamic charts with the Dojo Toolkit, how you can reuse an existing service with the RPC adapter, and how you can integrate other applications and publish data changes to clients with Web messaging and the SIBus. The considerations and tips presented here will help you get a better understanding of the Web 2.0 feature pack so you can quickly and successfully build or enhance your own Ajax-based applications.


Download

DescriptionNameSize
Sample applicationajax_chart_example_code.zip18 KB

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Web development
ArticleID=428815
ArticleTitle=Create a dynamic Ajax-based Web application with the WebSphere Application Server Feature Pack for Web 2.0
publish-date=09232009