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
download sample code

Sean Brydon
Carol McDonald

 

Pagination using Java Persistence APIs 

The Java Persistence 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:

  • Query setMaxResults(int maxResult)
    
    Set the maximum number of results to retrieve.
  • Query setFirstResult(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.

           
Code Sample: Method showing usage of the setFirstResult and setMaxResults method
public List<Item> getItemsVLH(String pID, int start, int chunkSize){
        EntityManager em = emf.createEntityManager();      
        Query query =
          em.createQuery("SELECT i FROM Item i WHERE i.productID = :pID");
        query = query.set
Parameter("pID",pID);
        query = query.
setFirstResult(start);
        query = query.setMaxResults(chunkSize);
        List<Item>  items = query.getResultList();
        em.close();
        return items;
    }


The key line in code example 1is 
List<Item>  items = query.setParameter("pID",pID).setFirstResult(start).setMaxResults(chunkSize).getResultList(); 
which sets the query up and gets the results. Note thequery.setFirstResult starts counting 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 private Collection<Tag> tags=new Vector<Tag>();  (see 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.
           
Code Sample from: Item.java

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

    private String itemID;
    private String productID;
    private String productID;
    private String name;
    private String description;
    private BigDecimal price;
    private Address address;
    private Collection<Tag> tags=new Vector<Tag>();
    
    public Item() { }
   
    @Id
    public String getItemID() {
        return itemID;
    }
    public String getProductID() {
        return productID;
    }
    public String getProductID() {
        return productID;
    }
    public String getName() {
        return name;
    }   
    public String getDescription() {
        return description;
    }
    public BigDecimal getPrice() {
       return price;
    } 
    @OneToOne(cascade={CascadeType.PERSIST})
    public Address getAddress() {
        return address;
    }
    @ManyToMany(mappedBy = "items")
    public Collection<Tag> getTags() {
        return tags;
    }

   
    public void setItemID(String itemID) {
        this.itemID = itemID;
    }    
    public void setProductID(String productID) {
        this.productID = productID;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public void setTags(Collection<Tag> tags) {
        this.tags=tags;
    }
    ... could add other business methods too
}   



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.

listpage.jpg

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:

        
Code Sample from:  List.jsp

<h:dataTable value='#{item.items}' var='dataTableItem' 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 valueattribute 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:

        
Code Sample from: faces-context.xml

 <managed-bean>
    <managed-bean-name>item</managed-bean-name>
      <managed-bean-class>
         com.sun.javaee.blueprints.sessionpagination.ItemController
      </managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
 </managed-bean>



This ItemController ManagedBean items property is defined as shown below:

        
Code Sample from: ItemController.java

       @EJB private CatalogFacade catalogfacade;

   public DataModel getItems() {
       model = new ListDataModel(catalogFacade.getItems( firstItem,batchSize));
       return model;       
   }


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:

        
Code Sample from: List.jsp

  <h:column>
      <f:facet name="header">
          <h:outputText value="Price"/>
      </f:facet>
      <h:outputText value="#{dataTableItem.price}"/>
  </h:column>


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 :

        
Code Sample from: ItemController.java

@EJB private CatalogFacade catalogfacade;


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

        
Code Sample from: CatalogFacadeBean.java

   @Stateless
   public class CatalogFacadeBean implements CatalogFacade {
   @PersistenceContext(unitName="PetCatalogPu")
   private EntityManager entityManager;
 
   @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
   public List<Item>  getItems(int firstItem,int batchSize) {      
       Query q = entityManager.createQuery("select object(o) from Item as o");
       q.setMaxResults(batchSize);
       q.setFirstResult(firstItem);
       List<Item> items= q.getResultList();
       return items;      
   }
   

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:

        
Code Sample from: List.jsp

<h:outputText value="Item #{item.firstItem + 1}..#{item.lastItem} of
     #{item.itemCount}"/>


This ItemController property is defined as shown below:

        
Code Sample from: ItemController.java

    public int getItemCount() {      
        int count = catalogFacade.getItemsCount();
        return count;     
    }

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:

        
Code Sample from: CatalogFacadeBean.java

    public int getItemCount() {
        Query q = entityManager.createQuery("select count(o) from Item as o");     
        int count = ((Long)q.getSingleResult()).intValue();     
          return count;
    }   
    


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. 

        
Code Sample from: List.jsp

 <h:commandLink action="#{item.next}" value="Next #{item.batchSize}"
    rendered="#{item.lastItem + item.batchSize <= item.itemCount}"/>   


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:

        
Code Sample from: ItemController.java

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


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.

        
Code Sample from: faces-config.xml

  <navigation-rule>
      <navigation-case>
          <from-outcome>item_list</from-outcome>
          <to-view-id>/item/List.jsp</to-view-id>
      </navigation-case>
  </navigation-rule>


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 :

        
Code Sample from: List.jsp

 <h:commandLink action="#{item.prev}" value="Previous #{item.batchSize}"        
        rendered="#{item.firstItem >=item.batchSize}"/>


 This ItemController previous() method  is defined as shown below: 
 
        
Code Sample from: ItemController.java

    public String prev() {
        firstItem -= batchSize;
        if (firstItem < 0) {
            firstItem = 0;
        }
        return "item_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 ItemController detailSetup() method:

        
Code Sample from: List.jsp

   <h:column>
       <f:facet name="header">
          <h:outputText value="Name"/>
       </f:facet>
       <h:commandLink action="#{item.detailSetup}" value="#{dataTableItem.name}"/>   
   </h:column>


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 :

        
Code Sample from: ItemController.java

    public String detailSetup() {
        item = (Item) model.getRowData();
        return "item_detail";
    }


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.

        
Code Sample from: faces-config.xml

    <navigation-rule>
        <navigation-case>
            <from-outcome>item_detail</from-outcome>
            <to-view-id>/item/Detail.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>    

   

The Detail.jsp uses the outputText component to display the ItemController ManagedBean's item properties:

        
Code Sample from: detail.jsp

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



 
    detailpage.jpg


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: