Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs
This Sample Store Catalog app demonstrates the usage of JSF,
the new Java Persistence APIs, and a Stateless Session EJB to implement pagination in a Java EE 5 application
target="bpcatalog">Sean
Brydon
target="bpcatalog">
Carol McDonald
Pagination using Java Persistence APIs
The Java Persistence
href="http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html">Query
APIs are used to create and execute queries that can return a
list of results. The query APIs also have some methods that
you can use to specify the chuck of a list you desire, in particular:
-
<a
href="http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html"
title="interface in javax.persistence">Query</a> <b>setMaxResults</b>(int maxResult)
Set the maximum number of results to retrieve. -
<a
href="http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html"
title="interface in javax.persistence">Query</a> <b>setFirstResult</b>(int startPosition)
Set the position of the first result to retrieve.
Lets consider an example, assume you have an Item.java object
that is a Java Persistence object entity and each item object
represents a row in the database. Lets assume the database is populated
with 100 items that have a productID="dog", and a client web
application wants to retrieve 10 items at a time. Lets look at some
code to use in this type of example.
showing usage of the setFirstResult and setMaxResults method
public
List<Item> getItemsVLH(String pID, int start, int
chunkSize){<br>
EntityManager em =
emf.createEntityManager(); <br>
Query query = <br>
em.createQuery("SELECT i FROM Item i WHERE i.productID = :pID");<br>
query = query.setParameter("pID",pID);<br>
query = query.setFirstResult(start); query =
query.setMaxResults(chunkSize);
List<Item> items = query.getResultList();<br>
em.close();<br>
return items;<br>
}<br>
<br>
The key line in code example 1 is
List<Item> items =
query.setParameter("pID",pID).setFirstResult(start).setMaxResults(chunkSize).getResultList();which sets the query up and gets the results. Note the
query.setFirstResult startscounting at zero. In this example, the client, maybe a JSP page
or Servlet, would need to keep track of the index position of the list
it is showing to the users. For example if it is showing the dogs from
index position 10 through 19 on its page and the user clicked the
"next" button then the JSP would have to submit the index position that
it desired 20 and the chunk size 10 to get the dogs at index positions
20 through 29. As you can see these APIs are easy to use and very
useful.
In code example 2 below, we show the
Item.java object. Notice this is just a
typical Java Persistence entity object, and we just show it here for
completeness of the example.
Now lets consider some design choices when using these APIs:
- The
Java Persistence APIs use lazy loading by default so you do not get a
deep copy of the objects that are retrieved. For example, in the list
of items, each Item contains all the data in the fields but does not
contain the data in the relationships, such as the tags which are
declared as
(seeprivate Collection<Tag>
tags=new Vector<Tag>();
code example 2).
This is because of the performance implications of fetching a list of
objects and all of the network of objects in their relationships. You
can change the fetching to eager or if you want you can fetch the data
in a relationship by calling the get method on that field on the
managed object.
<br>
@Entity<br>
public class Item implements java.io.Serializable {<br>
<br>
private String itemID;<br>
private String productID;<br>
private String productID;<br>
private String name;<br>
private String description;<br>
private BigDecimal price;<br>
private Address address;<br>
private Collection<Tag>
tags=new Vector<Tag>();<br>
<br>
public Item() { }<br>
<br>
@Id<br>
public String getItemID() {<br>
return itemID;<br>
}<br>
public String getProductID() {<br>
return productID;<br>
}<br>
public String getProductID() {<br>
return productID;<br>
}<br>
public String getName() {<br>
return name;<br>
} <br>
public String getDescription() {<br>
return description;<br>
}<br>
public BigDecimal getPrice() {<br>
return
price;<br>
} <br>
@OneToOne(cascade={CascadeType.PERSIST})<br>
public Address getAddress() {<br>
return address;<br>
} <br>
@ManyToMany(mappedBy = "items")<br>
public Collection<Tag>
getTags() {<br>
return tags;<br>
} <br>
public void setItemID(String itemID) {<br>
this.itemID = itemID;<br>
} <br>
public void setProductID(String
productID) {<br>
this.productID = productID;<br>
}<br>
public void setName(String name) {<br>
this.name = name;<br>
}<br>
public void setDescription(String
description) {<br>
this.description = description;<br>
}<br>
public void setPrice(BigDecimal price) {<br>
this.price = price;<br>
}<br>
public void setAddress(Address address) {<br>
this.address = address;<br>
}<br>
public void
setTags(Collection<Tag> tags) {<br>
this.tags=tags;<br>
}<br>
... could add other business methods too<br>
} <br>
<br>
Explanation of the usage of JSF, Catalog Facade Stateless
Session EJB , and Java Persistence APIs in a sample Store Catalog Application
The image below shows the Catalog Listing page, which allows a user to page through a list of items
in a store.
The List.jsp page uses a JSF dataTable component to display a list of
catalog items
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.jsp web page the dataTable is defined as shown below:
<br>
<h:dataTable value='#{item.items}' var='dataTableItem' border="1"<br>
cellpadding="2" cellspacing="0"><br>
<br>
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 UIData
component iterates through the list, each reference to dataTableItem points to the current item in the
list.
The dataTable's value
is bound to the items property
of the item controller class, ItemController, which is defined in the
faces-config.xml file:
<br>
<managed-bean><br>
<managed-bean-name><b>item</b></managed-bean-name><br>
<managed-bean-class><br>
com.sun.javaee.blueprints.sessionpagination.ItemController<br>
</managed-bean-class><br>
<managed-bean-scope>session</managed-bean-scope><br>
</managed-bean><br>
<br>
This ItemController ManagedBean items
property is defined as shown below:
@EJB private CatalogFacade
catalogfacade;<br>
<br>
public DataModel <b>getItems</b>()
{<br>
model = new
ListDataModel(catalogFacade.getItems( firstItem,batchSize));<br>
return
model; <br>
}<br>
<br>
The getItems() method wraps a List of items, returned from the
CatalogFacade Stateless Session EJB, in a DataModel.
UIData, the superclass of dataTable, supports data binding to a
collection of data objects represented by a DataModel instance, which
is the current value of this component itself. 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 Name, Photo, and Price item properties are displayed with the
column component:
<br>
<h:column><br>
<f:facet name="header"><br>
<h:outputText
value="Price"/><br>
</f:facet><br>
<h:outputText
value="#{dataTableItem.price}"/><br>
</h:column><br>
<br>
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
(item.items) and displays the names, photos, and prices. Each
time UIData iterates through the list of items, it renders one cell in
each column.
The dataTable and column tags use facets to represent parts of the
table that are not repeated or updated. These include headers, footers,
and captions.
The ItemController ManagedBean uses dependency injection to lookup and
obtain a reference to the CatalogFacade Stateless Session EJB :
<br>
@EJB private CatalogFacade catalogfacade;<br>
<br>
The CatalogFacade Session EJB uses the Java Persistence API
EntityManager Query object to return a list of items.
The Catalog Facade uses dependency injection to lookup and obtain a
Container Managed EntityManager.
Since the EntityManager can be container managed for EJB Session
Beans, the application does not
have to manage its lifecycle (i.e. call the
EntityManagerFactory.create() and EntityManager.close() methods).
<br>
@Stateless<br>
public class CatalogFacadeBean implements CatalogFacade { <br>
@PersistenceContext(unitName="PetCatalogPu")<br>
private EntityManager entityManager;<br>
<br>
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)<br>
public List<Item> getItems(int
firstItem,int batchSize) { <br>
Query q =
entityManager.createQuery("select object(o) from Item as o");<br>
q.setMaxResults(batchSize);<br>
q.setFirstResult(firstItem);<br>
List<Item> items=
q.getResultList();<br>
return
items; <br>
}<br>
<br>
Since this query is used for Read-Only browsing, the transaction
attribute in this example is specified as NOT_SUPPORTED. Queries using
transaction-scoped entity managers outside of a transaction are
typically more efficient than queries inside a transaction when the
result type is an entity. The JPA Query interface provides
support for pagination via the setFirstResult() and setMaxResults()
methods.
The ItemController ManagedBean pages through the list of items by
maintaining the firstItem and batchSize attributes and passing these as
parameters to the catalogFacade.getItems(firstItem, batchSize) method.
The ItemController's scope is defined as session, 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.
The ItemController itemCount property is used to get and display
the number of Catologue items in the data base:
<br>
<h:outputText value="Item #{item.firstItem + 1}..#{item.lastItem} of<br>
#{item.itemCount}"/><br>
<br>
This ItemController property is defined as shown below:
<br>
public int getItemCount()
{ <br>
int count =
catalogFacade.getItemsCount();<br>
return
count; <br>
}<br>
The ItemController getItemCount() method calls the CatalogFacade to get
the count of the list of items. The Catalog Facade Session EJB
getItemCount() method uses the JPA Query interface to get the count of
all items in the database item table:
<br>
public int getItemCount() {<br>
Query q =
entityManager.createQuery("select count(o) from Item as
o"); <br>
int count =
((Long)q.getSingleResult()).intValue(); <br>
return count;<br>
} <br>
<br>
A JSF commandLink is used to provide a link to click on to
display the next page of items. The commandLink
tag represents an HTML hyperlink and is rendered as an HTML <a> element. The commandLink
tag is used to submit an action event to the application.
<br>
<h:commandLink action="#{item.next}" value="Next
#{item.batchSize}"<br>
rendered="#{item.lastItem + item.batchSize <=
item.itemCount}"/> <br>
This commandLink action attribute
references an ItemController backing bean next() method that calculates
the
next page's first row number and returns a logical outcome
String, which causes the List page to display the next page's
list .
This ItemController next method is defined as shown below:
public String next() {<br>
if (firstItem + batchSize
< getItemCount()) {<br>
firstItem += batchSize;<br>
}<br>
return "<b>item_list</b>";<br>
} <br>
The JavaServer Faces NavigationHandler
matches the logical outcome, item_list
against the navigation rules in the application configuration resource
file to determine which page to access next. In this case, the
JavaServer Faces implementation loads the List.jsp
page after this method returns.
<navigation-rule><br>
<navigation-case><br>
<from-outcome><b>item_list</b></from-outcome><br>
<to-view-id>/item/List.jsp</to-view-id> <br>
</navigation-case><br>
</navigation-rule><br>
<br>
A JSF commandLink is used to provide a link to click on to
display the previous page of items. This
commandLink
action attribute references the ItemController prev() method that calculates the
previous page's first row number and returns a logical outcome
String, which causes the List page to display the previous page of
items :
<br>
<h:commandLink action="#{item.prev}" value="Previous
#{item.batchSize}" <br>
rendered="#{item.firstItem >=item.batchSize}"/> <br>
<br>
This ItemController previous() method is defined as shown
below:
public String <b>prev</b>()
{<br>
firstItem -= batchSize;<br>
if (firstItem < 0) {<br>
firstItem = 0;<br>
}<br>
return "item_list";<br>
} <br>
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 ItemController detailSetup() method:
<br>
<h:column><br>
<f:facet name="header"><br>
<h:outputText
value="Name"/><br>
</f:facet><br>
<h:commandLink action="#{item.<b>detailSetup</b>}"
value="#{dataTableItem.name}"/> <br>
</h:column> <br>
The item.detailSetup () method gets the Item data from the
current row of the dataModel, and returns a string which causes the
Detail.jsp page to display
the item details :
<br>
public String detailSetup() {<br>
item = (Item)
model.getRowData();<br>
return "<b>item_detail</b>";<br>
}<br>
The JavaServer Faces NavigationHandler
matches the logical outcome, item_detail
against the navigation rules in the application configuration resource
file to determine which page to access next. In this case, the
JavaServer Faces implementation loads the Detail.jsp
page after this method returns.
<br>
<navigation-rule><br>
<navigation-case><br>
<from-outcome><b>item_detail</b></from-outcome><br>
<to-view-id>/item/Detail.jsp</to-view-id><br>
</navigation-case><br>
</navigation-rule>
The Detail.jsp uses the outputText component to display the
ItemController ManagedBean's item properties:
<br>
<h:outputText value="#{item.item.name}" title="Name" /><br>
<h:outputText value="#{item.item.description}"
title="Description"/><br>
<h:graphicImage url="#{item.item.imageurl}" title="Imageurl" /><br>
<h:outputText value="#{item.item.price}" title="Price" /><br>
<h:outputText value="#{item.item.address.city}" title="Address" /><br>
<h:outputText value="#{item.item.contactinfo.email}"
title="Address"/>
Conclusion
This concludes the sample application which demonstrates how to work
with the JSF dataTable and DataModel to page through a list
of Item Entities which are retrieved using the
CatalogFacade Stateless Session EJB methods which use the
Java
Persistence API.
References
Here are some references to consider:
-
href="https://blueprints.dev.java.net/bpcatalog/ee5/persistence/index.html">Java
BluePrints Solutions Catalog for the Java Persistence APIs
contains a collection of topics and example applications. -
target="bpcatalog">Java
Persistence reference page on GlassFish Project - For older J2 EE 1.4 applications see the
href="http://java.sun.com/blueprints/patterns/ValueListHandler.html">Value
List Handler pattern described on the blueprints website.
This description is for J2EE 1.4 and older applications suing those
older versions of EJB but can be useful references. - Java EE tutorial
- Pro EJB 3: Java Persistence API book
- Login or register to post comments
- Printer-friendly version
- caroljmcdonald's blog
- 21858 reads






Comments
Pagination of Data Sets in a
by hzapata - 2011-02-13 16:16
I try download sample code, but I am redirect to pages "ERROR. Your account does not have the "Project Document - View" permission needed for you to access the page you requested in the techdayscode project "
How I can get permission for download?
by deb - 2011-11-21 11:17
I have the same problem. Where can I get the code?
I try download sample code, but I am redirect to pages "ERROR. Your account does not have the "Project Document - View" permission needed for you to access the page you requested in the techdayscode project "
How I can get permission for download?
I think the project that had the source code has been ...
by caroljmcdonald - 2011-11-21 12:07
I think the project that had the source code has been deleted. I will try to find it