Wednesday, 5 November 2008
Lazy Loading a JSF DataModel for an ICEfaces ice:dataTable
Iterator components like the ICEfaces ice:dataTable have two special attributes: value and var. The value attribute is typically bound to a JSF model-managed-bean, and the var attribute introduces a new variable into the JSF Expression Language (EL) like this:
<ice:dataTable value="#{modelBean.rows}" var="row">
<ice:column>
<f:facet name="header">
<ice:outputText value="#{msgs.firstName}" />
</f:facet>
<ice:outputText value=#{row.firstName}" />
</ice:column>
...
</ice:dataTable>
The ModelBean.getRows() method can return a variety of types, but in my experience the most typical one is a generic java.util.List like this:
public List<Row> getRows() {...}
Under the hood, JSF is expecting the value attribute to contain an instance of a JSF DataModel object. In fact, if you don't return a DataModel, JSF will implicitly wrap your return value with a wrapper class, such as the ListDataModel for values of type java.util.List.
Typically, the model bean that contains the data is kept in JSF session scope or ICEfaces extended-request scope. This is fine if you only have 10 or 20 rows in the result set, but what if you have 1,000,000 rows? Obviously there is a scalability concern in such a case, especially since the user is only going to be viewing 10 or 20 rows at a time in the browser.
Unfortunately, the JSF spec does not provide a way of loading data on demand (popularly known as "lazy loading" ). I've seen several posts on how to do this, but I thought it would be nice to develop a persistence-technology-independent solution.
To this end, I wrote an abstract class named LazyDataModel.java that is meant to be subclassed into a concrete implementation. Feel free to download the LazyDataModel.java (zipped) source code.
Here are the three methods you will need to supply in your concrete implementation:
public abstract int getRowsPerPage();
public abstract int countRows();
public abstract List<DTO> findRows(int startRow, int finishRow);
The DTO marker implies that this class is meant to be used at the JSF UI layer of a webapp/portlet, and that it is meant to be used in conjunction with the Data Transfer Object design pattern (formerly known as the Value Object / VO design pattern).
BTW, in order for this to be of benefit to the end user, you'll need to connect an ICEfaces ice:dataPaginator component to the ice:dataTable iterator. That will provide icons for navigation such as first-page, previous-page, next-page, and last-page.
Posted by at 3:20 PM in Entries by Neil Griffin