Ajax Programming with BEA Workshop

by Gary Horen
03/05/2008

Abstract

To develop client-centric Ajax applications, such as those that use the Dojo Toolkit, you need a JavaScript editor, a JavaScript debugger, and a message inspector to display the sequence of exchanges between client and server.

This article shows how to install and use a free JavaScript editor and debugger from Aptana, Inc., in BEA Workshop. It also shows the use of a message inspector in the Firebug plug-in, an extension for Firefox.

Tools for Client-centric Ajax Programming

The set of tools that a developer needs for Ajax is largely dictated by the chosen programming model. See my earlier article Exploring Ajax Runtime Offerings for a discussion of that topic. Since a client-centric runtime (like Dojo) is largely a library of JavaScript APIs, the developer needs at least a JavaScript editor and debugger.

Generally, a client-centric runtime is completely independent of the server-side technology, and the developer chooses the format of asynchronous (that is, Ajax) messages that pass between them. Another tool that's very important for this programming model is a message inspector that can display a sequence of exchanges between the client and the server at any point in the lifetime of the Ajax page.

This article shows how to install and use a free JavaScript editor and debugger from Aptana, Inc., in BEA Workshop. It also shows the use of a message inspector in the Firebug plug-in, an extension added to Firefox. It will be apparent to the reader that each of these toolkits offers features that go well beyond the scope of this article. I hope this introduction will encourage you to explore them further.

The Sample Application

The sample application is a simple Ajax data grid. Click the Load table from button, and the program will retrieve a datastream from http://dev2dev.bea.com/2008/03/SakiData.json, in JSON (JavaScript Object Notation) format, which is used to load the empty data grid, without refreshing this page. See An Introduction to JSON for an introduction to the notation.

This version of the sample application has one method of serving the data available to it: a stream of JSON coded in a static file here. At the end of this article you will find a Workshop project available for download, which serves both the static data file, and a stream dynamically generated by a .jsp, which shows how the same data can be easily serialized out of server-side Java objects. In this code, I use an open-source library called XStream, originally designed to serialize Java objects to XML, and whose latest release includes a feature that will produce a JSON stream using the same API. It's one of a number of alternative open-source solutions to the problem of serializing to JSON.

The data grid functionality, and the asynchronous pipe between the browser and server, are provided by the Dojo Toolkit, a free, open-source Ajax runtime.

View the sample application

Installing the Tools

This article demonstrates tooling from two different sources: Firebug, which may be installed into a current version of Firefox by following the instructions here; and the Aptana JavaScript tools, which can be installed into BEA Workshop 10.1 (or any Eclipse 3.2 instance) using the Eclipse Update Manager (Help→Software Updates→Find and Install...) from the update site at http://update.aptana.com/install/3.2/. This article discusses the free version (Community Edition); Aptana offers an upgrade to a Professional Edition, which includes cool features like the JSON Editor and debugging in both Firefox and Internet Explorer, as well as commercial support. The Community Edition supports debugging in Firefox only.

The XHR Traffic Inspector

The Firebug XHR Inspector is a great tool that will show you the history of Ajax (XMLHttpRequest) interactions on the current Web page. If you're reading this article in Firefox and have installed the Firebug plug-in, you can open the Firebug window from the Tools menu (Tools→Firebug→Open Firebug in new window). Click the Net tab, click XHR, and then click the button to load the data table in the application popup window above.

Figure 2 shows a record of the request to the server for the JSON stream. If you open the request and click the Response tab, Firebug will display the JSON stream that was served to the browser (see Figure 3). In a minute, we'll see in the debugger how the data gets loaded into the data grid widget.

XHR message history
Figure 2. XHR message history

JSON response to XHR request
Figure 3. JSON response to XHR request

JavaScript Debugging

Now let's look at the Aptana editor/debugger. Firebug provides a debugging tool, and, in fact, the Aptana debugger is dependent on Firebug's underlying mechanism. The advantage of using the Aptana tool is that you can edit and debug in the same window, using the Eclipse UI, in the same way you're used to being able to seamlessly switch back and forth between these tasks in Eclipse when you work with Java.

I'll demonstrate the debugger using the BEA Workshop project downloadable below, deployed on WebLogic Server, because using the debugger in conjunction with server-side code that you are developing will probably be the most common use case. Also, there's a bit of special setup that you need to do to make the debugger understand the structure of a WTP dynamic Web project, and I'll talk about some best practices you can adhere to, to make sure that the tools work well with your application code.

Download and import DojoWebProject.zip into a workspace using BEA Workshop 10.1, with the Aptana tools installed as described above. (Use the Project Import wizard at File→Import... General→Existing Projects into Workspace, and then click the Select Archive File radio button.) This project contains the text of this article (AjaxProgrammingWithWorkshop.html), release 1.0.2 of the Dojo Toolkit, the standalone Ajax application in Saki_table.html, the static JSON stream in SakiData.json, and SakiData.jsp to show how to render the same data dynamically. It should be deployed to WebLogic Server 10.0 (for this example I used the wlserver_10.0/samples/domains/workshop_10.1 domain) in my Workshop 10.1 BEA Home directory.

Important: Since much of the Dojo code doesn't pass the various validations done in the IDE, you should open the server definition for the project (double-click the entry in the Servers view in the J2EE perspective) and check Ignore project compilation errors when publishing (see Figure 4) to make sure that spurious validation errors don't prevent deployment.

Ignore project compilation errors when publishing
Figure 4. Ignore project compilation errors when publishing

Coding practices

Let's take a look at how the JavaScript and JSP code is constructed. The stand-alone Web page can be seen in Figure 5 below. Note that, except for the dojo.require() calls, there's no JavaScript code in the JSP page. It's all in a separate file ( Saki_table.js in the project). The reason for this is that in a JSP page the relationship between a given line number in the source file and the same line in the rendered HTML is not straightforward, because the server compiles the JSP file into a Java class, which then renders HTML into the browser. Since the JavaScript debugger is unaware of Java EE, it has no understanding of this mismatch, and therefore will not be able to find breakpoints in running JavaScript code if they're specified in terms of the JSP source.

The way to get around this disconnection is to place all JavaScript that you care about debugging into .js files, the references to which must be resolved by the browser (that is, with the <script> tag), not by the JSP compiler. (Pulling JavaScript code into a JSP page with <%@ include file="path" %> or <jsp:include page="path"/> will put you into the same situation as if you placed the code in the JSP source itself: The latter two methods include the JavaScript before the page is rendered, and the first one will cause the browser to request it from the server after the page is rendered.)

Also, watch out for a pitfall commonly experienced by beginning JavaScript programmers who have lots of experience with XML: The <script> tag must be closed with </script>, never with the <script src="mumble..."/> form. Using the latter will cause Dojo to fail to load and the Web page to behave in all kinds of unpredictable and confusing ways.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

        <title>Saki Table</title>

        <meta http-equiv="Content-Type" CONTENT="text/html;charset=utf-8"></meta>

        <style type="text/css">

                @import "dojo-release-1.0.2/dojox/grid/_grid/Grid.css";

                body {

                        font-size: 0.9em;

                        font-family: Geneva, Arial, Helvetica, sans-serif;

                }

                .heading {

                        font-weight: bold;

                        padding-bottom: 0.25em;

                }

                                

                #grid {

                        border: 1px solid #333;

                        width: 35em;

                        height: 30em;

                }

        </style>

        <script type="text/javascript" src="dojo-release-1.0.2/dojo/dojo.js" djConfig="isDebug:false, parseOnLoad: true"></script>

        <script type="text/javascript">

                dojo.require("dojox.grid.Grid");

                dojo.require("dojox.grid._data.model");

                dojo.require("dojo.parser");

        </script>

         
                              
<script type="text/javascript" src="Saki_table.js"></script>

</head>

<body>

<div class="heading">Sample Dojo application: loads JSON data into dojox.grid.Grid</div>

<input type="button" value="Load table from" onclick="populateTable();" />

<input id= "targetURL" type="text" size=60 value="http://localhost:7001/DojoWebProject/SakiData.json"/>



<div id="grid" dojoType="dojox.Grid" model="model" structure="layout"></div>

</body>

</html>



                            
Figure 5. Saki_table.jsp

Figure 6 shows our JavaScript, in the file: Saki_table.js.

 // Initial setup (runs when page loads)                

 // data grid layout: 

 // a grid view is a group of columns

 var view1 = {

        cells: [[

      {name: 'Character', width: "150px"}, 

      {name: 'Appears in Saki story', width: "300px"}

        ]]

 };

 // a grid layout is an array of views.

 var layout = [ view1 ];

 

 // the model will contain the data to be displayed in the view

 // This model object is connected when the grid is defined 

 // (see Saki_table.html).   It contains no data until the request 

 // is issued to the server in populateTable().

 model = new dojox.grid.data.Table(null, null);



 // Process the response to the asynchronous request

 function handleResponse(serverDataStream, ioArgs)

 {

        var unmarshaledData = eval("(" + serverDataStream + ")");

        if (unmarshaledData.response.type == "data") {                                  // normal response

                model.setData(unmarshaledData.response.tableContents);          // populate the model object with data; grid will display

        }

        else 

        {

                alert(unmarshaledData.response.message);          // application-detected error

        }

 }



 function handleError()

 {

        // system-detected error

 }



 // Issue an asynchronous request to the server for data.

 function populateTable()

 {

        var targetURL = dojo.byId("targetURL").value;   // get URL entered by user

     dojo.xhrGet({

         url: targetURL,

         load: handleResponse,

         error: handleError

     });

 }

Figure 6. Saki_table.js

Let's look quickly at the .js file (Figure 6 above) before we start the debugger:

  • The code outside the function body is invoked when the .js file is loaded into the page; it does the initial setup and defines a couple of page-scoped JavaScript variables. This code will work the same way whether the file is pulled into an HTML page or a JSP; the Workshop project below contains both.
  • The method populateTable() obtains the URL from the input field, and submits an asynchronous request to the server, through Dojo, to get the data. It specifies the handleResponse() method as the callback, which Dojo will invoke when the server response arrives.
  • handleResponse() calls the built-in JavaScript function eval() on the data stream returned from the server. eval() unmarshals the JSON into a tree of JavaScript objects, the structure of which we will look at in the Variable view of the debugger below.


Configuring and using the debugger

Before debugging, we need to deploy the project to WebLogic Server. My advice is to use Run As→Run on Server to deploy for browser-side debugging; in my experience, the Eclipse framework sometimes gets confused if two debugging sessions (for example, a JSP or Java debugging session, and a JavaScript one) are active at the same time.

After the Web application is deployed, raise the Debug dialog, and select Web Browser→Firefox to configure the debugger.

A WTP dynamic Web project expects by default that the developer will put Web files in the project-root/WebContent directory, which is elided from the URL submitted in an HTTP request. The default configuration for the Aptana debugger makes no such assumption; it's not aware of WTP project structure. So, you have to specify a folder-to-URL mapping in the debugger configuration to show the debugger how to do the translation. In the Debug dialog, map the Server path to elide the WebContent directory, as show in Figure 7.

Mapping Web Server Paths
Figure 7. Mapping Web Server paths

Then, in the Main tab of the Debug dialog, configure the debugger session to launch a specific page (to which you can browse in the project), using the base URL of the server, and check Append project name (see Figure 8).

Debugger launch settings
Figure 8. Debugger launch settings

At this point we can launch the debugger. It will bring up an instance of Firefox, into which the Aptana debugger extension has been loaded. Then, we put a breakpoint at the first line of the handleResponse() function in Saki_table.js.

When the breakpoint fires (Figure 9), you can see the call stack in the Debug tab and the variable tree in the Variables tab. The Variables view is opened to inspect the array of arrays of strings contained in unmarshaledData.response.tableContents, which is about to be passed to the Grid's data model.

Workbench window in Debugger perspective
Figure 9. Workbench window in Debugger perspective (click the image for a larger version)

Note the debugger statement in that method. Sometimes the debugger gets out of synch with the browser, and breakpoints set in the editor UI don't fire. When this happens, the easiest workaround usually is to place a debugger statement in the file, which causes a breakpoint when it's interpreted. From that point, variable viewing and instruction stepping work fine.

Conclusion

This has been a quick and by no means exhaustive look at some tooling that you can use in conjunction with BEA Workshop to help you with client-centric Ajax development. Both tools shown contain many more features, which I'll leave the reader to explore further.

JavaScript debuggers, like the runtime frameworks themselves, are not always perfect. Breakpoints that fail to fire in the debugger continue to be an intermittent problem—do a Web search for "missing breakpoint Firebug" to see. In my experience, it's usually a problem in the Firebug layer (on which the Aptana debugger depends, and which itself depends on the browser's JavaScript implementation). Placing a debugger statement in the code almost always gets around this. Imperfections in tools like these don't mean that they are not an essential part of the Ajax programmer's workbench. They are a big step up from calls to alert() and writes to the console, just as they were for Java and C programming. We're still in the early days of serious, widespread JavaScript development. The tools will continue to improve.

References

The products:

Note

The data for the grid was taken from the works of Saki (Hector Hugh Munro), a pre-World War I British satirist, principally an author of short stories, and one of his era's most virtuosic masters of English prose. Click a story title in the data table to read it.

Gary Horen is the Program Manager for Ajax and Languages on the BEA Workshop team