Asynchronous JavaScript and XML (AJAX) with Java 2 Enterprise Edition

Asynchronous JavaScript and XML (AJAX) with Java 2 Enterprise Edition

Anyone who has used Flickr, GMail, Google Suggest, or Google Maps will realize that a new breed of dynamic web applications are emerging. These applications look and act very similar to traditional desktop applications without relying on plugins or browser specific features. Web applications have traditionally been a set of HTML pages that must be reloaded to change any portion of the content. Over the past few years, technologies such as JavaScript and Cascading Style Sheet (CSS) have matured to the point where they can be used effectively to create very dynamic web applications that will work on all of the major browsers. This document and the solutions associated with it will detail several techniques that you can use today to enable your web applications to be more rich and interactive like desktop applications.

Introducing Asynchronous JavaScript and XML (AJAX)

Using JavaScript an HTML page can asynchronously make calls to the server from which it was loaded and fetch XML documents. The XML documents may then be used by JavaScript to update or modify the Document Object Model (DOM) of the HTML page. The term Asynchronous JavaScript and XML (AJAX) has emerged recently to describe this interaction model.

AJAX is not new. These techniques have been available to developers targeting Internet Explorer (IE) on the Windows platform for many years. Up until recently the technology was referred to as web remoting or remote scripting. Web developers have also used a combination of plugins, Java applets, and hidden frames to emulate this interaction model for some time. What has changed recently is that the inclusion of support for the XMLHttpRequest object has became ubiquitous in the mainstream browsers across all platforms. The real magic is the result of the JavaScript XMLHttpRequest object. While this object is not specified in the formal JavaScript specification, it is supported by all of the mainstream browsers today. While there are subtle differences with the JavaScript and CSS support among current generation browsers such as Firefox, IE and Safari, they are manageable. If you are required to support older browsers, AJAX may not be the answer for you.

What makes AJAX based clients unique is that the client contains page specific control logic embedded as JavaScript. The page interacts with the JavaScript based on events such as the document being loaded, a mouse click, focus changes, or even a timer. AJAX interactions allow for a clear separation of presentation logic from the data. An HTML page can pull in bite size pieces of data as needed versus reloading the whole page every time a change needs to be displayed. AJAX will require a different server-side architecture to support this interaction model. Traditionally, server-side web applications have focused on generating HTML documents for every client event resulting in a call to the server and the clients would refresh and re-render the complete HTML page for each response. Rich web applications focus on a client fetching an HTML document which acts as a template or container for injecting content into based on client events using XML data retrieved from a server-side component.

Some usecases for AJAX interactions are:

  • Realtime Form Data Validation: Form data such as user ids, serial numbers, postal codes, or even special coupon codes that require server-side validation can be validated in a form before the user submits a form.
  • Auto-Completion: A specific portion of form data such as an email address, name, or city name may be auto-completed as the user types.
  • Master Details Operations: Based on a client event an HTML page can fetch more detailed information on data such as a product listing that enables the client to view the individual product information without refreshing the page.
  • Sophisticated User Interface Controls: Controls such as tree controls, menus, and progress bars may be provided that do not require page refreshes.
  • Refreshing Data on the Page: HTML pages may poll data from a server for up to date data such as scores, stock quotes, weather, or application specfic data.
  • Server-side Notifications: An HTML page may simulate a server-side push by polling the server for event notifications which may notify the client with a message, refresh page data, or redirect the client to another page.

This list is not all inclusive, however, it does show that AJAX interactions allow web applications to do much more than they have traditionally done in the past. While many of these benefits are noteworthy there are some drawbacks to this approach as well:

  • Complexity: Server-side developers will need to understand that presentation logic will be required in the HTML client pages as well as in the server-side logic to generate the XML content needed by the client HTML pages. JavaScript skills are required for the HTML page developers. Over time it will become easier to create AJAX enabled applications as new frameworks are created and existing frameworks evolve to support the interaction model.
  • Standardization of the XMLHttpRequest Object: The XMLHttpRequest is not yet a part of the JavaScript specification which means that the behavior may vary depending on the client.
  • JavaScript Implementations: AJAX interactions depend heavily on JavaScript which has subtle differences depending on the client (see QuirksMode.org for more details on browser specific differences.
  • Debugging: AJAX applications are also difficult to debug because the processing logic is both embedded in the client and on the server.
  • Viewable Source: The client side JavaScript may be viewed by the client by simply selecting "View Source" form an AJAX enabled HTML page. A poorly designed AJAX based application could open itself up to hackers or plagarism.

Frameworks and patterns for AJAX technology are likely to emerge as developers gain more experienced writting applications that use the AJAX interaction model. It is still early to focus on a "one size fits all" framework for AJAX interactions. This document and the associated solutions focus on how AJAX interactions can be supported today by existing Java 2 Enterprise Edition (J2EE) technologies such servlets, JavaServer Pages, JavaServer Faces and the Java Standard Tag Libraries (JSTL).

The Anatomy of an AJAX interaction

Now that we have discussed what AJAX is and what some higher level issues are, let's put all the pieces together and show an AJAX enabled J2EE application.

Let's consider an example, a web application contains a static HTML page or an HTML page generated in JSP technology contains an HTML form that requires server-side logic to validate to form data without refreshing the page. A server-side web component (servlet) named ValidateServlet will provide the validation logic. The graphic below describes the details of the AJAX interaction that will provide the validation logic.

The items below represent the setups of an AJAX interaction as they appear in the graphic above.

  1. A client event occurs.
  2. An XMLHttpRequest object is created and initialized.
  3. The XMLHttpRequest object makes a call.
  4. The request is processed by the ValidationServlet.
  5. The ValidationServlet returns an XML Document containing the result.
  6. The XMLHttpRequest object calls the callback() function and processes the result.
  7. The HTML DOM is updated.
Now let look at each step of the AJAX interaction in more detail.

1. A client event occurs.

JavaScript functions are called as the result of an event. In the case the function validate() may be mapped to a onkeyup event on a link or form component.

  <input    type="text"
            size="20"  
              id="userid"
            name="id"
         οnkeyup="validate();">

The form element above will call the validate() each time a key is pressed in the form field.

2. A XMLHttpRequest object is created and initialized.

An XMLHttpRequest object is initialized and configured.

var req;

function validate() {
    var idField = document.getElementById("idField");
    var url = "validate?id=" + escape(idField.value);
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }
    req.open("GET", url, true);
    req.onreadystatechange = callback;
    req.send(null);
}

The validate() function initializes a XMLHttpRequest object open method requires three arguments which are with a url String of GET or POST represeting the HTTP method to be used, a String for the target URL, and a boolean indicating whether or not the call will be made asynchronously. If an interaction is set as asynchronous (true) a callback fuction must be specfied. The callback function for this interaction is set with the statement req.onreadystatechange =callback;. See the section titled "The XMLHttpRequest object calls the callback() function and processes the result" for more details.

3. The XMLHttpRequest object makes a call.

When the statment req.send(null); is reached the call will be made. In the case of a HTTP get this content may be null or left blank. When the this function is called on the XMLHttpRequest object the call to the URL that was set during the initialization of the object is called. In the case of this example the data that is posted (id) is included as a URL parameter.

Use an HTTP GET when the request is idempotent meaning that two duplicate requests will return the same results. When using HTTP GET method the length of URL including escaped URL parameters is limited by some browsers and by server-side web containers. The HTTP POST method should be used when sending data to the server that will effect the server-side application state. A HTTP POST requires a Content-Type header to be set on the XMLHttpRequest object by using the following statement:

req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("id=" + escape(idTextField.value));

When sending form values from JavaScript you should take into consideration the encoding of the field values. JavaScript includes an escape() function which should be used to ensure localized content is encoded properly and that special charachters are escaped correctly.

4. The request is processed by the ValidationServlet.

A servlet mapped to the URI "validate" checks if the user id is in the user databse or not.

A servlet processes a XMLHttpRequest just as it would any other HTTP request. The example below show a server extracting the id parameter from the request and validating whether or not the parameter has been taken.

public class ValidationServlet extends HttpServlet {
    
    private ServletContext context;
    private HashMap users = new HashMap();
 
    public void init(ServletConfig config) throws ServletException {
        this.context = config.getServletContext();
        users.put("greg","account data");
        users.put("duke","account data");
    }

    public void doGet(HttpServletRequest request, HttpServletResponse  response)
        throws IOException, ServletException {

        String targetId = request.getParameter("id");

        if ((targetId != null) && !users.containsKey(targetId.trim())) {
            response.setContentType("text/xml");
            response.setHeader("Cache-Control", "no-cache");
            response.getWriter().write("
 
 valid"); 
        } else {
            response.setContentType("text/xml");
            response.setHeader("Cache-Control", "no-cache");
            response.getWriter().write("
 
 invalid"); 
        }
    }
}

In this example a simple HashMap is used to contain the users. In the case of this example let us assume the user id "duke" was submitted.

5. The ValidationServlet returns an XML Document.

The user id "duke" is present in the list of user ids in the users HashMap. The ValidationServlet will write a XML document to the response containing an "message" element with the value of "invalid". More complex usecases may require DOM, XSLT, or other APIs to generate the response.

    response.setContentType("text/xml");
    response.setHeader("Cache-Control", "no-cache");
    response.getWriter().write("
 
 invalid"); 

Two things that a developer needs to be aware of is that the Content-Type is set to "text/xml" and the Cache-Control needs to be set to "no-cache". The XMLHttpRequest object will only process requests that are of the Content-Type of "text/xml" and the Cache-Control being set to "no-cache" will keep browsers from locally caching responses for cases where duplicate requests for the same URL (including URL parameters) may return different responses.

6. The XMLHttpRequest object calls the callback() function and processes the result.

The XMLHttpRequest object was configured to call the callback() function when there are changes to the readyState of the XMLHttpRequest object. Let us assume the call to the ValidationServlet was made and the readyState is "4" signifying the XMLHttpRequest call is complete. The HTTP status code of "200" signifies a successful HTTP interaction.

function callback() {
    if (req.readyState == 4) {
        if (req.status == 200) {
            // update the HTML DOM based on whether or not message is valid
        }
    }
}

Browsers maintain an object representation of the documents being displayed (referred to as the document object model (DOM)). JavaScript in an HTML page has access to the DOM and APIs are available that allow JavaScript to modify the DOM after the page has loaded.

Following a successful request, JavaScript code may modify the DOM of the HTML page. The object representation of the XML document that was retrieved from the ValidationServlet is available to JavaScript code using the req.responseXML where req is an XMLHttpRequest object. The DOM APIs provide a means for JavaScript to navigate the content from that document and use that content to modify the DOM of the HTML page. A string representation of the document that was retrieved by calling req.responseText. Now let us look at the how to use the DOM APIs in JavaScript by looking at the following XML document returned from the ValidateServlet.

 <message>
  valid
 </message>

The example above is a simple XML fragment that contains the sender of the message element which is simply the string "valid" or "invalid". A more advanced sample may contain more than one message and valid names that might be presented to the user.

function parseMessage() {
    var message = req.responseXML.getElementsByTagName("message")[0];
    setMessage(message.childNodes[0].nodeValue);
}

The parseMessages() function will process XML document retrieved from the ValidationServlet. This function will call the setMessage() with value of the message element to update the HTML DOM.

7. The HTML DOM is updated.

7. The HTML DOM is updated.

The XMLHttpRequest object was configured to call the callback() function when there are changes to the readyState of the XMLHttpRequest object. Let us assume the call to the ValidationServlet was made and the readyState is "4" signifying the XMLHttpRequest call is complete. The HTTP status code of "200" signifies a successful HTTP interaction.

function callback() {
    if (req.readyState == 4) {
        if (req.status == 200) {
            // update the HTML DOM based on whether or not message is valid
        }
    }
}

Browsers maintain an object representation of the documents being displayed (referred to as the document object model (DOM)). JavaScript in an HTML page has access to the DOM and APIs are available that allow JavaScript to modify the DOM after the page has loaded.

Following a successful request, JavaScript code may modify the DOM of the HTML page. The object representation of the XML document that was retrieved from the ValidationServlet is available to JavaScript code using the req.responseXML where req is an XMLHttpRequest object. The DOM APIs provide a means for JavaScript to navigate the content from that document and use that content to modify the DOM of the HTML page. A string representation of the document that was retrieved by calling req.responseText. Now let us look at the how to use the DOM APIs in JavaScript by looking at the following XML document returned from the ValidateServlet.

 <message>
  valid
 </message>

The example above is a simple XML fragment that contains the sender of the message element which is simply the string "valid" or "invalid". A more advanced sample may contain more than one message and valid names that might be presented to the user.

function parseMessage() {
    var message = req.responseXML.getElementsByTagName("message")[0];
    setMessage(message.childNodes[0].nodeValue);
}

The parseMessages() function will process XML document retrieved from the ValidationServlet. This function will call the setMessage() with value of the message element to update the HTML DOM.

7. The HTML DOM is updated.

The XMLHttpRequest object was configured to call the callback() function when there are changes to the readyState of the XMLHttpRequest object. Let us assume the call to the ValidationServlet was made and the readyState is "4" signifying the XMLHttpRequest call is complete. The HTTP status code of "200" signifies a successful HTTP interaction.

function callback() {
    if (req.readyState == 4) {
        if (req.status == 200) {
            // update the HTML DOM based on whether or not message is valid
        }
    }
}

Browsers maintain an object representation of the documents being displayed (referred to as the document object model (DOM)). JavaScript in an HTML page has access to the DOM and APIs are available that allow JavaScript to modify the DOM after the page has loaded.

Following a successful request, JavaScript code may modify the DOM of the HTML page. The object representation of the XML document that was retrieved from the ValidationServlet is available to JavaScript code using the req.responseXML where req is an XMLHttpRequest object. The DOM APIs provide a means for JavaScript to navigate the content from that document and use that content to modify the DOM of the HTML page. A string representation of the document that was retrieved by calling req.responseText. Now let us look at the how to use the DOM APIs in JavaScript by looking at the following XML document returned from the ValidateServlet.

 <message>
  valid
 </message>

The example above is a simple XML fragment that contains the sender of the message element which is simply the string "valid" or "invalid". A more advanced sample may contain more than one message and valid names that might be presented to the user.

function parseMessage() {
    var message = req.responseXML.getElementsByTagName("message")[0];
    setMessage(message.childNodes[0].nodeValue);
}

The parseMessages() function will process XML document retrieved from the ValidationServlet. This function will call the setMessage() with value of the message element to update the HTML DOM.

7. The HTML DOM is updated.

JavaScript can gain a reference to any element in the HTML DOM using a number of APIs. The recommended way to gain a reference to a element is to call document.getElementById("userIdMessage") where "userIdMessage" is the id attribute of an element appearing in the HTML document. With a reference to the element JavaScript may now be used to may be modify attributes of the element, modify the style properties of element, or add or remove, modify child elements.

One common means to change the body content of an element is to set the innerHTML property on the element as can be seen in the following example.

<script type="text/javascript">
 function setMessage(message) {
     var userMessageElement = document.getElementById("userIdMessage");
     userMessageElement.innerHTML = "<font color=/"red/">" + message + " </font>";
 }
</script>
<body>
<div id="userIdMessage"></div>
</body>

The portions of the HTML page that were affected are re-rendered immediately following the setting of the innerHTML. If the innerHTML property contains elements such as <image> or <iframe> the content specificed by those elements is fetched and rendered as well.

The main drawback with this approach is that the HTML that is set as the body of the into the <div> element body will be hardcoded as string in the JavaScript including other markup like the <font> element. Intermixing presentation with JavaScript code as strings will make a page difficult read and edit.

Another means of modifying the HTML DOM is to dynamically create new elements and append them as children to a target element as can be seen in the following example.

<script type="text/javascript">
 function setMessage(message) {
     var userMessageElement = document.getElementById("userIdMessage");
     var userIdMessageFont = document.getElementById("userIdMessageFont");
     var messageElement = document.createTextNode(message);
     if (userMessageElement.childNodes[0]) {
         // update the elements
         userIdMessageFont.replaceChild(messageElement, userIdMessageFont.childNodes[0]);
     } else {
         // create the new elements
         var fontElement = document.createTextNode("font");
         fontElement.setAtribute("id", "userIdMessageFont");
         fontElement.setAtribute("color", "red");
         userMessageElement.appendChild(fontElement);
         fontElement.appendChild(messageElement);
     }
 }
</script>
<body>
 <div id="userIdMessage"></div>
</body>

The code sample above shows how JavaScript DOM APIs may be used to create an element or alter the element programatically. The JavaScript DOM APIs support in various browsers can differ so care needs to be taken when developing applications.

Final Thoughts

We have seen that there are many possible problems that AJAX interactions can solve. J2EE technology provides a good base to develop and deploy AJAX based applications with APIs for tying in HTTP processing, databases, web services, XML processing and business objects. With a better understanding of this interaction model, today's applications can become more interactive providing a better experience to the end user.

This document described common usecases, technologies involved, and reviewed the anatonmy of an AJAX interaction. Please refer to the various solution entries for more specfic examples.

References

The Apple Developer connection has some good documentation on the XMLHttpRequest object.

The JavaScript DOM bindings defined by the W3C.

A great reference for JavaScript and CSS support in browsers may be found at  http://www.quirksmode.org.

Defintion of AJAX by Jesse James Garrett.


© Sun Microsystems 2005. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值