Sample Application using dojo, the Java API for Restful Web
Services JAX-RS, and the Java Persistence APIs
a RESTful Pet Catalog
This Sample Pet Store
Catalog application shows how to expose a Catalog as a
RESTful Web Service for remote client applications, and it shows how to
code a
Dojo
client which gets and displays the Web Service responses in
a dynamic Ajax table (
Dojo
grid). I re-implemented
this
Sample Catalog application implemented with JAX-WS on the server side
and JSF on the client side which is also available in the
Java One Metro hands on lab.
Download
the RESTful Pet Catalog 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 Catalog Listing page, which allows a user to
page through a list of items
in a store.
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.
Dojo style sheets
Every page using the dojo Grid needs to import the grid style sheet
Grid.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.css instead 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 |
formatImage =
function(value) {
if (!value)
return
' ';
return "<img src='" +
value + "'/>";
};
// Data Grid layout // A grid view is a group of columns
var view1 = {
cells: [
[
{name: 'Name', field: "name"},
{name: 'Description', field: "description", width: '200px'},
{name: 'Photo',field: "imagethumburl", formatter: formatImage, width:
'120px'},
{name: 'Price',field: "price"}
]
]
};
// a grid layout is an array of views.
var layout = [ view1 ];
|
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 the
dojox.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 items
list
model.setData(responseObject.items.item);
}
// make request to the items web service
function loadTable(page){
start = page * batchSize;
var targetURL = "resources/items/?start="+
encodeURIComponent(start);
dojo.xhrGet({
url: targetURL,
handleAs: "json",
load: handleResponse,
error: handleError
});
}
|
The
loadTable
function calls
dojo.xhrGet to
make an XMLHttpRequest to the
items 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
items JAX-RS web service. Below is an example of a
JSON response from the
items
JAX-RS web service:
Example json data |
{"items":
{"@uri":"http://host/catalog/resources/items/",
"item":[
{"@uri":"http://host/catalog/resources/items/1/",
"name":"Friendly Cat",
"description":"This black and white
colored cat is super friendly.",
"id":"1",
"imageurl":"http://localhost:8080/CatalogService/images/anthony.jpg"},
{"@uri":"http://host/catalog/resources/items/2/",
"name":"Fluffy Cat",
"description":"A great pet for a
hair stylist!
"id":"2",
"imageurl":"http://localhost:8080/CatalogService/images/bailey.jpg"}
]
}
}
|
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
items 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 the
loadTable()
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/items/ for the
items
RESTful web service. The items
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 items
RESTful web
service was generated from the item data base table (the sql is in the
how to run section).
Below is a snippet from the
ItemsResource.java
class which was generated by the Netbeans "Generate RESTful Web
Services
from Entity Classes" feature :
Code Sample from: ItemsResource.java |
// Service URI path
"/items/"
@Path("/items/")
public class ItemsResource
{
@GET
@ProduceMime("application/json")
public ItemsConverter 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 Item e") String query) {
try {
ItemsConverter items = new ItemsConverter(
getEntities(start,
max, query),
context.getAbsolutePath(), expandLevel);
return items;
} finally {
PersistenceService.getInstance().close();
}
}
|
The
ItemsResource
represents a list of items. The
ItemsResource
get method
returns a list of Item 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 ItemsResource
the URI path is /items/.
@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 ItemsConverter
class is a JAXB
annotated class which is used to marshal a list of Item objects
into XML or JSON
format. The getEntities method
returns a list of Item 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:
Here is an example of an HTTP response for this Web Service:
Received:
{"items":
{"@uri":"http://host/catalog/resources/items/",
"item":[
{"@uri":"http://host/catalog/resources/items/1/",
"name":"Friendly Cat",
"description":"This black and white
colored cat is super friendly.",
"id":"1",
"imageurl":"http://localhost:8080/CatalogService/images/anthony.jpg"},
{"@uri":"http://host/catalog/resources/items/2/",
"name":"Fluffy Cat",
"description":"A great pet for a
hair stylist!
"id":"2",
"imageurl":"http://localhost:8080/CatalogService/images/bailey.jpg"}
]
}
} |
The
ItemsConverter
class is a
JAXB annotated
class, used to marshal a list of Item objects into XML or
JSON format. A snippet of the
ItemsConverter
class is shown below:
Code Sample from: ItemsConverter.java |
@XmlRootElement
public class ItemsConverter {
@XmlElement
public Collection<ItemConverter>
getItem(){
...
return items;
}
@XmlAttribute
public URI
getUri() {
return uri;
}
|
Java Persistence Query API
The
ItemsResource getEntities
method
uses the Java Persistence API
Query object
to return a list of
items.
Code Sample from: ItemsResource.java |
@Path("/items/")
public class ItemsResource
{
.
. .
protected Collection<Item> 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 Item
entity class which maps to the item table that stores the
item instances. This is a
typical Java Persistence entity object. There are two requirements for
an entity:
- annotating the class with an
@Entity
annotation.
- 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: Item.java |
@Entity
public class Item
implements Serializable {
@Id
private Long id;
private String name;
private String description;
private String imageurl;
private String state;
private BigDecimal price;
public Item() { }
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 items, and a dojo
client which gets and displays the Web Service responses in
a dynamic Ajax table.
Configuration of the Application
for Netbeans 6.5m1 , Glassfish V2, and MySQL
Running the Sample Code
- Download the sample
code and extract its contents. You should now see the newly
extracted directory
as
<sample_install_dir>/catalog, where <sample_install_dir>
is the directory
where you unzipped 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:\catalog.
- Start NetBeans IDE. Click Open Project in the File menu and
select the
catalog directory you just
unzipped.
- Start the MySQL database as follows:
- Click the Services tab in the NetBeans IDE.
- Expand the databases node. You should see the MySQL server
database in the list of databases.
- Right-mouse click on the MySQL server database and select
Start.
- Create the catalog database as follows:
- Right-mouse click on the MySQL server database and select
Create Database.
- Enter the database name catalog. This will open a New
Database Connection window. Click O.K. to accept the displayed
settings.
- Create the tables in the MySQL catalog database as follows:
- Expand the Drivers node. You should a driver for the catalog
database in the list of drivers.
- Right-mouse click on the catalog driver and select Connect.
- Right-mouse click on the catalog driver and select Execute
Command. This will open up a SQL command window.
- Copy the contents of the
createdbmysql.sql file
in the catalog directory and paste the contents into the
SQL command window.
- Click the Run SQL icon
(Ctrl+Shift+E) above the SQL command window.
- Build the project as follows:
- Right click the
catalog node in
the
Projects window.
- Select Clean and Build Project.
- Run the project as follows:
- Right click the
catalog 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/catalog/).
For more Information: