Technical Article

Creating an AJAX-Enabled Application, a Do-It-Yourself Approach

By Rick Palkovic and Mark Basler, September 2006

Ajax is a combination of existing technologies rather than a technology in itself. It combines, at a minimum, JavaScript, XML, HTML, and their related technologies such as Cascading Style Sheets (CSS) and Document Object Model (DOM).

Ajax techniques can exchange data asynchronously between a client web application and a web or application server, thus making the user experience more responsive. To that end, Ajax-enabled client applications typically use the XMLHttpRequest object to request data from the application server.

Because Ajax relies on several underlying technologies and is not a clearly defined technology itself, there are many ways to implement its functionality. This series of articles uses a single example application to describe several of the most popular and productive approaches, beginning with the most basic. One good source of information about Ajax is the article Ajax Design Strategies. That article provides information about the tradeoffs among various approaches to implementing Ajax.

To get the most out of this article, you should be familiar with the NetBeans IDE and the Java EE 5 tutorial .

The application used in these articles is derived from the Duke's Bookstore application, included in the Java EE 5 tutorial. The application has been extracted from the tutorial for use in this article.

Adding a Pop-Up Balloon Feature

This article is based on the premise that, as a developer, you want to add informational pop-up balloons to books listed in the catalog of Duke's Bookstore. The pop-up balloons will appear when a user's mouse pointer hovers over a catalog entry.

There are several ways to add this feature, of course. The following table compares some alternatives and highlights the tradeoffs. (Similar comparisons can be found elsewhere — at ajax info, for example.)

Technology Pros Cons
Conventional HTML
  • Universal browser compatibility
  • Slow, page swap disorients users
Applet
  • Can use full Java APIs
  • Custom data streaming, graphic manipulation, threading, and advanced GUIs
  • Well-established scheme
  • Code downloading time too big a penalty; too heavyweight a solution for this feature
Adobe (formerly Macromedia) Flash
  • Excels at vector graphics
  • Browser needs a proprietary plug-in
  • Scripting language is proprietary
Java WebStart
  • Very fast response after initial load
  • Disconnected operation is possible
  • Incremental redeployment of downloaded application
  • JDK 1.1 and earlier do not work
  • First-time download time could be significant
DHTML
  • Uses widely deployed technologies (JavaScript, DOM, and CSS)
  • Does not communicate asynchronously (full page refresh required)
DHTML with Hidden iFrame
  • Mimics asynchronous behavior as iFrame loads page in background
  • iFrame may soon be deprecated; W3C recommends use of OBJECT instead
Ajax
  • Uses existing technologies (JavaScript, XHTML, DOM)
  • High level of compatibility between browsers
  • Toolkits and JavaServer Faces components available
  • Quick response; no need to download code or full pages
  • No plug-in required
  • Uses existing developers' skill sets
  • Can be complex to develop and maintain
  • Browser bookmarks and history features can break

After comparing alternative technologies, the balance of pros and cons tilts in favor of Ajax for your application. The arguments against using Ajax — user's loss of context and difficulty in programming — are not objectionable. First, because the pop-up balloons you plan don't persist on the page, your users will be able to return to a bookmarked page without confusion. Second, you plan to use features in the NetBeans IDE that will simplify programming and deployment.

Implementing Pop-Up Balloons With Ajax

Your first approach to implementing the feature is to add the Ajax-based pop-up balloons to your application directly. You write supporting JavaScript and CSS files and fulfill the Ajax request by writing a servlet in Java. You integrate these files with the existing JavaServer Pages (JSP) files in the NetBeans project. This approach is the most direct model for adding Ajax to a legacy application. However, it might not be the easiest to program.

To understand the architecture of this approach, consult the brief discussion in Ajax Design Strategies.

Downloading and Installing the Tools

To follow along with remainder of this article, you will need to download the example application and the necessary tools. If they are not installed on your local system, download and install them now, using the installation instructions on the download pages.

  • Duke's Bookstore project

In the rest of this article, the installed location of your GlassFish application server will be denoted by server, and the installed location of the Duke's Bookstore project will be denoted by project. Your installation directory trees should look like the following figure. In this case, the value of server would be C:/glassfish, and the value of project would be C:/bookstore.

Figure 1: Server and Project Installation Directories

Setting Build Properties

You must edit the file that defines build properties to customize it for your environment. These build properties are used by the ant scripts that build the project.

To edit the build.properties file:

  1. In a text editor, open the file project /examples/bp-project/build.properties
  2. Follow the editing instructions in the file. Specifically, edit the following lines, specifying the path to your GlassFish installation and the path to your project folder:

javaee.home= server

javaee.tutorial.home= project

for example:



javaee.home=C:/glassfish 
javaee.tutorial.home=C:/bookstore                       

Editing these two lines should be sufficient for most default installations. The following table shows how to set other values, if necessary.

Property Name Description Examples
javaee.home The installation directory of the GlassFish application server c:/glassfish
javaee.server.name Host name of the the GlassFish application server localhost
javaee.server.port The port number you chose while installing the GlassFish application server 8080
javaee.server.username The administrator username specified while installing the GlassFish application server admin
javaee.server.passwordfile The path to a file containing the administrator password for the GlassFish application server. The password file needs to be in the following format:

AS_ADMIN_PASSWORD= admin-password

Where you will replace admin-password with the admin password for the GlassFish application server.

c:/bookstore/examples/common/admin-password.txt
javaee.adminserver.port The port number you chose while installing the GlassFish application server 4848
proxy.host The host name of your HTTP proxy server, if the GlassFish application server is behind a firewall. Leave blank otherwise. myproxy.mydomain
proxy.port The port number of your HTTP proxy server, if the GlassFish application server is behind a firewall. Leave blank otherwise. 8080

Preparing the Server and Database

Next, start the server's database and domain to prepare it for the application deployment.

  1. Open a command shell. Start the GlassFish javadb database by typing the following command:
    
          
     server 
     /bin/asadmin start-database 
         
         
  2. Start a domain by typing the following command:
    
    
     server
    /bin/asadmin start-domain
                        
                    

Next, create database tables. This step is needed to set up the database and jdbc resource in javadb and the GlassFish server.

  • Create database tables by typing the following commands:
    
           
      cd  
      project
      /examples/web/bookstore2                         
    ant create-tables   
    
    

Starting the NetBeans IDE and Registering the GlassFish Server

To register the GlassFish server so that it can be used with the NetBeans IDE:

  1. Start the NetBeans IDE.
  2. From the menu bar, choose Tools > Server Manager. The Server Manager window opens.
  3. In the Server Manager window, click Add Server. The Add Server Instance window opens.
  4. In the Add Server Instance window, select the Sun Java System Application Server instance. Click Next.
  5. Browse to specify the platform location where the GlassFish server is installed (the value of server). The radio button Register Local Default Domain is selected by default. The domain shown will be the one you started from the command line:

    localhost:4848(server/domains/domain1)

    Click Next.

  6. Enter the administrator username and password. The default values are Username: admin Password: adminadmin
  7. Click Finish. In the Server Manager window, select the Sun Java System Application Server. The Server Manager window looks like the following figure.
  8. Click Close to dismiss the Server Manager window.

Opening the Bookstore Project in the NetBeans IDE

Next, open the project in the NetBeans IDE:

  1. From the NetBeans toolbar, choose File > Open. The Open Project window opens.
  2. Navigate to project /examples/web/bookstore2. Select the bookstore2 project folder and click Open Project Folder. The IDE opens the project folder and selects bookstore2 as the main project. Note that the bookstore project is also opened because bookstore2 depends on many of the files in bookstore.
  3. If the IDE flags the bookstore project and alerts you that references need to be resolved:
    1. Right-click the project and choose Resolve Reference Problems from the pop-up menu.
    2. In the resulting window, click Resolve and navigate to the server /glassfish/lib directory. Select the javaee.jar file and open it. Click Close to resolve the reference and close the window.
  4. If the bookstore2 project also produces an alert:
    1. Right-click on the project name and choose Resolve Missing Server Problem from the pop-up menu.
    2. In the resulting window, select the GlassFish server that you registered previously. Click OK to resolve the reference.

Running the Bookstore Project

You can now build and deploy the bookstore2 project.

In the NetBeans Projects window, the bookstore2 project should be shown in bold type to indicate that it is the main project. If it is not, set it as the main project by choosing Files > Set Main Project > bookstore2.

  • Build and deploy the bookstore2 project by choosing Run > Run Main Project.

The status of the build is shown in the NetBeans Output window. When the build finishes successfully, your browser opens to show the Duke's Bookstore application. Clicking on the Start Shopping link will take you to the catalog page, shown below.

Figure 3: Duke's Bookstore, Catalog Page

Exploring Duke's Bookstore

From the Duke's Bookstore catalog page, shown in the previous figure, you can click one of the book links. Clicking a link opens a new page with detailed information about the book, as shown in the following figure.

Figure 4: Duke's Bookstore, Detail Page

Users would have easier access to this information if it could be displayed in a pop-up balloon when a user rolled over the link in the catalog page. You will now implement this feature with Ajax. In your implementation, the entire page will not need to reload to show the information. Only the information in the pop-up balloon loads when the user mouses over the link. The following figure shows the Ajax-enabled page.

Figure 5: Duke's Bookstore, with Pop-up Balloon

Adding a Pop-Up Balloon to the Bookstore Application

Your first approach to adding the Ajax pop-up balloon to the application is the most basic: you will hand-code a JavaScript ( .js) file and a cascading style sheet ( .css) file for the client. To handle the client requests on the server, you hand-code a Java servlet ( .java). You also edit the project's bookcatalog.jsp file.

To save you time, these files have been provided for you. They are already in the project directory, and can be found at the following locations:

project /examples/web/bookstore2/web/popup.js

project /examples/web/bookstore2/web/popup.css

project /examples/web/bookstore2/web/books/bookstore/bookcatalog.jsp

project /examples/web/bookstore2/src/java/com/sun/bookstore2/dispatcher/PopupServlet.java

Now, examine each of these files to see how they were created.

Writing the JavaScript File

The popup.js file provides the JavaScript functions that cause the pop-up balloon to appear.

To examine the popup.js file in the IDE:

  1. Select the Files view of the project, expand the bookstore2 > web node, and double-click popup.js. The file opens in the NetBeans JavaScript Editor.
  2. From the menu bar, choose View > Show Line Numbers. Refer to the NetBeans Editor view of the file in the following discussion.

The opening lines of the file (lines 1-3) create a component namespace object, bpui. The name is used in the Java Blueprints Solutions Catalog, and stands for “blueprints user interface.” Using the namespace as a prefix is good programming practice because it helps ensure that functions will have unique names. For example, if you simply defined showPopup() as a function instead of bpui.alone.showPopup(), then there could be a conflict with another showPopup() function. The last such function that is defined in a file takes precedence over all earlier functions.

In line 7, you create a bpui.alone object to hold the pop-up balloon.

In line 8, you create a bpui.alone.timeout timeout variable in the object. The timeout is used as follows.

When a user mouses over a book link in the catalog page, a timer begins counting. If the mouse is still hovering over the link after a timeout period of 1000 ms has elapsed, an XMLHttpRequest request is sent to the server. If the server responds with the necessary pop-up balloon data before the timeout has expired, the balloon is hidden until the end of the timeout. If the server is slow and does not respond until after the timeout, one of two conditions applies:

  • The user keeps the mouse pointer over the link, and the balloon pops up when the necessary data is received, or
  • The user moves the pointer out of the link, and the balloon remains hidden even after the server responds. The timer is cleared when the user mouses out, and awaits the next mouseover event.

Line 9 creates a bpui.alone.req object to hold the request.

The function bpui.alone.showPopup() (beginning on line 12) is called when the user mouses over a link. The function sets the location for the pop-up balloon and then sets the timer to begin counting. After the timeout period has elapsed, the bpui.alone.showPopupInternal() function is called.

The function bpui.alone.showPopupInternal() (beginning on 32) initiates the Ajax XMLHttpRequest request.

Because your Ajax implementation will use a servlet to respond to client requests, your popup.js file uses the following line to set the URL:

url="../PopupServlet?bookId=" + escape(bookId);

The servlet mapping is defined in the web deployment descriptor file, web.xml, which is stored in the following location:

project /examples/web/bookstore2/build/web/WEB-INF/web.xml

Note that another line, commented out in popup.js, can be used to set the URL:

// url="../book_lookup.jsp?bookId=" + escape(bookId);

When this line is uncommented, it sets a JSP page as the dispatcher. You enable this line later when you explore the JSP approach. For now, leave the line as a comment.

The function then concatenates the Ajax dispatcher URL with the bookId (line 40) and sets the pop-up balloon's Ajax callback function (line 41).

The statement at line 42 specifies that the XMLHttpRequest object uses a GET method (as opposed to a POST method) to communicate with the server-side component. The url parameter indentifies the URL of the server-side component, which was set to PopupServlet in the previous statement. The parameter true indicates that the communication is asynchronous.

Finally, the function sends the request (line 43).

The callback function ajaxReturnFunction() (beginning on line 46) accepts the server response. The function checks the validity of the request's response by making sure that the ready state is complete ( readyState property equals 4) and the response is OK ( status property equals 200). For details about how to work with Ajax XMLHttpRequest objects, click here.

The function then extracts the document root of the XML response and parses it. The function document.getElementById() (lines 55–56) inserts the information into the appropriate nodes of the DOM in the JSP. Note the innerHTML property, which is used to insert an HTML fragment. Using the innerHTML property to update the DOM avoids the need to create each element in the object individually with conventional DOM API functions.

The last line of the if clause (line 58) sets the value for the visibility style of the pop-up balloon to visible. The initial style is set to hidden in the popup.css file, which is explained in the following section.

The bpui.alone.hidePopup() function (beginning on line 65) is called on mouseout to hide the pop-up balloon and clear the timeout variable.

Writing the CSS File

In the do-it-yourself approach to Ajax described here, you must provide a cascading style sheet ( .css file) that describes the appearance of the pop-up balloon. In this project, the popup.css file describes the layout for the balloon, including its fonts, colors, and dimensions. The bookcatalog.jsp file uses these descriptions to build the pop-up balloon as it inserts content.

To view the popup.css file in the IDE, double-click the bookstore2 > web > popup.css node in the Files window, just as you did for the popup.js file.

The file begins by defining seven class styles that are used to set the pop-up balloon's border widths and colors, its background color, and the margins within which the text content of the balloon appears. The class styles also specify the images used to produce rounded corner effects for the pop-up balloon. In each square corner image, the outside corners are white, and the inside corners are transparent to allow the balloon's border color to show through.

Following these definitions is another class style definition, div.bpui_alone_popup, that is used with the block-level container tag <div>. This class is also used to format the balloon's content.

To learn more about CSS, consult one of the many online resources available, such as W3 Schools.

Editing the JavaServer Pages File

By examining the bookcatalog.jsp file, you learn how the popup.js and popup.css files produce a pop-up balloon.

  1. In the NetBeans Files window, expand the bookstore2 > web > books node and select the bookcatalog.jsp file.
  2. Right-click the file and choose Rename from the context menu. Rename the file bookcatalog_orig.jsp. This file is the original version of the file, which does not produce pop-up balloons.
  3. Select the file bookcatalog_popup.jsp, right-click, and choose Rename from the context menu. Change the name to bookcatalog.jsp.
  4. Double-click bookcatalog.jsp to view the file in the NetBeans Editor.

The original and pop-up versions of the file are nearly identical except for the code between the comment lines at line 28 and line 57:

<!-- BEGIN: popup -->

and

<!-- END: popup -->

The first two lines (29–30) provide the links to the popup.js and popup.css files:



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

<link type="text/css" rel="stylesheet" href="../popup.css" />
             
         

As discussed earlier, the popup.css file provides the presentation layout styles for the pop-up balloon. The code following these links (lines 33–56) makes use of the CSS styles and HTML to draw the balloon and insert content into it.

The remainder of the file is identical to the original bookcatalog.jsp file, with one exception. Embedded in the layout table for the page, in lines 100–104, are event handlers that call JavaScript functions from popup.js when the user mouses over or mouses out of a book title link.



<!-- added event handlers to trigger popup -->

<a href="${url}"

 onmouseover="bpui.alone.showPopup(event, '${bookId}')"

onmouseout="bpui.alone.hidePopup()">

 <strong>${book.title} </strong>

</a>

The following clause triggers the pop-up balloon:

onmouseover="bpui.alone.showPopup(event, '${bookId}')"

The value of ${bookId} determines the data that is returned from the server in response to the Ajax XMLHttpRequest.

The following clause hides the pop-up balloon:

onmouseout="bpui.alone.hidePopup()"

The pop-up balloon's show and hide functions can be placed elsewhere. Here, they are placed directly following code that provides the value for ${bookId}, which the onmouseover() function uses to retrieve book information.

Writing a Servlet to Generate Response

With the JavaScript, CSS, and book catalog JSP files prepared, all you need to implement your Ajax pop-up balloons is a servlet or server-side component to handle the XMLHttpRequest. The most hands-on approach to implementing a dispatcher is to write a servlet.

An example of such a servlet is provided for you at

project /examples/web/bookstore2/src/java/com/sun/bookstore2/dispatcher/PopupServlet.java

View the file in the IDE by opening the bookstore2 > src > java> com > sun > bookstore2 > Dispatcher node and double-clicking PopupServlet.java. The file opens in the NetBeans Java Editor.

Note that nothing in the servlet is unique to Ajax. The servlet composes an XML response to a client request, and is unaware of the asynchronous nature of the request.

The client obtains information for a book by sending a request that contains a bookID. The PopupServlet responds by pulling a Book object from the server-side database, extracting the necessary information, constructing an XML file, and returning the XML file to the client. In the client, the JavaScript callback function, bpui.alone.ajaxReturnFunction(), handles the response.

This file was created in the NetBeans IDE. Therefore, it extends the standard HTTP servlet (line 24):

public class PopupServlet extends HttpServlet {

All requests and responses are forwarded to the method on line 30:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)

In this method, you set the return type:

response.setContentType("text/xml;charset=UTF-8");

You get the response writer from the response itself (line 32), which provides a stream to write the data. Line 33 is from the original bookstore application:

BookstoreMessages messages=new BookstoreMessages();

The messages object contains the data you want to display in the pop-up balloon. The developers of the application used mnemonics to identify parts of each message. For internationalization (i18n) reasons, the mnemonics refer to keys in a properties file. The values of the keys are retrieved and printed. For example, the statement

out.println(messages.getString("Critics"));

finds the following line, which is provided by the locale file stored in the project /examples/web/bookstore/src/com/sun/bookstore/messages/ directory:

{ "Critics", "Here's what the critics say: " },

and prints the phrase "Here's what the critics say: ". Line 56 does exactly that, together with HTML formatting tags and a description from the database that contains the critics' comments.

As part of the request from the client, the bookId of the relevant book is passed in. Using the bookId parameter, the servlet determines the identity of the book to look up.

Because the basic application codes a database object ( BookDBAO) in the servlet context, it is necessary to get the database object from the servlet context in order to retrieve the book information (lines 47 and 48). All of the bookDBAO functions required are a result of the original bookstore application coding. The bookDBAO.getBook(bookId) method returns a book object that contains the necessary data.

After the servlet has obtained the data, it composes a response to the request in the series of out.println() methods (lines 50–66). Note the CDATA prefix in the method calls. For example,

out.println("<title><![CDATA[Book Detail]]></title>");

The CDATA prefix is an XML construct that instructs the parser to ignore any XML code in the character string. The prefix allows the payload of the XML elements to be passed to the client application. The complete message is contained between the output <message> and </message> tags.

Generating Server Response with JSP

You can generate XML server response with a JSP page rather than a servlet. If you are familiar with JSP programming, you will probably find it much quicker to develop a JSP page than a servlet.

JSP pages show their value in speed of programming, particularly in the NetBeans IDE. If you start your project in the NetBeans IDE, JSP pages are deployed as soon as they are saved, eliminating redeployment and repackaging time. In addition, you can take advantage of the tag library that is associated with JSP technology but is unavailable in a servlet.

The JSP page that generates the response is named book_lookup.jsp. It is stored in the project /examples/web/bookstore2/web directory. The XML messages that are returned by this JSP page and PopupServlet described earlier are exactly the same. They are just two ways of generating the same XML response.

Open the file for viewing in the NetBeans Editor by expanding the bookstore2 > web > node in the Files window and double-clicking the book_lookup.jsp file.

The file contains two scriptlets that provide presentation logic, along with JSP code for the presentation itself. Separating the two activities provides modularity.

The two scriptlets in the file are demarcated by <% and %> symbols (lines 9–28 and 40–53). JSP presentation code lies between the scriptlets (lines 30–38).

Note that in the JSP code, no message manipulation is required. Message manipulation is handled by the <fmt> tag library. This code is taken directly from the bookdetails.jsp file, in the project /examples/web/bookstore2/web/books directory. Users who click a book link are routed to a details page. The information on the details page is much like that shown in the pop-up balloon, and the code from the details page is reused for the pop-up balloon.

In summary, if you already have the JSP file for the details page, you do not need to write a servlet to generate the XML response. Instead, you can use another JSP file to generate the response, using existing code to describe the presentation, and taking advantage of the <fmt> tag libraries to format the displayed response.

Using the book_lookup.jsp File

The popup.js file determines whether to use PopupServlet or book_lookup.jsp to serve the client XMLHttpRequest. To enable book_lookup.jsp:

  1. View bookstore2 > web > popup.js in the NetBeans Editor.
  2. Remove comments from line 38 so that it reads as follows:

    url="../book_lookup.jsp?bookId=" + escape(bookId);

  3. Comment out line 40 by inserting initial slashes so that it reads as follows:

    // url="../PopupServlet?bookId=" + escape(bookId);

  4. Run the project by choosing Run > Run Main Project.

Your project builds, deploys, and runs with results identical to those you saw when you used PopupServlet.java.

Summary

In this article, you learned how to hand-code an Ajax feature into a web application that was developed in the NetBeans IDE. You installed and configured the tools you needed to develop and deploy the application: the NetBeans IDE and the GlassFish application server.

You learned how to code the popup.js, popup.css, and bookcatalog.jsp files in the client to generate an XMLHttpRequest request object. You learned how to write a servlet, deployed on the GlassFish server, that can generate a response to the request.

You then learned how to specify a JavaServer Page on the server instead of a servlet to generate a response.

Next Steps

In the next article in this series, you will use Dojo toolkit libraries to implement the pop-up balloon Ajax feature.

References