SQL Zone is brought to you in partnership with:

As a Java Architect at Sun Microsystems, Carol McDonald has spoken at various conferences including JavaOne, Java University, Sun Tech Days, Sun Network, Sun Code Camps, JDJEdge, and JUGs including Machester, Boston, Maine, Cologne, FAA, Richmond, Memphis, D.C... Carol blogs about the latest technologies that she is speaking about at http://weblogs.java.net/blog/caroljmcdonald/. Before returning to Sun in 2007, Carol worked 2 1/2 yrs as an Architect on massive OLTP Spring/hibernate application to manage > 10 mill loans for the consumer credit division of a leading automoblile manufacturer and a leading bank. Before joining Sun the first time in 1999 Carol worked on Pharmaceutical Intranet applications for Roche in Switzerland, a Telecom Network Management Application for Digital (now HP) in France, a X.400 Email Server for IBM in Germany, and as a student intern for the National Security Agency. Carol holds a M.S. in Computer Science from the University of Tennessee, a B.S. in Geology from Vanderbilt University, and is a Sun Certified Java Architect and Java Language Programmer. Carol is also Fluent in French and German. Carol has posted 11 posts at DZone. View Full User Profile

JSF 2.0, JPA, GlassFish and MySQL

07.31.2009
| 25071 views |
  • submit to reddit

This Pet Catalog app explains a web application that uses JSF 2.0, JPA, GlassFish and MySQL. I took this example  GlassFish and MySQL, Part 2: Building a CRUD Web Application With Data Persistence and modified it to use some of the new features JSF 2.0. 

The image below shows the Catalog Listing page, which allows a user to page through a list of items in a store.




JSF 2.0 Facelets XHTML instead of JSP

For JSF 2.0, Facelets XHTML is the preferred way to declare JSF Web Pages. JSP is supported for backwards compatibility, but not all JSF 2.0 features will be available for views using JSP as their page declaration language.  JSF 2.0 Facelets has some nice features like templating (similar in functionality to Tiles) and composite components, which I'm not going to discuss here but you can read about that in this article: http://www.ibm.com/developerworks/java/library/j-jsf2fu2/index.html and in this Tech Tip Composite UI Components in JSF 2.0.

The Catalog application's resources

JSF 2.0 standardizes how to define web resources. Resources are any artifacts that a component may need in order to be rendered properly -- images, CSS, or JavaScript files.  With JSF 2.0 you put resources in a resources directory or a subdirectory.



In your Facelets pages, you can access css files with the  <h:outputStylesheet>,  javascript files with the <h:outputScript> , and images with the <h:graphicImage> JSF tags. The list.xhtml uses the  <h:outputStylesheet tag to load the styles.css stylesheet , and the <h:graphicImage tag to display images from the resources as shown below:

<h:outputStylesheet name="css/styles.css" target="body"/>
<h:graphicImage library="images" name="banner_logo.gif" />

The Catalog application uses a resource bundle to contain the static text and error messages used by the Facelets pages. Putting messages in a resource bundle makes it easier to modify and internationalize your Application text.  The messages are in a properties file in a java package directory.

Title=Pet Catalog
Next=Next
Previous=Prev
Name=Name

The resource bundle is configured in the faces-config.xml File (you don't need any other configuration in the faces-config.xml for JSF 2.0, as explained later you no longer have to configure managed beans and navigation with XML).

 <application>
<resource-bundle>
<base-name>web.WebMessages</base-name>
<var>msgs</var>
</resource-bundle>
</application>

The List.xhtml facelets page uses a JSF dataTable component to display a list of catalog items in an html table.  The dataTable component is useful when you want to show a set of results in a table. In a JavaServer Faces application, the UIData component (the superclass of dataTable)  supports binding to a collection of data objects. It does the work of iterating over each record in the data source. The HTML dataTable renderer displays the data as an HTML table.

In the list.xhtml web page the dataTable is defined as shown below:  (Note: Red colors are for Java EE tags, annotations code,  and Green is for my code or variables)

<h:dataTable value='#{catalog.items}' var='row' border="1"
cellpadding="2" cellspacing="0">

The value attribute of a dataTable tag references the data to be included in the table. The var attribute specifies a name that is used by the components within the dataTable tag as an alias to the data referenced in the value attribute of dataTable.  In the dataTable tag from the List.jsp page, the value attribute points to a list of catalog items. The var attribute points to a single item in that list. As the dataTable component iterates through the list, each reference to dataTableItem points to the current item in the list.

JSF 2.0 Annotations instead of XML configuration

The dataTable's value is bound to the items property of the catalog managed bean. With JSF 2.0 managed beans do not have to be configured in the faces-config.xml file, you annotate the managed beans instead as shown below:

@ManagedBean
@SessionScoped
public class Catalog implements Serializable {

By convention, the name of a managed bean is the same as the class name, with the first letter of the class name in lowercase. To specify a managed bean name you can use the name attribute of the ManagedBean annotation, like this: @ManagedBean(name = "Catalog").

This Catalog ManagedBean items property is defined as shown below:

    private DataModel items = null;

public DataModel getItems() {
if (items == null) {
getPagingInfo();
items = new ListDataModel(getNextItems(pagingInfo.getBatchSize(), pagingInfo.getFirstItem()));
}
return items;
}

The getItems() method wraps a List of item objects in a DataModel. UIData, the superclass of dataTable, supports data binding to a collection of data objects represented by a DataModel instance.  The data collection underlying a DataModel instance is modeled as a collection of row objects that can be accessed by a row index.  The APIs provide mechanisms to position to a specified row index, and to retrieve an object that represents the data that corresponds to the current row index.   

The Item properties Name, Photo, and price are displayed with the column component:

<h:dataTable var="row" value="#{catalog.items}">
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.Name}"/>
</f:facet>
<h:outputText value="#{row.name}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.Photo}"/>
</f:facet>
<h:graphicImage library="images" name="#{row.imagethumburl}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.Price}"/>
</f:facet>
<h:outputText value="#{row.price}"/>
</h:column>
</h:dataTable>

The column tags represent columns of data in a UIData component. While the UIData component is iterating over the rows of data, it processes the UIColumn component associated with each column tag for each row in the table.

The UIData component  iterates through the list of items (catalog.items)  and displays the row.price. Each time UIData iterates through the list of items, it renders one cell in each column.

The dataTable and column tags use facet to represent parts of the table that are not repeated or updated. These include headers, footers, and captions.

Using the Java Persistence API (JPA) with JSF

The Catalog ManagedBean uses the Java Persistence API EntityManager Query object to return a list of items. The Catalog ManagedBean annotates the field private EntityManager em;  with @PersistenceUnit , which causes an entity manager factory to be injected when the managed bean is instatiated.

@ManagedBean
@SessionScoped
public class Catalog implements Serializable {

@PersistenceUnit(unitName = "catalogPU")
private EntityManagerFactory emf;

private EntityManager getEntityManager() {
return emf.createEntityManager();
}

public List<Item> getNextItems(int maxResults, int firstResult) {
EntityManager em = getEntityManager();
try {
Query q = em.createQuery("select object(o) from Item as o");
q.setMaxResults(maxResults);
q.setFirstResult(firstResult);
return q.getResultList();
} finally {
em.close();
}
}

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: q.setMaxResults(int maxResult) sets the maximum number of results to retrieve. q.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:

  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.  The O/R  relationships with Address and Product are also annotated. For more information on defining JPA entities see Pro EJB 3: Java Persistence API book.


@Entity
public class Item implements java.io.Serializable {

@Id
private Integer id;
private String name;
private String description;
private String imageurl;
private String imagethumburl;
private BigDecimal price;
@ManyToOne
private Address address;
@ManyToOne
private Product product;

public Item() { }

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

...
}

The Catalog ManagedBean pages through the list of Items by maintaining the PagingInfo.firstItem and PagingInfo.batchSize attributes and passing these as parameters to the  getNextItems(firstItem, batchSize) method. The catalog's scope  is defined with the annotation @SessionScoped, a JSF Managedbean with session scope will be stored in the session meaning that the bean's properties will stay alive for the life of the Http Session.

A JSF commandButton is  used to provide a button to click on to display the next page of items.  The commandButton tag is used to submit an action event to the application. 

 <h:commandButton action="#{catalog.next}" value="#{msgs.Next}" />   

This commandButton action attribute references the catalog Managed bean next() method which calculates the next page's first row number  and returns a logical outcome String, which causes the list.xhtml page to display the next page's list . The catalog next method is defined as shown below:


   public String next() {
if (firstItem + batchSize < itemCount()) {
firstItem += batchSize;
}
return "list";
}

JSF 2.0 Simplified Navigation

The JavaServer Faces 2.0  NavigationHandler convention adds .xhtml to the logical outcome of the action method (in this example list) and loads that file, in this case, it loads the list.xhtml page after this method returns. If the action doesn't begin with a forward slash (/), JSF assumes that it's a relative path.  You can specify an absolute path by adding the slash like this "/items/list".

A JSF commandLink is  used to provide a link to click on to display a page with the item details. This commandLink action attribute  references The catalog getDetail() method:

   <h:column>
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:commandLink action="#{catalog.getDetail}" value="#{row.name}"/>
</h:column>

The catalog getDetail() method  gets the item data from the current row of the dataModel, and returns a string which causes the detail.xhtml page to display the item details :

public String getDetail() {
item = (Item) model.getRowData();
return "detail";
}

The JavaServer Faces NavigationHandler adds .xhtml to the logical outcome of the action, detail and loads that file. In this case, the JavaServer Faces implementation loads the detail.xhtml page after this method returns.

The detail.xhtml uses the outputText component to display the catalog ManagedBean's item properties:

    <h:outputText value="#{catalog.item.name}" title="Name" />
<h:outputText value="#{catalog.item.description}" title="Description"/>
<h:graphicImage library="images" name="#{catalog.item.imageurl}" title="Imageurl" />
<h:outputText value="#{catalog.item.price}" title="Price" />
<h:outputText value="#{catalog.item.address.city}" title="Address" />
<h:outputText value="#{catalog.item.contactinfo.email}" title="Address"/>  



Hot Deployment and Session Retention with JSF 2.0 and Glassfish
  • Incremental compile of all JSF 2.0  artifacts when you save.
  • Auto-deploy of all web or Java EE 6 artifacts
  • Session retention: maintain stateful sessions across re-deployments


Conclusion

This concludes the sample application which demonstrates a pet catalog web application which uses JSF 2.0, JPA, GlassFish and MySQL. Next let's run the application. 

Published at DZone with permission of its author, Carol Mcdonald.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Reza Rahman replied on Fri, 2009/07/31 - 8:34am

Carol,

Great demonstration of some of the newer Java EE 6 features. I noticed the manual creation of the entity manager and the lack of transactions. Are you planning on adding @Stateless or @Stateful to avoid these? Also, I would suggest adding some unit testing code since what's what a lot of developers seem to feel Java EE 6 lacking due to the specific enhancements like embedded containers (OpenEJB is a great example) to standardize unit testing in Java EE.

Cheers,
Reza

Carol Mcdonald replied on Mon, 2009/08/10 - 9:29am

Hi Reza,

I like your book btw. Yes I plan on showing more  java ee 6 features  with  glassfish v3 later, like packaging EJBs in a war. I developed this example with just JSF 2.0 and it runs on Glassfish v2 or v3. I'm having some problems with java ee 6 on my mac now, I think because I don't have Java se 6 on my mac, needs more looking into. 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.