This Sample Store Catalog app demonstrates the usage of JavaServer Faces, a Catalog Stateful Session Bean, the Java Persistence APIs, and Seam to implement pagination of data sets. I took this example  Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs  and refactored it to use Seam on Glassfish by following the steps in Brian Leonards blog http://weblogs.java.net/blog/bleonard/archive/2007/06/seam_refresh_1.htmlSeam Refresh  and the clickable list example in the Seam Tutorial

Download the Seam Sample Application Code

Explanation of the usage of JSF, Seam, 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

DataTable  JSF component

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 rendererdisplays the data as an HTML table.

In the List.jsp web page the dataTable is defined as shown below:   (Note:Redcolors are for Java EE tags, annotations code, Blue for Seamspecific and Green for my code orvariables)

        
Code Sample from:  List.jsp

<h:dataTablevalue='#{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 UIDatacomponent iterates through the list, each reference to dataTableItem points to the current item in the list.

The dataTable's value is bound to the itemsattribute of the CatalogBeanclass:


        
Code Sample from: CatalogBean.java

@Stateful

@Scope(SESSION)
@Name("catalog")
@Interceptors({org.jboss.seam.ejb.SeamInterceptor.class})

public class CatalogBeanimplements Serializable, Catalog {
   
    @DataModel
    private List<Item> items=null;

    @Factory("items")
    public void getItems() {
        if ((items==null)  || (index != firstItem) ){
           getNextItems();
        }
    }
   



The @DataModelSeam annotation exposes an attribute of type java.util.List to a JSF page as an instance of javax.faces.model.DataModel. The  <h: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.  In this case, the DataModel is made available in a session context variable nameditems.

When the List.jsp page is diplayed it will try to resolve the items context variable. Since this context variable is not initialized, Seam will call the factory method getItems(), which performs a JPA query (see getNextItems() code below) and results in a DataModel being outjected.

The @Name Seam annotation specifies catalogas the application unique component name which Seam will use to resolve references to the catalogcontext variable. Seam will instantiate the component and bind a new instance to the context variable the first time JSF encounters the variable name catalog. The instance will be bound to the context specified by the@ScopeSeam annotation. The CatalogBean is a org.jboss.seam.ScopeType.SESSIONscoped component.

The @Stateful EJB 3.0 annotation marks this as a Stateful EJB. A Stateful EJB is used because the current chunk of items, and the user's position in the count of items in the db table, is maintained for the user's session.

The @Interceptors EJB 3.0 annotation registers the SeamInterceptor.class as an EJB interceptor for this session bean component.
The Seam framework uses  EJB interceptors to perform bijection, context demarcation, validation, etc, (the interceptor could be defined in the ejb-jar.xml instead).

 

Column JSF component

On the List.jsp page the Item Name, Photo, and Price  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 the dataTable component. While the dataTable component is iterating over the rows of data, it processes the column component associated with eachcolumn tag for each row in the table. As the dataTable component iterates through the list, each reference to dataTableItem points to the current item in the list.

The dataTable component  iterates through the list of items and displays the names, photos, and prices. Each time the dataTable 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.


Java Persistence Query API

The CatalogBeanSession EJB uses the Java Persistence API Queryobject to return a list of items. With the @PersistenceContextannotation the CatalogBean 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: CatalogBean.java

  
@DataModel
   private List<Item> items=null;

   @PersistenceContext(unitName="PetCatalogPu")
   private EntityManager em;

   private int batchSize = 10;
   private int index = 0;
   private int firstItem = 0;
 
   @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
   public void getNextItems() {
        Query q = em.createQuery("select object(o) from Item as o");
        q.setMaxResults(batchSize);
        q.setFirstResult(firstItem);
        items= q.getResultList();
        index = firstItem;
   }
   

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 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 Itementity 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 @Entityannotation.
  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 Addressand Productare also annotated. For more information on defining JPA entities see Pro EJB 3: Java Persistence API book.

           
Code Sample from: Item.java

@Entity
@Name("item")
@Scope(ScopeType.EVENT)

public class Item implements java.io.Serializable {

   
@Id 
      private String itemID;

    private String name;   
    private String description;   
    private String imageurl;   
    private String imagethumburl; 
    private BigDecimal price;
    @OneToOne(cascade={CascadeType.PERSIST})
    private Address address;
    @ManyToOne
    private Product product;

    
    public Item() { }
     
    public String getItemID() {
        return itemID;
    }

    public void setItemID(String itemID) {
        this.itemID = itemID;
    }

    public String getName() {
        return name;
    }

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

    public void setDescription(String description) {
        this.description = description;
    }

    public BigDecimal getPrice() {
       return price;
    } 

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public Product getProduct() {
        return product;
    }
    public void setProduct(Product product) {
        this.product = product;
    }

    ...
}   



The @Namehttp://docs.jboss.com/seam/1.0.1.GA/reference/en/html/annotations.html#name-annotation seam annotation specifies the (application unique) component name item, which is used in the  Detail.jsp to display the selected item's attributes. The @ScopeSeam annotation binds the iteminstance to the org.jboss.seam.ScopeType.EVENTcontext.

The CatalogBeanpages through the list of items by maintaining the firstItemand batchSizeattributes and passing these as parameters to thequery.setFirstResult(int startPosition),query.setMaxResults(int maxResult) methods. The CatalogBean's scope is defined as org.jboss.seam.ScopeType.SESSION, which corresponds to the JSF managed bean session scope.


The CatalogBeanitemCountproperty is  used to get and display the number of Catologue items in the  data base:

        
Code Sample from: List.jsp

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



The CatalogBeangetItemCount() method uses the JPA javax.persistence.Queryinterface to get the count of all items in the database item table:

        
Code Sample from: CatalogBean.java
        
   
private int itemCount= 0;

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


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 actionevent to the application. 

        
Code Sample from: List.jsp

 <h:commandLinkaction="#{catalog.next}" value="Next #{catalog.batchSize}"
    rendered="#{catalog.lastItem + catalog.batchSize <= catalog.itemCount}"/>   


This commandLink actionattribute references the CatalogBean 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 CatalogBeannext()method is defined as shown below:

        
Code Sample from: CatalogBean.java

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


The JavaServer Faces NavigationHandlermatches the logical outcome,  item_listagainst the navigation rules in the application configuration resource file faces-config.xmlto 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 commandLinkis  used to provide a link to click on to display the previous page of items. This commandLink actionattribute  references the  CatalogBean's 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:commandLinkaction="#{catalog.prev}" value="Previous #{catalog.batchSize}"   
        rendered="#{catalog.firstItem >=catalog.batchSize}"/>


 This CatalogBeanprev()method  is defined as shown below: 
 
        
Code Sample from: CatalogBean.java

    public String prev() {
        firstItem -= batchSize;
        if (firstItem < 0) {
            firstItem = 0;
        }
        getNextItems();
        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 CatalogBean select() method:

        
Code Sample from: List.jsp

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


With Seam if you use the @DataModelSelection with the@DataModel annotation, when the user clicks on the link, Seam will propagate the selected row from theDataModel into the annotated attribute:

        
Code Sample from: CatalogBean.java

    @DataModelSelection
    @Out(required=false)
    private Item item;

    public String select() {
        return "item_detail";
    }



The @DataModelSelectionSeam annotation tells Seam to inject the DataModel List element corresponding to the clicked link into the itemattribute.  The @Out Seam annotation transfers the value of this attribute to the itemevent context variable, making it available to a JSP page after theactioncatalog.selectmethod execution. So when a row of the dataTable is selected, the selected row is injected to the itemattribute of the CatalogBeanStateful bean, and then outjected to the event context variable named itemwhich is used in the Detail.jsp page to display the item details.

The CatalogBean select() returns a string,  "item_detail",which causes the Detail.jsp page to display the item details. The JavaServer Faces NavigationHandlermatches the logical outcome,  item_detailagainst the navigation rules in the application configuration resource file faces-config.xml to determine which page to access next. In this case, the JavaServer Faces implementation loads theDetail.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 outputTextcomponent to display the itemproperties:

        
Code Sample from:  Detail.jsp

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




    detailpage.jpg


Conclusion
This concludes the sample application which demonstrates how to useSeam with the JSF dataTable and DataModel to page through a list of  Item Entities which are retrieved using  the CatalogBean Stateful Session EJB methods which use  the Java Persistence APIs.


Configuration of the Application for Seam, JSF, JPA, running on Glassfish

First I recommend reading and following the steps in Brian Leonard's blog Seam Refresh .  I will summarize those steps here:
  • Downloadand extract JBoss 4.2.0 GA
  • Downloadand install GlassFish V1, following the instructions on the download page. Alternatively you can use Sun Java System Application Server PE 9, Sun's GlassFish distribution.
  • Downloadand extract Seam 1.2.1 GA
  • Download and install NetBeans 5.5.1
  • Download the Seam Sample Application Code
  • install Glassfish and Netbeans 5.5.1.  Then add the glassfish application server to Netbeans.

To Open and Test Run the seampagination Project:

  • Use the Resolve Reference Problems dialog to map the ejb and web modules to their project, which are subdirectories beneath the seampagination directory.
  • After the references are resolved, right-click the seampagination project and select Open Required Projects.
  • In Netbeans create a JBossSeam Library as documented in Seam Refresh.
  • Right-click the seampagination-EJBModule to resolve the reference problems:
    • browse to the server\default\deploy\jboss-web.deployer\jsf-libsdirectory of your JBoss server installation, select jsf-api.jar and select Open.
    • browse to the Seam lib directory and select hibernate-all.jar and thirdparty-all.jar, and select Open.
  • Right-click the Libraries node of the seampagination-EJBModule project , choose Add Library and add the JBossSeam library you created.
  • Right-click the seampagination-WebModule and select Resolve Reference Problems:
    • Browse to the seampagination-ejb directory which is a sub-directory below the seampagination directory and select Open Project Folder.
    • Browse to the  jboss-seam-ui.jar found in the root of where you extracted the Seam framework and select Open Project Folder.
If you want to create your own Java EE application using Seam on Glassfish with Netbeans from scratch (read the steps in Brian Leonard's blog Seam Refresh summarizedhere): 
  • In Netbeans create a JBossSeam Library as documented in Seam Refresh.
  • Use Netbeans to create a new Enterprise Application
  • Right-click the Libraries node of the EJBModule project , choose Add Library and add the JBossSeam library you created.
  • Right-click the Libraries node of the EJBModule project , choose Add Jar  and add these jars:
  • Right-click the Libraries node of the WebModule project ,  choose Add Jar  and add these jars:
  • create an empty seam.properties file in the seampagination-EJBModule src\conf Folder.
  • add  the following phase listener to your faces-config.xml file under webpages web-inf:
     
    <lifecycle>
            <phase-listener>
                org.jboss.seam.jsf.SeamPhaseListener
            </phase-listener>
    </lifecycle>

  • add the following  context parameter to your web.xml file 
    <context-param>
         <param-name>
              org.jboss.seam.core.init.jndiPattern
         </param-name>
         <param-value>
               java:comp/env/your ear name/#{ejbName}/local
         </param-value>  
    </context-param>
  • add the following listener class to your web.xml file
     
    <listener>
            <listener-class>
                org.jboss.seam.servlet.SeamListener
            </listener-class>
    </listener>
  • For any session EJB's referenced from the web, add  EJB references to your web.xml, for example:
     
    <ejb-local-ref>
         <ejb-ref-name>your ear name/CatalogBean/local</ejb-ref-name>
         <ejb-ref-type>Session</ejb-ref-type>
         <local-home/>
         <local>your package name.Catalog</local>
         <ejb-link>CatalogBean</ejb-link>
    </ejb-local-ref>
  • For any EJB's referenced from the web add  a Seam interceptor to the EJB, for example : @Interceptors({org.jboss.seam.ejb.SeamInterceptor.class})

References:


Carol McDonald