A jMaki widget expects data in JSON format as defined by the standard data models. There are three possible ways to generate the JSON data from a Jersey endpoint that can be consumed by a jMaki widget:
- Return JSON representation of a resource as generated using the BadgerFish convention and then apply a stylesheet (specified in
xhp.json
) to convert the received data into the JSON format as expected by the jMaki widget. This keeps the server code simple but requires a stylesheet to convert from one JSON format (defined by BadgerFish convention) to another JSON format (as expected by the jMaki widget). - Return XML representation of the resource and then apply a stylesheet (specified in xhp.json) to convert the received JSON into the format as expected by the jMaki widget. This keeps the server code simple but requires a stylesheet to convert from the XML format (defined by JAXB) to JSON format (as expected by the jMaki widget).
- Return JSON representation as expected by the jMaki widget. This can be achieved only using low-level JSON APIs on the server-side and can be directly consumed by the jMaki widget.
This TOTD explains 2nd and 3rd bullet. The first bullet can be applied following the solution proposed in 2nd bullet.
- Download and expand the latest Jersey download.
- Download and install GlassFish V2. This will be required for deploying the jMaki project and using Database client and Persistence libraries.
- Open "
examples/HelloWorld
" project in NetBeans 6 IDE. - In the NetBeans IDE, Services tab, expand Databases, right-click on the node with URL "
jdbc:derby://localhost:1527/sample [app on APP]
" and select Connect. Enter the password as "app
" and select "OK
". - Configure the database
- Right-click again on the URL and select "
Execute Command...
" and issue the command:create table BOOKS (title varchar(255),
author varchar(255),
isbn varchar(255),
description varchar(255),
PRIMARY KEY (isbn))This will create the database table.
- Add data to the newly created table using the following command:
INSERT INTO BOOKS VALUES('Marathon', 'Jeff Galloway', 'ABCDEF', 'The best book on running');
INSERT INTO BOOKS VALUES('Run a Marathon', 'Duke', '123456', 'How to train for a marathon ?');You can enter additional rows if you like.
- Right-click again on the URL and select "
- Create the Persistence Unit
- In NetBeans IDE, right-click on the project, select "
New
", "Entity Classes from Database...
". - Choose the Database Connection with the URL given above.
- In the "
Available Tables
", select "BOOKS
" and click on "Add >
". Click on "Next >
". - Click on "
Create Persistence Unit...
", take all the defaults and click on "Create
" and then click on "Finish
". - Add the following NamedQuery "
@NamedQuery(name = "Books.findAll", query = "SELECT b FROM Books b")
" to the generated Books class. - Add the following annotation "
@javax.xml.bind.annotation.XmlRootElement
" to the generated Books class.
- In NetBeans IDE, right-click on the project, select "
- Add a new bean representing the array of Books.
- Right-click on "
com.sun.ws.rest.samples.helloworld
" package, select "New
", "Java Class...
" and enter the Class Name as "BookList
". - Replace the template class with the following code:
package com.sun.ws.rest.samples.helloworld;
/**
* @author Arun Gupta
*/
@javax.xml.bind.annotation.XmlRootElement
public class BookList {
@javax.xml.bind.annotation.XmlElement
protected java.util.List<Books> book;public BookList() {
if (book == null)
book = new java.util.ArrayList<Books>();
}public void add(Books name) {
book.add(name);
}public java.util.List<Books> getValue() {
return book;
}
}
- Right-click on "
- Add a resource that generates the XML and JSON representation to be consumed a jMaki-wrapped DataTable widget.
- Expand Source Packages, right-click on "
com.sun.ws.rest.samples.helloworld.resources
", select "New
", "Java Class...
" and enter the Class Name as "TableResource
". - Replace the generated template class with the following code:
package com.sun.ws.rest.samples.helloworld.resources;
import com.sun.ws.rest.samples.helloworld.BookList;
import com.sun.ws.rest.samples.helloworld.Books;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.ProduceMime;
import javax.ws.rs.UriTemplate;
import javax.xml.bind.JAXBException;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;/**
* @author Arun Gupta
*/
@UriTemplate("/table")
public class TableResource {
@HttpMethod
@ProduceMime("application/xml")
@UriTemplate("/xml")
public BookList getXML() throws JAXBException {
BookList booklist = new BookList();
for (Books b : getBooks()) {
booklist.add(b);
}
return booklist;
}@HttpMethod
@ProduceMime("application/json")
@UriTemplate("/json")
public JSONObject getJSON() throws JSONException {
JSONObject tableDataModel = new JSONObject();
String[] labels = { "Title", "Author", "ISBN", "Description"};
JSONArray columns = new JSONArray();
for (String l : labels) {
JSONObject item = new JSONObject();
item.put("label", l).put("id", l);
columns.put(item);
}
tableDataModel.put("columns", columns);JSONArray rows = new JSONArray();
for (Books b : getBooks()) {
&
nbsp; JSONObject item = new JSONObject();
item.put(labels[0], b.getTitle());
item.put(labels[1], b.getAuthor());
item.put(labels[2], b.getIsbn());
item.put(labels[3], b.getDescription());
rows.put(item);
}
tableDataModel.put("rows", rows);return tableDataModel;
}private List<Books> getBooks() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("HelloWorldPU");
EntityManager em = emf.createEntityManager();
List<Books> list = em.createNamedQuery("Books.findAll").getResultList();
return list;
}
}The
getXML()
method returns only the table rows data in an XML format. This XML representation of the resource is then processed by a stylesheet (specified later in the jMaki application) and converted into the JSON format as expected by the jMaki widget. The stylesheet adds the column information as well. ThegetJSON()
method uses low-level JSON APIs to return the data exactly as expected by the jMaki widget (including the column information).In the case of returning an XML representation we can return the column information as well but that would only complicate the code for this sample purpose.
- Expand Source Packages, right-click on "
- Right-click on "
com.sun.ws.rest.samples.helloworld
", edit "Main.java
" and change line 42 to use "TableResource
" class instead of "HelloWorldResource
". The updated code looks like:HttpHandler handler = ContainerFactory.createContainer(
HttpHandler.class,
TableResource.class);Fix the import.
- Right-click on project, select "
Properties
", choose "Libraries
" and add the following JARs by clicking on "Add JAR/Folder
" button:- "
GLASSFISH_HOME/javadb/lib/derbyclient.jar
" - "
GLASSFISH_HOME/lib/toplink-essentials.jar
" - "
GLASSFISH_HOME/lib/toplink-essentials-agent.jar
"
- "
- Right-click on the Project and select "
Run
".
This concludes developing/configuring/running the Jersey endpoint. Now let’s create a new web application and add a jMaki widget that consumes the resource representation exposed by this endpoint:
- In the NetBeans IDE, create a new Web application project. Make sure to install jMaki plugin in the NetBeans IDE. Enable "
jMaki Ajax Framework
" for the project. - Expand "
Web pages
", "resources
", and edit "xhp.json
" to add the following entries at the end:,
{"id": "jersey-json",
"url":"http://localhost:9998/table/json"
},
{"id": "jersey-xml",
"url":"http://localhost:9998/table/xml",
"xslStyleSheet": "table.xsl"
}This defines two external services (Jersey endpoints) that can be used by the jMaki widgets. The first entry is a Jersey endpoint that returns JSON representation of the resource. The second entry is a Jersey endpoint that returns the XML representation and additionally specifies a stylesheet that converts the data from XML format to the JSON format expected by the jMaki widget.
- Expand "
Web pages
", "resources
", "xsl
" and add a new stylesheet (table.xsl). The content of the stylesheet are given below:<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/><xsl:template match="/">
<xsl:apply-templates select="bookList"/>
</xsl:template><xsl:template match="bookList">
{"columns":
[{"label":"Title","id":"Title"},
{"label":"Author","id":"Author"},
{"label":"ISBN","id":"ISBN"},
{"label":"Description","id":"Description"}],
"rows": [
<xsl:apply-templates select="book" />
]
}
</xsl:template><xsl:template match="book">
{
"Title" : "<xsl:value-of select="title" />",
"Author" : "<xsl:value-of select="author" />",
"ISBN" : "<xsl:value-of select="isbn" />",
"Description" : "<xsl:value-of select="description" />"
}
<xsl:if test="(position()!=last())">,</xsl:if>
</xsl:template>
</xsl:stylesheet> - Drag-and-drop two jMaki-wrapped Yahoo DataTable widget in the main section of the default generated index.jsp.
- Change the generated code fragment to use the values from the different Jersey endpoints instead of using the static values. The updated code fragment will look like:
<a:widget name="yahoo.dataTable"
service="/xhp?id=jersey-json" />
<a:widget name="yahoo.dataTable"
service="/xhp?id=jersey-xml" /> - Deploy the project and now the jMaki-wrapped widgets are now displayed in the browser window as shown below. The Firebug dump shows the data received by jMaki.
Please leave suggestions on other TOTD that you’d like to see. A complete archive is available here.
Technorati: totd jersey jmaki json netbeans glassfish
Related posts:
Hi,
As is usual very good tutorial. Well-explained and clean.
Thank’s for your help.
Comment by Freetrax — October 3, 2007 @ 12:31 am
I’ll need a search with grabs the data from by Database maybe with the autocompleter.
Have you a sample for this problem??
Comment by Anja — October 30, 2007 @ 12:05 pm
I am getting:
javax.persistence.PersistenceException: No Persistence provider for EntityManager named HelloWorldPU
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:89)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:60)
at resources.TableResource.getBooks(TableResource.java:63)
I checked that persistence.xml exists, in the correct places, and db connection is fine.
I think this has to do with a deployment issue, but I could not figure out on my own.
One thing that is not clear is on the article in #3
Expand "Web pages", "resources", "xsl" and add a new stylesheet.
what is the name of the stylesheet? Is not mentioned in the article.
Best Regards,
-C.B.
Comment by [email protected] — November 28, 2007 @ 8:14 pm
I updated the blog with the stylesheet name. Did you check the PU name in persistence.xml is the same as used in the JPA code ?
Comment by Arun Gupta — December 13, 2007 @ 11:45 pm