a Dynamic Ajax table example using dojo and RESTful Web Services on Glassfish


This Sample Catalog app demonstrates a RESTful Web Service, coded using JAX-RS: Java API for RESTful Web Services (JSR-311)and Java Persistence API, which provides a list of customers, and a Dojo client which  gets and displays the Web Service responses in a dynamic Ajax table ( Dojo grid).

Download the dojo Sample Application Code

Dojo  is an open source DHTML toolkit written in JavaScript.

JAX-RS provides a standardized API for building RESTful web services in Java. Central to the RESTful architecture is the concept of resources identified by universal resource identifiers (URIs). The API  provides a set of annotations which you can add to Plain Old Java Objects (POJOs)  to expose web resources identified by URIs .

Explanation of the usage of Dojo and JAX-RS in a sample Catalog Application

The image below shows the Customer Listing page, which allows the user to page through a list of customers.
    
    table.jpg


Quick installation and use of dojo with Netbeans

There are 3 ways to install dojo which you can read about in the book of dojo. A quick and easy way to use dojo with Netbeans is to download the JavaScript libraries from http://dojotoolkit.org/downloads.   Create a new NetBeans Web Applications project. Extract the dojo toolkit  into the project web directory: .../web , then rename dojo-release-1.1.1/ to src/  this will give you the project structure shown below.  I have already done this for the sample project so you do not have to download dojo in order to run the sample.
    dojonetproj.JPG

Dojo style sheets

Every page using the dojo Grid needs to import the grid style sheetGrid.css as shown below:

        
Code Sample from:  index.html

    <style type="text/css">
      /* tundraGrid.css matches Dijit Tundra style. */
      @import "src/dojox/grid/_grid/tundraGrid.css";
      @import "src/dijit/themes/tundra/tundra.css";
      @import "src/dojo/resources/dojo.css";
      @import "src/dojox/grid/_grid/Grid.css";
    </style>



This will load the the CSS files required by the Dojo grid widget, you can just use  dojox/grid/_grid/Grid.cssinstead of tundraGrid if you don't want the tundra style.  

Loading base dojo and required modules into an application

In order to load dojo into your application,  put the relative path to the dojo.js file in a script element in the head section of your  HTML page as shown below:

        
Code Sample from:  index.html

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




This script element will load the base dojo script which gives you access to all the dojo functionality.

Next  the application specifies which  dojo modules to load, using  the dojo.require function (kind of like  import in Java):

        
Code Sample from:  index.html

 <script type="text/javascript">
   dojo.require("dojox.grid.Grid");
   dojo.require("dojox.grid._data.model");
   dojo.require("dojo.parser");
 </script>


Dojo is organized into three major layers: Dojo Core, Dijit, and DojoX.   DojoX builds on  Dojo Core and provides newer extensions to the Dojo toolkit. The rest of the Java Script for this application is in the file dynamicTable.js.

The Grid Widget

You can use widgets declaratively by using special attributes inside of regular HTML tags, or programmatically through JavaScript.
The dojoType attribute declares a Dojo widget. Below is the declaration of the Grid widget for this applicaton:
            
Code Sample from:  index.html

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


The model and structure attributes point to the  JavaScript variables for the model and layout structure explained below.

The Grid View

A Dojo grid  is a widget useful for displaying data sets in a table with its own scrollable views.  The dojo grid widget requires a layout. A grid layout is declared as an array of views.  Each view is a group of columns,  declared as an array of arrays. Each array element is an object, the "name" property of the object names the column. The column names will be displayed in the top row of the grid. The code below declares 4 columns: Company,City, State, Zip. This grid layout structure consists of one view as shown  below:

        
Code Sample from:  dynamicTable.js

 
// Data Grid layout
// A grid view is a group of columns
var view1 = {
            cells: [
                [
                    {name: 'Company', field: "name"},
                    {name: 'City', field: "city"},
                    {name: 'State',field: "state"},
                    {name: 'Zip',field: "zip"}
                ]
            ]
};
// a grid layout is an array of views.
var layout = [ view1 ];


This grid layout for this example is shown in the figure below (note: how the data for the table gets loaded is explained below).
    dojogrid.JPG

The Grid Model

The dojo grid widget requires a data model. The model variable declares the type of Dojo object that the Grid will use for the json data that will be loaded in the grid. There are different options for the model, this example uses thedojox.grid.data.Objects which is a collection of objects to be displayed in the grid.

        
Code Sample from:  dynamicTable.js

// the model will contain the data to be displayed in the view
model = new dojox.grid.data.Objects(null,null);

function handleResponse(responseObject, ioArgs){
    // set the model object with the returned customers list
    model.setData(responseObject.customers.customer);       
}  

// make request to the customers web service
function loadTable(page){
    start = page * batchSize;
    var targetURL = "resources/customers/?start="+ encodeURIComponent(start);   
    dojo.xhrGet({
        url: targetURL,
        handleAs: "json",
        load: handleResponse,
        error: handleError
    });
}

The loadTablefunction calls   dojo.xhrGetto make an XMLHttpRequest to the customers JAX-RS web service specified by the url: parameter. When the response from web service is returned, the callback function handleResponse specified by load: is called and the response is passed to the callback function in the responseObject. The handleAs  parameter specifies the response data type, handleAs: "json"  means the returned data is of the type JSON (Java Script object notation).
In the   handleResponse callback function,  model.setData is called to populate the Dojo grid  with the data returned from the  the customers JAX-RS web service. Below is an example of a JSON response from the customers JAX-RS web service:

        
Example json data

{"customers":
  {"@uri":"http://host/dojoRest/resources/customers/",
   "customer":[
     {"@uri":"http://host/dojoRest/resources/customers/1/",
       "name":"JumboCom",
      "city":"Fort Lauderdale",     
       "state":"FL",
       "zip":"33015"},
     {"@uri":"http://host/dojoRest/resources/customers/2/",
       "name":"Livermore Enterprises",
       "city":"Miami",
       "state":"FL",
       "zip":"33055"}
    ]
  }
}


Loading the table

The dojo.addOnLoad function allows you to call a  function after a page has loaded and after Dojo has finished its initilization. This application uses dojo.addOnLoad to call the loadTable() function (which we looked at above)  which calls the  customers JAX-RS web service and sets the results in the grid data model.

        
Code Sample from:  dynamicTable.js

    <script type="text/javascript">
        dojo.addOnLoad(function(){
            loadTable(0);
        });
    </script>

 

Events for paging

The  "<<"">>"buttons call the next() previous()functions when clicked:

        
Code Sample from:  index.html

<input type="button" value="<<" onclick="previous();">
</input>
<input type="button" value=">>" onclick="next();">
</input>


The next()function  increments the page number and then calls theloadTable() funtion:

        
Code Sample from:dynamicTable.js


function next() {
    page =page + 1;
    loadTable(page);
}

function previous() {
    page =page - 1;
    if (page < 0) page = 0;
    loadTable(page);
}


RESTful  Web Services with JAX-RS


The  dojo.xhrGet url: parameter  references the URI resources/customers/for the customers   RESTful web service.  The customers RESTful web service was generated using Netbeans 6.1 as explained in the Generating RESTful Web Services from Entity Classes  tutorial.  Using Netbeans 6.1 you can generate JPA Entity Classes from Database tables, then you can Generate RESTful Web Services from Entity Classes, and then you can test the Web Services with a browser interface. The customers RESTful web service was generated from the customer data table which comes already created in the Java DB with Netbeans. 

Below is a snippet from the CustomersResource.java class which was generated by the Netbeans "Generate RESTful Web Services from Entity Classes" feature :

        
Code Sample from: CustomersResource.java

// Service URI path "/customers/"

@Path("/customers/")

public class CustomersResource{
  
    @GET
    @ProduceMime("application/json")
    public
CustomersConverterget(@QueryParam("start")
           @DefaultValue("0") int start, @QueryParam("max")
            @DefaultValue("4") int max, @QueryParam("expandLevel")
            @DefaultValue("1") int expandLevel, @QueryParam("query")
            @DefaultValue("SELECT e FROM Customer e") String query) {
        try {
            CustomersConverter custs = new CustomersConverter(
               getEntities(start, max, query),
                context.getAbsolutePath(), expandLevel);
            return
custs;
        } finally {
            PersistenceService.getInstance().close();
        }
    }


The CustomersResourcerepresents a list of customers. The CustomersResource getmethod returns a list of Customer objects in JSON format. 
  • To address a resource in REST you specify its URI. @Path is a JAX-RS annotation that identifies the URI path for the resource. For the CustomersResource  the URI path is /customers/.
  • @GET specifies that thegetmethod supports the HTTP GET method.
  • @ProduceMimespecifies the MIME types that a method can produce. Here, the annotation specifies that the getmethod returns a JSONArray object.  TheCustomersConverterclass is a JAXB annotated class which is used to marshal a list of Customer objects into XML or JSON format.   The getEntitiesmethod returns a list of Customer entity objects and is explained below.  
  • @QueryParamspecifies input parameters for methods.  When the method is invoked, the input value will be injected into the corresponding input argument. 
  • @DefaultValuespecifies a default value for an arguement if no input value is given.
Here is an example of an HTTP request for this Web Service:

    
Request: GET http://host/dojoRest/resources/customers/?start=0


Here is an example of an HTTP response for this Web Service:

    
Received:
{"customers":
  {"@uri":"http://host/dojoRest/resources/customers/",
   "customer":[
     {"@uri":"http://host/dojoRest/resources/customers/1/",
       "name":"JumboCom",
      "city":"Fort Lauderdale",     
       "state":"FL",
       "zip":"33015"},
     {"@uri":"http://host/dojoRest/resources/customers/2/",
       "name":"Livermore Enterprises",
       "city":"Miami",
       "state":"FL",
       "zip":"33055"}
    ]
  }
}


The CustomersConverterclass is a JAXB annotated class, used to marshal a list of Customer objects into XML or  JSON format.  A snippet of the CustomersConverterclass is shown below:


        
Code Sample from: CustomersConverter.java

@XmlRootElement
public class CustomersConverter {

    @XmlElement
    public Collection<CustomerConverter> getCustomer(){
       ...
       return items;
    }
    @XmlAttribute
    public URI getUri() {
        return uri;
    }



Java Persistence Query API

The CustomersResourcegetEntities method uses the Java Persistence API Queryobject to return a list of customers.

        
Code Sample from: CustomersResource.java

@Path("/customers/")

public class CustomersResource{
  
    . . .

    protected Collection<Customer> getEntities(int start, int max, String query) {
       
PersistenceService ps =PersistenceService.getInstance();
        Query query = ps.
createQuery(query);
        query.
setFirstResult(start);
       query.setMaxResults(max);
        returnquery.getResultList();
    }

 

The Java Persistence Query APIs are used to create and execute queries that can return a list of results.  The JPA Query interface provides support for pagination via the setFirstResult() and setMaxResults() methods: query.setMaxResults(int maxResult) sets the maximum number of results to retrieve.query.setFirstResult(int startPosition) sets the position of the first result to retrieve.

In the code below, we show the Customerentity class which maps to the  CUSTOMER table that stores the customer instances. This is a typical Java Persistence entity object. There are two requirements for an entity:
  1. annotating the class with an @Entityannotation.
  2. annotating the primary key identifier with @Id
Because the fields name, description.... are basic mappings from the object fields to columns of the same name in the database table, they don't have to be annotated. 
For more information on Netbeans and JPA see basics of developing a web application using Java™ Persistence API.


        
Code Sample from: Customer.java

@Entity

public class Customerimplements Serializable {

   
@Id 
    private Integer customerId;

    private String name;
    private String addressline1;   
    private String city;  
    private String state; 
    private String zip;

    
    public
Customer() { }
     
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }



}   




Conclusion
This concludes the sample application which  demonstrates a RESTful Web Service, coded using JAX-RS: Java API for RESTful Web Services (JSR-311) , which provides a list of customers, and a dojo client which  gets and displays the Web Service responses in a dynamic Ajax table.

Configuration of the Application for jMaki, JPA, Netbeans 6.1 and Glassfish V2

  • Download and install NetBeans 6.1 bundled with GlassFish V2
  • Alternatively you can  Downloadand install GlassFish V2 separately.

Open and Run the Sample code:

  1. Download the sample code and extract its contents. You should now see the newly extracted directory as<sample_install_dir>/dojoRest, where <sample_install_dir> is the directory where you installed the sample package. For example, if you extracted the contents to C:\ on a Windows machine, then your newly created directory should be atC:\dojoRest.

  2. Start the NetBeans IDE. Click Open Project in the File menu and select the dojoRest directory you just unzipped.

  3. Build the project as follows:

     
    • Right click the dojoRest node in the Projects window.
    • Select Clean and Build Project.

  4. Run the project as follows:

     
    • Right click the dojoRest node in the Projects window.
    • Select Run Project.
When you run the project, your browser should display the opening page of the Sample Application (at http://localhost:8080/dojoRest/).

References: