Using DWR (Direct Web Remoting) for Building AJAX Applications

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.com/ajaxcodecamp



This hands-on lab takes you through the basics of using DWR (Direct Web Remoting) for developing AJAX-based web applications. This document is designed to get you going as quickly as possible.

In this lab, you will learn (1) step by step of building DWR based AJAX application (2) How to configure your web application configuration file web.xml to be DWR aware (3) How to use write DWR configuration file called dwr.xml (4) How to use some of the DWR utility functions.


Expected duration: 90-120 minutes

Prerequisites

This tutorial assumes you have some basic knowledge of, or programming experience with, the following technologies.

Software Needed

Before you begin, you need to install the following software on your computer. The dwr.jar file is already included as part of the hands-on lab zip file so you don't have to download it yourself.


Change Log


Things to be done

Lab Exercises


Exercise 1: Build and run "Chat-Demo" sample DWR application

In this exercise, you are going to build and run "Chat demo" sample application (dwr.examples.chat NetBeans project) using NetBeans.  All the required code and library files are already provided as a ready-to-run NetBeans project.

  1. Open, build, and run "Chat-Demo" sample DWR application using NetBeans
  2. Test remoted methods
  3. Look under the hood of the Chat-Demo sample DWR application
  4. Add another method to remote to the Chat-Demo sample application
  5. For your own exercise, add another method to the Chat-Demo sample application

(1.1) Open, build, and run "Chat-Demo" sample DWR application (dwr.examples.chat) using NetBeans

1.  Open dwr.examples.chat NetBeans project.


Figure-1.10: Open dwr.examples.chat NetBeans project

2. Resolve a reference problem.


Figure-1.11: Resolve Reference Problems


Figure-1.12: Resolve


Figure-1.13: Select dwr.jar file

Figure-1.14: Reference problem is resolved

3. Build and run the project


Figure-1.16: Run


Figure-1.12: Do some chatting Figure-1.13: Running Data Validation using AJAX


                                                                                                   return to top of the exercise                                                                                                               

(1.2) Test remoted methods

DWR provides a testing page for the remoted methods.  All you have to do is to append /dwr to the URL.

1. From your browser, go to http://localhost:8080/dwr.examples.chat/dwr. This page gives you a debugging page in which you can interact with the backend application.
2. Click Chat. (Figure-1.13 below)  It will display all the methods that are remoted by DWR.


Figure-1.13: Debugging page

3.  Now you see there are two methods - addMessage("") and getMessage() - are remoted by DWR, which means these two methods can be invoked through the matching JavaScript object.
4. Click Execute button of the getMessages() method. (Figure-1.14 below)


Figure-1.14: Debugging page, Click Execute button of the getMessages() method

5. You should see Figure-1.15 below.  This shows the data that has been returned in the form of JSON as a result of invoking getMessages() method of the JavaScript object Chat. (Note: We will learn about JSON later in this course.)


Figure-1.15: Returned data

6.  Type in whatever string you like - 3rd message in the example below - into the gray area of the addMessage() call and click Execute button. (Figure-1.16 below).


Figure-1.16: Debugging page, Click Execute button of the addMessage() method

7. You should see Figure-1.17 below.  This shows the data that has been returned as a result of invoking addMessage() method of the JavaScript object Chat.


Figure-1.17: Returned data

                                                                                                   return to top of the exercise

(1.3) Look under the hood of the "Chat-Demo" sample DWR application

In this step, you will learn the underlying architecture of DWR by looking into the pieces that make up the dwr.examples.chat sample application.

1. First of all, you have to have dwr.jar file in your web application.  The dwr.examples.chat application has it.  You can see that by expanding dwr.examples.chat project node then Libraries.  You should see dwr.jar file. (Figure-1.30 below)

Note: The dwr.jar file can be downloaded from DWR home site


Figure-1.30: dwr.jar

2. You have to include the DWR servlet mapping in the web.xml of your web application.  Every DWR application has to have this.  The debug parameter could be set to false or absent.

    <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>

You can see the web.xml file of the dwr.examples.chat application under Web Pages->WEB-INF node. (Figure-1.33 below)


Figure-1.33: The web.xml file has to have DWR servlet mapping

3. You then have to have DWR configuration file called dwr.xml in the same directory you have web.xml file.  In this file, you specify which Java classes and which methods of those Java classes you want to do "remoting".  You can see the the dwr.xml file of the dwr.examples.chat application under Web Pages->WEB-INF node. (Figure-1.34 below)


Figure-1.34: The dwr.xml file

In this example, the dwr.xml indicates that all the public methods of the mypackage.Chat Java class will be remoted as Chat JavaScript object.  Now let's take a look at the mypackage.Chat Java class and how the methods of it gets called from the browser.

4.  Double click Chat.java under Source Packages->mypackage to open it in the source code editor window. (Figure-1.35 below)


Figure-1.35: mypackage.Chat.java

Note that there are two public methods - addMessage(String text) and getMessage().  These two methods will be remoted.  Now let's take a look on how these two methods are invoked from the JavaScript.

5. Double click index.html under Web Pages to open it in the source code editor window. (Figure-1.36 below)


Figure-1.36: index.html

Note how addMessage() and getMessages() methods of a JavaScript object called Chat are invoked.

                                                                                                   return to top of the exercise

(1.4) Add another method to remote to the Chat-Demo sample application


Now you are going to add another method to the mypackage.Chat Java class for remoting.  The new method is to return the number of messages that have been posted. We will call it getNumberOfMessages().

1. Double-click Chat.java under Source Packages->mypackage to open in the source editor.
2. Modify the Chat.java  file as following.  The new code fragments that need to be added are highlighted in bold and blue colored font.

/*
 * Chat.java
 *
 * Created on May 29, 2006, 8:03 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package mypackage;

import java.util.LinkedList;
import java.util.List;

public class Chat{

    private static int numberOfMessages = 0;

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

    public List getMessages(){
        return messages;
    }

    public int getNumberOfMessages(){
        return numberOfMessages;
    }

    private static LinkedList messages = new LinkedList();
}

3. Right click dwr.examples.chat project node and select Run.  What we want to do test at this point is to make sure the new method we've added is remoted.
4. From your browser, go to http://localhost:8080/dwr.examples.chat/dwr. This page gives you a debugging page in which you can interact with the backend application.
5. Click Chat. (Figure-1.x below)  It will display all the methods that are remoted by DWR. It should include getNumberOfMessages(). You can also click Execute button of the method. And it should return the number.  (Figure-1.40 below)


Figure-1.40: Verify that the new method you've added is correctly remoted.

Now you can be assured that the new method has been correctly remoted by the DWR. Now let's change the client side.

6. Double-click index.html under Web Pages to open in the source editor.
7. Modify the index.html file as following.  The new code fragments that need to be added are highlighted in bold and blue-colored font.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
    <head>
        <title>Chat-Demo</title>

        <!-- You have to include these two JavaScript files -->
        <script type='text/javascript' src='dwr/engine.js'></script>
        <script type='text/javascript' src='dwr/util.js'></script>
       
        <!-- This JavaScript file is generated specifically for your application -->
        <script type='text/javascript' src='dwr/interface/Chat.js'></script>
 
        <script type='text/javascript'>
            function sendMessage(){
                var text = DWRUtil.getValue("text");
                DWRUtil.setValue("text", "");
       
                // Invoke addMessage(text) method of the Chat class on
                // the server.  The gotMessages is a callback function.
                Chat.addMessage(text, gotMessages);
            }
   
            function checkMessages(){
                Chat.getMessages(gotMessages);

                // This code will not work - you do not want to call the method
                // synchronously. 
                var chatcount = Chat.getNumberOfMessages();
                DWRUtil.setValue("chatcount", chatcount);
            }
   
            // Callback function
            function gotMessages(messages){
                var chatlog = "";
                for (var data in messages){
                    chatlog = "<div>" + messages[data].text + "</div>" + chatlog;
                }
                DWRUtil.setValue("chatlog", chatlog);
                setTimeout("checkMessages()", 1000);
            }
        </script>
    </head>
   
    <body onload="setTimeout('checkMessages()', 1000)">
        <p>Messages:</p>
        <div id="chatlog" style="border: 1px solid black;"></div>
        <p>Number of messages:</p>
        <div id="chatcount" style="border: 1px solid black;" ></div>
        <p>
            Your Message:
            <input id="text" />
            <input type="button" value="Send" onclick="sendMessage()" />
        </p>
    </body>
</html>

8. Right click dwr.examples.chat project node and select Run.  You will see the following result. (Figure-1.43 below)


Figure-1.43: The Number of messages field is not getting updated.

You noticed that the above is not working as you expected.  Somehow the chatcount is not being displayed.  There is a reason for that.  Think about for a moment why this code would not work.

9. Modify the index.html file as following.  The new code fragments that need to be added are highlighted in bold and blue colored font.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
    <head>
        <title>Chat-Demo</title>

        <!-- You have to include these two JavaScript files -->
        <script type='text/javascript' src='dwr/engine.js'></script>
        <script type='text/javascript' src='dwr/util.js'></script>
       
        <!-- This JavaScript file is generated specifically for your application -->
        <script type='text/javascript' src='dwr/interface/Chat.js'></script>
 
        <script type='text/javascript'>
            function sendMessage(){
                var text = DWRUtil.getValue("text");
                DWRUtil.setValue("text", "");
       
                // Invoke addMessage(text) method of the Chat class on
                // the server.  The gotMessages is a callback function.
                Chat.addMessage(text, gotMessages);
            }
   
            function checkMessages(){
                Chat.getMessages(gotMessages);
            }

            function checkChatCount(){
                // The getNumberOfMessages() needs to be called in asynchronous fashion
                Chat.getNumberOfMessages(gotChatCount);

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

                // The checkChatCount() function gets called in 1000 ms.
                setTimeout("checkChatCount()", 1000);
            }

            // Callback function of the Chat.getNumberOfMessages(gotChatCount)
            function gotChatCount(ChatCount){
                DWRUtil.setValue("chatcount", ChatCount);
            }
         
        </script>
    </head>
   
    <body onload="setTimeout('checkMessages()', 1000)">
        <p>Messages:</p>
        <div id="chatlog" style="border: 1px solid black;"></div>
        <p>Number of messages:</p>
        <div id="chatcount" style="border: 1px solid black;" ></div>
        <p>
            Your Message:
            <input id="text" />
            <input type="button" value="Send" onclick="sendMessage()" />
        </p>
    </body>
</html>

10. Right click dwr.examples.chat project node and select Clean and Build Project, Deploy Project, then Run in the sequential order.  You will see the following result. (Figure-1.45 below)


Figure-1.45: The Number of messages are correctly reflected now

                                                                                                   return to top of the exercise

(1.5) Add another method for remoting

For your own exercise, add another method as shown in Code-1.46 below to the Chat.java and then expose the information in the browser as you did with the getNumberOfMessages() method in step 1.4 above.

    public String getLastMessage(){
        if (messages.size()== 0) {
            return "";
        }
        //getFirst will actually return the "last" message based on this data
        //structure
        Message m = (Message)messages.getFirst();
        return (String)m.getText();
       
    }
Code-1.46: Modification for your own exercise

Summary

In this exercise, you have built and run a simple DWR sample application.  You learned how DWR application is structured.  You also add another Java method for remoting.

                                                                                                                        return to the top




Exercise 2: Build and run "Dynamic Form Editing" sample DWR application

In this exercise, you will build and run another DWR sample application called "Dynamic Form Editing".  Here you are going to exercise on how to pass a JavaBean object called Person as a parameter on a remoted method.  All the required code and library files for step (2.1) are already provided as a ready-to-run NetBeans project.  For step (2.2), you are going to follow instruction in this document to change code.  Step (2.3) is left for your own exercise.


(2.1) Open, build, and run "Dynamic Form Editing" sample DWR application using NetBeans

1.  Open dwr.examples.form-editing NetBeans project

2. Resolve reference problem as you did above in Exercise 1.

3. Build and run the project.


Figure-2.10: Result of running "Dynamic Form Editing" sample DWR application


Figure-2.11: Write a form

                                                                                                                         return to top of the exercise

(2.2) Pass a nested object as a parameter

In this step, you are going to modify name field of the Person class to be a JavaBean class from its current String type.   The Person class is considered as a nested class once it contains another class as a child.

1. Double click Person.java under dwr.examples.form-editing->Source Packages->uk.ltd.getahead.testdwr to open it in the source editor of NetBeans.
2. Modify the Person.java as shown below - Change String type of name field to Name class. The code fragment that needs to be changed are in bold and blue-colored font.  There are 4 places you need to change from String to Name in the Person.java file.

package uk.ltd.getahead.testdwr;

public class Person {
   
    private Name name;
    private String address;
    private int id;
    private float salary;
   
    // No arg constructor to make it a JavaBean
    public Person(){
    }
   
    public Person(Name name, String address, int id, float salary){
        this.name = name;
        this.address = address;
        this.salary = salary;
        this.id = id;
    }
   
    public Name getName() {
        return name;
    }
   
    public void setName(Name name) {
        this.name = name;
    }
   
    public String getAddress() {
        return address;
    }
   
    public void setAddress(String address) {
        this.address = address;
    }
   
    public float getSalary() {
        return salary;
    }
   
    public void setSalary(float salary) {
        this.salary = salary;
    }
   
    public int getId() {
        return id;
    }
   
    public void setId(int id) {
        this.id = id;
    }

}

3. Now we need to create Name class.  Right-click uk.ltd.getahead.testdwr package node under dwr.examples.form-editing->Source Packages and select New->Java Class.  (Figure-2.21 below)


Figure-2.21: Create a New Java Class

4. For Class Name: field under Name and Location pane, type in Name.  Click Finish.  (Figure-2.22 below)


Figure-2.22: Name class

5. Modify IDE generated Name.java code as shown below. (Code-2.23 below)  The code fragments that need to be added are highlighted in bold and blue-colored font.  Make sure you have no arg constructor.  Otherwise, DWR will have a problem in conversion of the class.

package uk.ltd.getahead.testdwr;

/**
 *
 * @author sang
 */
public class Name {
   
    private String firstname;
    private String middlename;
    private String lastname;
   
    // No arg constructor
    public Name() {
    }

    public Name(String firstname, String middlename, String lastname) {
        this.firstname = firstname;
        this.middlename = middlename;
        this.lastname = lastname;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getMiddlename() {
        return middlename;
    }

    public void setMiddlename(String middlename) {
        this.middlename = middlename;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
   
}
          Code-2.23: Name.java

5. Modify createPeople() method of the  Demo.java as shown below. (Code-2.24 below) The change is to create Person object instances using Name object instances.

    private void createPeople() {
        Person fred = new Person(new Name("Fred", "Middle", "Shin"), "1 Red Street",
                2, 100000.0f);
        Person jim = new Person(new Name("Jim", "M", "Clinton"), "42 Brown Lane", 3, 20000.0f);
        Person shiela = new Person(new Name("Shiela", "Mi", "Hutcherson"), "12 Yellow Road",
                4, 3000000.0f);
       
        people.put(new Integer(fred.getId()), fred);
        people.put(new Integer(jim.getId()), jim);
        people.put(new Integer(shiela.getId()), shiela);
    }
   
    private static final String SESSION_CLICKS = "sessionClicks";
   
    private static final String CONTEXT_CLICKS = "contextClicks";
   
    private static int nextId = 10;
   
    private final Map people = new HashMap();
   
    private Person person = new Person(new Name("John Doe", "Mid", "Thompson"),
            new Date().toString(), 1, 100000.0F);
}
Code-2.24: Modified Demo.java

5. Modify index.html under dwr.examples.form-editing->Web Pages. (Code-2.25 below)  The Code-2.25 is the complete document of the index.html.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
        <title>DWR Examples from DWR website</title>

        <script type='text/javascript' src='dwr/engine.js'></script>
        <script type='text/javascript' src='dwr/interface/Demo.js'></script>
        <script type='text/javascript' src='dwr/util.js'></script>
 
        <script type='text/javascript'>
            // This function gets called when window is loaded.
            // The fillForm is a callback function to be called asynchronously.
            function readPerson() {
                Demo.getExamplePerson(fillForm);
            }

            function writePerson() {
                DWRUtil.getValues(person);
                DWRUtil.getValues(person.name);
                DWRUtil.getValues(person.address);
                Demo.setExamplePerson(null, person);
            }

            function clearPerson() {
                //person = { id:"", name:"", address:"", salary:"" };
                person = { id:"", firstname:"", middlename:"", lastname:"", address:"", salary:"" };
                DWRUtil.setValues(person);
            }

            var person;
            var name;

            // Callback function
            function fillForm(aperson) {
                // Add some alert messages to display the data that is received from the server
                alert(DWRUtil.toDescriptiveString(aperson));
                alert(DWRUtil.toDescriptiveString(aperson.name));
                person = aperson;
                DWRUtil.setValues(person);
                // Note the easy syntax for accessing the Name child object from Person parent object
                name = aperson.name;
                DWRUtil.setValues(name);
            }

            // Initialization that is called when window is loaded
            function init() {
                DWRUtil.useLoadingMessage();
                readPerson();
            }
           
            // Call init function when window is loaded
            window.onload = init;

        </script>
    </head>

    <body>
   
        <h1>Dynamic Form Editing</h1>

        <p>This is a very simple demonstration of form editing using DWR.</a>
       
        <h2>Demo</h2>
        <table>
            <tr>

                <td>First Name:</td>
                <td><input id="firstname" type="text"/></td>
                <td>Middle Name:</td>
                <td><input id="middlename" type="text"/></td>
                <td>Last Name:</td>
                <td><input id="lastname" type="text"/></td>

            </tr>
            <tr>

                <td>Salary:</td>
                <td><input id="salary" type="text"/></td>

            </tr>
            <tr>

                <td>ID:</td>

                <td><input id="id" type="text"/></td>

            </tr>
            <tr>

                <td>Address:</td>
                <td><input type="text" id="address"/></td>

            </tr>
            <tr>

                <td colspan="2" align="right">
                    <input type="button" value="Clear" onclick="clearPerson()"/>
                    <input type="button" value="Read" onclick="readPerson()"/>
                    <input type="button" value="Write" onclick="writePerson()"/>
                </td>

            </tr>
        </table>
    </body>
</html>
Code-2.25: Modified index.html

6. Modify dwr.xml file under dwr.examples.form-editing->Web Pages->WEB-INF. (Code-2.26 below)  You are instructing DWR to do the conversion of the Name JavaBean class.

<?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="Demo" scope="session">
      <param name="class" value="uk.ltd.getahead.testdwr.Demo"/>
    </create>

    <create creator="new" javascript="Chat">
      <param name="class" value="uk.ltd.getahead.testdwr.Chat"/>
    </create>

    <create creator="new" javascript="UrlValidator">
      <param name="class"
        value="org.apache.commons.validator.UrlValidator"/>
    </create>

    <create creator="new" javascript="CreditCardValidator">
      <param name="class"
        value="org.apache.commons.validator.CreditCardValidator"/>
    </create>

    <create creator="script" javascript="EmailValidator"
        scope="application">
      <param name="language" value="beanshell"/>
      <param name="script">
        import org.apache.commons.validator.EmailValidator;
        return EmailValidator.getInstance();
      </param>
    </create>

    <create creator="new" javascript="XOM">
      <param name="class"
                value="uk.ltd.getahead.testdwr.XOMDemo"/>
    </create>
    <create creator="new" javascript="JDOM">
      <param name="class"
                value="uk.ltd.getahead.testdwr.JDOMDemo"/>
    </create>
    <create creator="new" javascript="DOM4J">
      <param name="class"
                value="uk.ltd.getahead.testdwr.DOM4JDemo"/>
    </create>
    <create creator="new" javascript="DOM">
      <param name="class"
                value="uk.ltd.getahead.testdwr.DOMDemo"/>
    </create>

    <convert converter="bean"
        match="uk.ltd.getahead.testdwr.Person"/>
    <convert converter="bean"
        match="uk.ltd.getahead.testdwr.Message"/>
    <convert converter="bean"
        match="uk.ltd.getahead.testdwr.Name"/>
    <convert converter="bean" match="$Proxy*"/>

  </allow>

</dwr>
Code-2.26: Modified dwr.xml

7. Right click dwr.examples.form-editing project and select Run.  You should see an alert message displaying the content of the returned data. (Figure-2.27 below)


Figure-2.27: First alert message within the callback function

8. Click OK of the alert message. You should the see the second alert message, which displays the content of the Name object.
9. Click OK of the second alert message. (Figure-2.28 below)


Figure-2.28: Second alert message within the callback function.

10. You should see the result as shown below. (Figure-2.29 below)


Figure-2.29: Display of the default person

11. Change the values and click Write button.
12. Click Read button if the changed values are displayed.


Trouble-shooting:  If you see the following error dialog box, then it means DWR is having a problem converting between Person Java object and Person JavaScript object.  The source of the problem could be (1) The Person Java class is not a JavaBean - maybe it does not have no-arg constructor (2) The <convert> element in the dwr.xml file is not specified or incorrectly specified.




Solution: The solution to this exercise is available as ready-to-open-and-run NetBeans project <LAB_UNZIPPED_DIRECTORY>/ajaxdwrintro/solutions/dwr.examples.form-editing-solution.  You can just open it and run it.



                                                                                                                         return to top of the exercise

(2.3) Make Address field to be a Java class for your own exercise

For your own exercise, make Address class to be a JavaBean class (instead of String type).  Write Address.java as shown in Code-2.30 below. Make modifications in Demo.java, index.html, and dwr.xml files as you did in step (2.2) above.  Rebuild and test the application.

package uk.ltd.getahead.testdwr;

/**
 *
 * @author sang
 */
public class Address{
  
    private String street;
    private String state;
    private String zipcode;
  
    /** Creates a new instance of Address*/
    public Address() {
    }

    public Address(String street, String state, String zipcode) {
        this.street = street;
        this.state = state;
        this.zipcode = zipcode;
    }

    public String getstreet() {
        return street;
    }

    public void setstreet(String street) {
        this.street = street;
    }

    public String getstate() {
        return state;
    }

    public void setstate(String state) {
        this.state = state;
    }

    public String getzipcode() {
        return zipcode;
    }

    public void setzipcode(String zipcode) {
        this.zipcode = zipcode;
    }
  
}


                                                                                                                         return to top of the exercise

Summary

In this exercise, you have learned how to pass Java object as a parameter for a remoted method.  You also learned how to pass a nested Java object as a parameter.
   
                                                                                                                                   Return to the top



Exercise 3: Build and run "Dynamic Table Editing" (dwr.examples.table-editing) sample DWR application

In this exercise, you will build and run another DWR sample application called "Dynamic Table Editing"(dwr.examples.table-editing project).  You will get to learn how to use  DWRUtil.addRows() and DWRUtil.removeAllRows() utility functions for manipulating tables.

Before you do this exercise, please get yourself familiarized with these two utility functions by reading Generating Tables tutorial from DWR website.  All the required code and library files for step (3.1) are already provided as a ready-to-open-and-run NetBeans project.

    1. Open, build, and run "Dynamic Table Editing" sample DWR application using NetBeans
    2. Add another field Hobby to the table
    3. Add another field of your own to the table for your own exercise

(3.1) Open, build, and run "Table Editing" sample DWR application using NetBeans


1. Open dwr.examples.table-editing NetBeans project.
2. Resolve reference problem as you did above in Exercise 1.
3. Build and run the project.

Figure-3.10: Edit Shiela's information


Figure-3.11: Edit Shiela's address


Figure-3.12: Add another row



Figure-3.13: New row is added

                                                                                                                         return to top of the exercise

(3.2) Add another field "Hobby" to the table


In this step, you are going to add another field called Hobby to the table and rebuild the application.

1.  Modify Person.java.  The code fragments that need to be added are highlighted in bold and blue colored font. (Code-3.20 below)

package uk.ltd.getahead.testdwr;

public class Person {
   
    /* Getters and setters go here */
    private String name;
    private String address;
    private int id;
    private float salary;
    private String hobby;
   
    // No arg constructor to make it a JavaBean
    public Person(){
    }
   
    public Person(String name, String address, int id, float salary, String hobby){
        this.name = name;
        this.address = address;
        this.salary = salary;
        this.id = id;
        this.hobby = hobby;
    }
   
    public String getName() {
        return name;
    }
   
    public void setName(String name) {
        this.name = name;
    }
   
    public String getAddress() {
        return address;
    }
   
    public void setAddress(String address) {
        this.address = address;
    }
   
    public float getSalary() {
        return salary;
    }
   
    public void setSalary(float salary) {
        this.salary = salary;
    }
   
    public int getId() {
        return id;
    }
   
    public void setId(int id) {
        this.id = id;
    }

    public String getHobby() {
        return hobby;
    }
   
    public void setHobby(String hobby) {
        this.hobby= hobby;
    }
}
Code-3.20: Modified Person.java

2.  Modify Demo.java to reflect hobby property of the Person class. (Code-3.21 below)  

    /**
     * Setup the list of people.
     */
    private void createPeople() {
        Person fred = new Person("Fred", "1 Red Street",
                2, 100000.0f, "Swimming");
        Person jim = new Person("Jim", "42 Brown Lane", 3, 20000.0f, "Golfing");
        Person shiela = new Person("Shiela", "12 Yellow Road",
                4, 3000000.0f, "Dancing");
       
        people.put(new Integer(fred.getId()), fred);
        people.put(new Integer(jim.getId()), jim);
        people.put(new Integer(shiela.getId()), shiela);
    }
   
    private static final String SESSION_CLICKS = "sessionClicks";
   
    private static final String CONTEXT_CLICKS = "contextClicks";
   
    private static int nextId = 10;
   
    private final Map people = new HashMap();
   
    private Person person = new Person("John Doe",
            new Date().toString(), 1, 100000.0F, "Walking");
Code-3.21: Modified Demo.java

3. Modify JavaScript code in the index.html. (Code-3.22 below)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
        <title>DWR Examples from DWR website</title>

        <script type='text/javascript' src='dwr/engine.js'></script>
        <script type='text/javascript' src='dwr/interface/Demo.js'></script>
        <script type='text/javascript' src='dwr/util.js'></script>
 
        <script type='text/javascript'>
            // Callback function for Delete method
            function update() {
                Demo.getAllPeople(fillTable);
            }

            // Functions to be passed to DWRUtil.addRows
            var getName = function(person) { return person.name };
            var getDoB = function(person) { return person.address }; // if we return to using dates, add .toLocaleDateString()
            var getSalary = function(person) { return person.salary };
            var getHobby = function(person) { return person.hobby};
            var getEdit = function(person) {
                return '<input type="button" value="Edit" onclick="readPerson('+person.id+')"/>';
            };
            var getDelete = function(person) {
                return '<input type="button" value="Delete" onclick="deletePerson('+person.id+', \''+person.name+'\')"/>';
            };
           
            // Callback function for getAllPeople method
            // The table is reconstructed
            function fillTable(people) {
                DWRUtil.removeAllRows("peoplebody");
                DWRUtil.addRows("peoplebody", people, [ getName, getDoB, getSalary, getHobby, getEdit, getDelete ])
            }

            // Event handler to be called when Edit button is clicked
            function readPerson(id) {
                Demo.getPerson(fillForm, id);
            }

            // Event handler to be called when Delete button is clicked
            function deletePerson(personid, name) {
                if (confirm("Are you sure you want to delete " + name + "?")) {
                    Demo.deletePerson(update, { id:personid });
                }
            }
           
            // Event handler to be called when Save button is clicked
            function writePerson() {
                DWRUtil.getValues(person);
                Demo.addPerson(update, person);
            }

            var person = { id:-1, name:null, address:null, salary:null, hobby:null };

            // Event handler to be called when Clear button is clicked
            function clearPerson() {
                person = { id:-1, name:null, address:null, salary:null, hobby:null };
                DWRUtil.setValues(person);
            }

            // Callback function for readPerson method
            function fillForm(aperson) {
                person = aperson;
                DWRUtil.setValues(person);
            }
    
            // Function that will be called when page is loaded
            function init() {
                DWRUtil.useLoadingMessage();
                update();
            }
           
            // Set init function to be called when page is loaded
            window.onload = init;
        </script>
    </head>

    <body>

        <h1>Dynamically Editing a Table</h1>

        <p>This demo stores the list of people in your session, so the editing relies on <b>Cookies</b>. DWR can use application, session and request scope to store beans</p>

        <h2>Demo</h2>
            
        <table border="1" class="rowed">

            <thead>
                <tr>

                    <th>Name</th>
                    <th>Address</th>
                    <th>Salary</th>
                    <th>Hobby</th>
                    <th colspan="2">Actions</th>

                </tr>
            </thead>
            <tbody id="peoplebody">
            </tbody>

        </table>

        <h4>Edit Person</h4>

        <table>
            <tr>

                <td>ID:</td>
                <td><span id="id">-1</span></td>

            </tr>
            <tr>

                <td>Name:</td>

                <td><input id="name" type="text"/></td>

            </tr>
            <tr>

                <td>Salary:</td>
                <td><input id="salary" type="text"/></td>

            </tr>
            <tr>

                <td>Address:</td>
                <td><input type="text" id="address"/></td>

            </tr>
            <tr>

                <td>Hobby:</td>
                <td><input type="text" id="hobby"/></td>

            </tr>
            <tr>

                <td colspan="2" align="right">
                    <input type="button" value="Save" onclick="writePerson()"/>
                    <input type="button" value="Clear" onclick="clearPerson()"/>
                </td>

            </tr>
        </table>
    </body>
</html>
Code-3.22: Modified index.html

4. Right-click dwr.examples.table-editing project node and select Run.  You should see the fugure below.  (Figure-3.33 below)


Figure-3.33: Hobby field is added

5.  Add another person and see if the application behaves as expected.

                                                                                                                         return to top of the exercise

(3.3) Add another field of your own to the table for your own exercise


For your own exercise, add another field of your choice to the table. Make modifications in Person.java, Demo.java, and index.html files as you did in step (3.2) above.  Rebuild and test the application.  As an optional exercise, please make Address field as a JavaBean class as you did in step (2.2) above.

Summary


In this exercise, you built and ran a DWR sample application called "Dynamic Table Editing"(dwr.examples.table-editing).  You also learned how to use  DWRUtil.addRows() and DWRUtil.removeAllRows() utility functions for manipulating tables.

                                                                                                                               return to the top



Exercise 4: Build and run "Dynamically Populating a Selection List" sample DWR application


In this exercise, you will build and run another DWR sample application called "Dynamically Populating a Selection List". 


(4.1) Open, build, and run "Dynamically Populating a Selection List" sample DWR application using NetBeans


1. Open dwr.examples.populating-selectionlist NetBeans project.
2. Resolve reference problem as you did above in Exercise 1.

3. Build and run the project.


Figure-4.10: Result of running the application

Figure-4.11: The Pick a Number selections are changed


                                                                                                             return to the top 





Homework exercise (for people who are taking Sang Shin's "AJAX online course")


1. The homework is to modify the dwr.examples.table-editing project you built as Exercise #3 as following.  (You might want to create a new project by copying the dwr.examples.table-editing project.)  You can name the new project in any way you want but here I am going to call to call it as dwr.examples.table-editing-homework
2. Send the following files to ajaxhomework@sun.com with Subject as AJAXHomework-ajaxdwrintro.