Friday Jul 18, 2008

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

a Dynamic Ajax table example using jMaki 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 jMaki client which  gets and displays the Web Service responses in a dynamic Ajax table.

Download the jMaki Sample Application Code

jMaki is an Ajax framework that provides a lightweight model for creating JavaScript centric Ajax-enabled web applications. jMaki provides wrapped widgets that can be used as JavaServer Pages tags, as JavaServer Faces components, within a Phobos application, or with PHP. This sample applicaton uses jMaki with JavaServer Pages.

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

pagingtable.jpg

jMaki dataTable widget

With  jMaki and JavaServer Pages, you can easily include wrapped widgets from ajax toolkits into a JavaServer Page as a custom JSP tag. With the Netbeans jMaki plugin you can drag  jMaki widgets from the Palette into a JSP. jMaki standardizes widget data and event models to simplify the programming model and to simplify interactions between widgets.

The sample application's index.jsp page uses a jMaki yahoo.dataTable widget to display a  list of customers in a dynamic table.

The jMaki table widgets (there is also a jMaki dojo table widget) are useful when you want to show a set of results in tabular data on a web page.  Table widgets provide sortable columns, row selection, and they can be updated using jMaki publish subscribe events.

In the List.jsp web page the dataTable is defined as shown below:   (Note: Red colors are for jMaki tags or variables,  and Green for my code or variables)

Code Sample from:  index.jsp

<a:widget name="yahoo.dataTable"
subscribe="/table"
service="webresources/customers/jMakiTable"/>


To determine the data format and events for the table you can refer to the  jMaki Table Data Model or look at the widget.json file for the table widget. This file is located in the resources/yahoo/dataTable directory.

The service attribute references the customers/jMakiTable RESTful web service which returns the data to be included in the table.  The data for the table should be a JSON object containing an object of columns and an array of row arrays. The column names need a unique id which is then used in the data to associate it with a given row. An example for a table of companies is shown below:


Code Sample from:  widget.json
{
 'columns':[
     {'label' :'Company', 'id' : 'name'},
     {'label':'City', 'id' : 'city'},
     {'label':'City', 'id' : 'state'}
 ],
 'rows':[
     {'name' : 'Sun Microsystems', 'city' : 'Santa Clara',
'state' : 'CA'},
     {'name' : 'IBM', 'city' : 'Raleigh','state' : 'NC'}
 ]
}



The subscribe="/table" attribute specifies a topic that events can be sent to. Publish and subscribe events can be used to tie widgets together (more on this later).

RESTful  Web Services with JAX-RS


The dataTable's service attribute references the URI  webresources/customers/jMakiTable for the customers jMakiTable  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.  I added the jMakiTable method to the generated customers Web Service,  in order to return the customers in the jMaki table format. I followed the jMakiBackend example which comes with Jersey (the JAX-RS reference implementation) which is expained in Japods blog:  jMaki Widgets Talking To Jersey Resources In JSON.


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
CustomersConverter get(@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 CustomersResource represents a list of customers. The CustomersResource get method 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 the get method supports the HTTP GET method.
  • @ProduceMime specifies the MIME types that a method can produce. Here, the annotation specifies that the get method returns a JSONArray object.  The CustomersConverter class is a JAXB annotated class which is used to marshal a list of Customer objects into XML or JSON format.   The getEntities method returns a list of Customer entity objects and is explained below.  
  • @QueryParam specifies input parameters for methods.  When the method is invoked, the input value will be injected into the corresponding input argument. 
  • @DefaultValue specifies 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/jMakiRest/webresources/customers/?start=0


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

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


Below is the getTable method  from the CustomersResource.java class,  which returns a list of Customers in the jMaki  JSON table format.

Code Sample from: CustomersResource.java


public class CustomersResource {
     . . .

  @GET
  @Path("/jMakiTable")
  @ProduceMime("application/json")
    public CustomerTableModel getTable(@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) {

        CustomersConverter custs = get(start, max,
                   expandLevel, query);
        return new CustomerTableModel(custs.getCustomer());
    }


The getTable method calls the CustomersResource get method, explained above,  to get a list of Customer Entities which are used to create a CustomerTableModel class. The CustomerTableModel class is a JAXB annotated class, used to marshal a list of Customer objects into the jMaki  JSON table format.  A snippet of the CustomerTableModel class is shown below:


Code Sample from: CustomerTableModel.java

@XmlRootElement
public class CustomerTableModel {

    public static class JMakiTableHeader {

        public String id;
        public String label;

        public JMakiTableHeader(String id,
           String label) {
            this.id = id;
            this.label = label;
        }
    }
    public List<JMakiTableHeader> columns =
          initHeaders();
    public List<CustomerConverter> rows;

  . ..



Java Persistence Query API

The CustomersResource getEntities method uses the Java Persistence API Query object 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);
        return query.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 Customer entity 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 @Entity annotation.
  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 Customer implements 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;
    }



}   


jMaki Publish Subscribe events 

jMaki publish subscribe events tie widgets actions together. The sample app uses two jMaki yahoo.button widgets which publish to the /button/previous, /button/next topics when the respective button is clicked:

Code Sample from: List.jsp

<a:widget name="yahoo.button" value="{label : '<<',
                 action : {topic : '/button/previous'}}" />

<a:widget name="yahoo.button" value="{label : '>>',
                 action : {topic : '/button/next'}}" />


Events in jMaki are handled by jMaki Glue , which allows JavaScript components to talk to each other. You put function listeners which Subscribe to topics that your widgets Publish to in a file called glue.js (to read more about this see A practical guide to jMaki Events ).

Connecting the listener to the handler

The listener handler for the  /button/next topic is shown below. First you declare the topic to listen to and then the listener function which will handle the notification. The /button/next listener handler  increments the page number and then calls the getNextPage funtion.

Code Sample from: glue.js

var page= 0;
var start= 0;
var batchSize=4;

jmaki.subscribe("/button/next", function(args) {
    page =page + 1;
    getNextPage
(page);
});

jmaki.subscribe("/button/previous", function(args) {
    page =page - 1;
    if (page < 0) page = 0;
    getNextPage
(page);
});

function getNextPage(page) {
    start = page \* batchSize;
    jmaki.doAjax
({method: "POST",
      url:
"webresources/customers/?start="+encodeURIComponent(start),
      callback :
function(req) {
        var respObj = eval('('+ req.responseText +')');

        var rows =  respObj.customers.customer;

        jmaki.publish
("/table/clear", { });
        for(j=0;j<rows.length;j++) {
           var row = rows[j];
           jmaki.publish
("/table/addRow",{value: row});
        }
      }
  });    
}


The getNextPage function uses  jmaki.doAjax, which provides an easy way to make an  XMLHttpRequest, to call the /customers/ RESTful Web Service  passing the start index  as a URI parameter.  The  callback function uses  eval to convert the XMLHttpRequest response into a JSON object. Then  jmaki.publish is called to publish the returned customer JSON objects to the /table/addRow topic.

The yahoo.dataTable widget subscribes to the table topic.
Subscribe events allow you to manipulate a given instance of a widget. The event names are appended to the the subscribe topic name following a "/". For example  "/table/addRow" will call the yahoo.dataTable addRow function which will add the  payload value passed to the widget to the the table. This will cause the  returned customer JSON object to be displayed in the table on the html page.


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  jMaki  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  Download and install GlassFish V2 separately.
  • Download and install the jMaki plug-in in the NetBeans update center.

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>/jmakiRest, 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 at C:\\jmakiRest.

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

  3. Build the project as follows:

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

  4. Run the project as follows:

    • Right click the jmakiRest 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/jmakiRest/).


If you want to create your own jMaki application:
  • check out Arun Gupta's blog and screencasts.

References:




About

caroljmcdonald

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today