Developing AJAX Applications the Easy Way Blog

Version 2

    {cs.r.title}



              
                        

    Contents
    The Chat Web Page
    Server-Side Java
    Configuring DWR
    The Client-Side Scripting
    Conclusion
    Resources

    AJAX is the buzzword of the moment among web developers, so much so that you could be sick of introductions to AJAX by now (if that's the case, skip down to "The Chat Web Page"). AJAX is a technology that is hotly debated from many angles, but it has stuck because it encapsulates something that is new from a user's perspective. The functionally that is newly available to all web users is "in-page replacement": the ability for a web page to change using data from a web server without totally redrawing itself. This functionality has been around in Mozilla and Internet Explorer for a while, but it is only recently that Safari and Konqueror users have been able to join in.

    It is this ability to have web pages that update dynamically that is changing the way users interact with the web. For example:

                              
    ActivityOld StyleAJAX Style
    Scrolling in a mapping websiteClick on a right arrow to refresh whole page.Drag map area to the right--and watch the map scroll, like Google Maps.
    Looking up a word in a dictionaryEnter the word, and click Submit to see a definition for that word.Begin typing the word, see possible matches as you type and the definitions as soon as you finish typing, like ObjectGraph Dictionary.
    Interacting in online forumType message, click Submit, regularly click "check new messages".Type messages, and wait as new replies appear automatically without needing your interaction. We will create a site like this in this article.
    Filling out form with a number of fieldsVisit a number of pages of a "wizard," getting error messages about invalid fields.Fill out a form that reports on errors as you type, and can dynamically add data (like filling in full address details from a zip code) without needing a slow page refresh.

    AJAX isn't the best acronym in the world: it stands forAsynchronous JavaScript and XML. This does nothing to describe the benefits to a user: the technology behind it does not have to be asynchronous, and the best implementations don't necessarily use XML, either. However, the buzzword has stuck so we are better off going with the flow now.

    The problem for the web developer is that while this is a very attractive way of creating websites, and one where you can get started without a huge amount of effort, there are a number of pitfalls that can make life harder. All browsers have different quirks, so you can easily discover that, for example, you have locked Mac users out of the party.

    DWR, hosted on java.net, is an Java open source library that helps developers to write websites that include AJAX technology. Its mantra is "Easy Ajax for Java." It allows code in a web browser to use Java functions running on a web server as if they were in the browser.

    This article demonstrates the use of DWR to create a multi-user web-based chat site. It demonstrates how simple it is to integrate JavaScript in the web browser with Java on the server. The aim is to have a fully functional system in about 100 lines of code for both the client and the server. The emphasis will not be on fancy graphics or lots of chat features, because that would distract us from the core business of how to write AJAX code without lots of effort.

    The Chat Web Page

    The web page has two parts: one area where you can see the messages that others type, and an input field where you can type messages yourself. Figure 1 shows what it looks like.

    The chat web page
    Figure 1. The chat web page

    The HTML is very simple:

     <p>Messages:</p> <div id="chatlog"></div> <p> Your Message: <input id="text"/> <input type="button" value="Send" onclick="sendMessage()"/> </p>
    

    We'll come to the JavaScript code in a bit, but let's start with the server side. Just how much code do you need for a multi-user web-based chat system?

    Server-Side Java

    We have two classes to do the server-side work. The first is theMessage class that holds a single string entered by the user. The Message also maintains a unique ID as a property. For now, we are going to cheat by using the current time in milliseconds as the ID:

     public class Message { public Message(String newtext) { text = newtext; if (text.length() > 256) { text = text.substring(0, 256); } text = text.replace('<', '['); text = text.replace('&', '_'); } public long getId() { return id; } public String getText() { return text; } long id = System.currentTimeMillis(); String text; }
    

    The constructor does a few simple things: it shortens messages to 256 characters and replaces < with[ and & with _ to prevent abuse. All fairly simple so far.

    The other class in the server is the Chat class that keeps track of the messages sent to the server--also very simple:

     public class Chat { public List addMessage(String text) { if (text != null && text.trim().length() > 0) { messages.addFirst(new Message(text)); while (messages.size() > 10) { messages.removeLast(); } } return messages; } public List getMessages() { return messages; } static LinkedList messages =new LinkedList(); }
    

    And that's it for the server-side code!

    Two of these methods are important from the web browser's point of view: addMessage(), which is called in response to a user typing in the input area, and getMessages(), which is polled from time to time to see if anyone else has said anything.

    Configuring DWR

    Now we need to remote these two methods to the web browser. The first step is to copy dwr.jar into your web app. You can download dwr.jar from its java.net project. Next, you need to configure your app server's web.xml to understand DWR. The standard bit of code looks like this:

     <servlet> <servlet-name>dwr-invoker</servlet-name> <display-name>DWR Servlet</display-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping>
    

    Finally, you need to tell DWR about the chat server you just created. Specifically, you need to tell it two things:

    • That Chat is safe to be remoted to the browser.
    • That Message is allowed as a parameter.

    DWR could do the second bit for you, but we'll do it this way to make sure that you don't give away access to anything by mistake. The DWR configuration file, dwr.xml, is placed alongsideweb.xml in your WEB-INF folder. For your chat application, dwr.xml should look like this (obviously, replace the [your.package] bits with the package that you used from the code above):

     <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr> <allow> <create creator="new" javascript="Chat"> <param name="class" value="[your.package].Chat"/> </create> <convert converter="bean" match="[your.package].Message"/> </allow> </dwr>
    

    We are telling DWR it is OK to create Chat classes for remoting to the browser, and that in JavaScript they will be called 'Chat'. It also says that Messageis safe to use as a parameter.

    The Client-Side Scripting

    The final bit is the JavaScript that is fired off by the HTML to call into the Java code. The good news is that DWR makes this bit easy. Typically, the JavaScript code for this type of thing would contain complex XMLHttpRequest code, DOM manipulation, and parameter collation. With DWR, you don't worry about any of that.

    First we include the JavaScript that tells the browser about theChat code. There are there useful script lines:

     <script type='text/javascript' src='/[YOUR-WEB-APP]/dwr/engine.js'></script> <script type='text/javascript' src='/[YOUR-WEB-APP]/dwr/interface/Chat.js'></script> <script type='text/javascript' src='/[YOUR-WEB-APP]/dwr/util.js'></script>
    

    The script engine.js contains the core of DWR. Generally, you just include it as is, and then ignore it. There are a few methods in it that are sometimes useful, but you can see the full documentation for them at the DWR website. The scriptutil.js contains some utility functions that are totally optional, but will help you greatly in getting anything done with DWR. Chat.js is dynamically generated by DWR as the remote version of Chat.java. If you look at it, you'll see something like this:

     
    Chat.addMessage = function(callback, p0) { ... } Chat.getMessages = function(callback) { ... } 
    

    DWR does everything it can to make the JavaScript version of your Java code as simple as possible, but there are some things you need to be aware of. The most obvious is that the "A" in AJAX stands for asynchronous; so by definition, the remote method is not executed the instant your JavaScript code is executed. This would not be an issue, except for the complexity of knowing what to do with the values returned by Java to the browser. DWR solves the problem by asking for a callback method, to which it will pass the returned data. The first parameter to any DWR-generated method is always the callback function.

    Above, we created a web page with a JavaScript function that we've not implemented, until now: the sendMessage()event is fired off by the browser whenever the "send" button is pressed. As you might guess, this is going to callChat.addMessage():

     function sendMessage() { var text = DWRUtil.getValue("text"); DWRUtil.setValue("text", ""); Chat.addMessage(gotMessages, text); }
    

    The first line gets the value from the input field.DWRUtil.getValue() works with most HTML elements, so long as they have an id attribute (in this case, the input element has an id="text").

    Next, we use the setValue() method to blank out the input element; again, the setValue() is very smart at working out what to do with your data and how it should update your web page with the new data.

    Then we call Chat.addMessage() and ask DWR to return the list of messages typed by other web users to thegotMessages() function. It looks like this:

     function gotMessages(messages) { var chatlog = ""; for (var data in messages) { chatlog = "<div>" + messages[data].text + "</div>" + chatlog; } DWRUtil.setValue("chatlog", chatlog); }
    

    This is where DWR excels. The Java methodChat.addMessage() returned a List ofMessage objects. DWR has automatically converted this into an array of JavaScript objects. All we need to do ingotMessages() is to iterate over the messages array, getting the text member from each object in the array, and build some HTML from it. Finally, we push the string we have created into the div using the ever-versatilesetValue() method.

    And that's it! We have a basic multi-user, web-based chat system in about 100 lines of code, for both the client and server code.

    There are a number of things missing for this to be useful: a polling method that uses setTimeout() to callChat.getMessages() would keep things flowing a bit more. The downloaded code contains an extra six lines of JavaScript to make this happen. We could also add code to only alter the display if new messages have arrived; this would make for a flicker-free display. Finally, having a back-off mechanism where the browsers poll the server less often if nothing much is happening would be a good idea to prevent swamping the server.

    You can see the final version here. It adds the features listed above, plus highlighting of new messages--all of which takes an extra 50 or so lines of JavaScript.

    It is also worth checking outhttp://localhost:8080/[YOUR-WEB-APP]/dwr, which is a test debug page that automatically shows you the classes you have remoted, and allows you to test their functionality.

    Conclusion

    Using DWR can make creating cross-browser AJAX websites very easy, and introduces a very neat way to interact between JavaScript in the web browser and Java on the server. It is simple to get started with and integrates well with your current website.

    Resources

      
    http://today.java.net/im/a.gif