I came today to an interesting thread on one of the forums. The discussion was concerned to "dynamic" data models of JSF data tables. Because this issue focuses in the center of my current interest, I want write a few words on this topic.
Returning to the forum entries, one of participants argued that :
" ... When workig on real application there are a thousands of even a millions rows.
But I have seen several JSF dagatable components.
They implement pagination, sorting and filtering on client side!! According to me this is very silly. This technology is called enterprise and they sort the data on the client side with java script!
I have not seen any good JSF data grid that has build in features for sorting, filtering and lazy loading on the server side.
Why is that? Am I looking in wrong direction or really there in no build support for this. Lately I am testing primefaces and lazy loading datatable. It really works fine, but the table i can only lazy load. If you add sort and filter then the problems begin...
Is there any datatable JSF component than can perform lazy load pagination, and filtering and sorting on server side?"
One of answers was:
No, there isn't. Because the component library cannot know what will be the persistence mechanism.
In my opinion the answer isn't correct. There are implementations of JSF components where problem was solved. One of this is ADF Faces based on Apache Trinidad component set. The second is by example Richfaces with data table component.
But, in fact, in ADF Faces the data model which supports sorting or searching on the server side is a very specific solution. In this sense cited answer is valid. Table component designed as generic solution, without "knowledge" about model and based on JSF standard data model (javax.faces.model.DataModel), can't deal with logic which obviously should work on the model side.
Ok. In conclusion the problem can be solved, but don't exists a one standard solution method. So let's see what solutions are used.
In
ADF Faces ADF Table (af:table) component can "consume" model derived from
org.apache.myfaces.trinidad.model.CollectionModel
. The same data model is used by the Trinidad Table and Iterator components. CollectionModel class extends the Faces DataModel (
javax.faces.model.DataModel
) class and adds on support for rowKeys and sorting. What more construction of CollectionModel class provides possibility to implement simple lazy, incremental loading of data portions.
Very elegant solution is the fact that ordinary DataModels are still supported, and will automatically be wrapped into CollectionModels. However, in this case, the functionality added by CollecionModel isn't anymore supported.
An important feature is support for rowKeys. In the Faces DataModel, rows are identified entirely by index. This causes major problems if the underlying data changes from one request to the next - a user request to delete one row may delete a different row because a row got added by another user, etc. To work around this, CollectionModel is based around unique row keys.
Although Trinidad CollectionModel looks like complete solution, however some functionalities like filtering are solved outside of main model class. The specific properties of ADF BC are used to provide those functions.
Different approach to the problem presents
RichFaces. Base class for all models used by
RichFaces is org.ajax4jsf.model.ExtendedDataModel
. Just as in Trinidad CollectionModel, ExtendedDataModel introduces rowKeys as an unique identification of rows. ExtendedDataModel introduces also one simple method to "walk" through the data collection. In CollectionModel class isn't so easy to figure out where we should load the data from external datasource, and because of this I like the solution in ExtendedDataModel.
Default implementation of the ExtendedDataModel for the tables when filtering and sorting will be not used is SequenceDataModel. But functionalities like sorting and filtering need the more extensive model. For this purpose RichFaces provides
org.richfaces.model.ArrangeableModel
, an implementation of the ExtendedDataModel which implements Arrangeable interface for sorting and filtering support.
Class ArrangeableModel contains one universal method
arrange
which can be used in derived classes when implementing sorting and filtering behaviours. The
object org.richfaces.model.ArrangeableState
passed as a parameter to arrange method contains informations sufficient for implementing own mechanism of sorting or filtering.
Comparing the two presented approaches, especially when you compare source code, it is easy to see that JBoss approach looks very simple and clean, whereas Oracle's code is at first sight unclear. On the other hand Trinidad CollectionModel is direct implementation of
javax.faces.model.DataModel
without any additional "decoration", and because of this can look some poor. What more af:table component used in combination with ADF Bussiness Components is the best I've ever seen, because of possibility to create fully dynamic data table in seconds and only declaratively.
The purpose of my exercise wasn't comparison of datatable models only for the sake of this article. A problem which I wrote about refers to the situation when we create custom datatable component and we should decide what model of data would be used.
The basic idea was that the designed component will have built-in features for sorting, filtering and lazy loading, all working on the server side. As I wrote, there doesn't exists ready mechanism for these functionalities in base JSF DataModel implementation. Different vendors provide own specific solutions of this problem.
The component based on Datatables plug-in for the jQuery Javascript library has extensive user interface with possibility of sorting, filtering, lazy-loading, in-place editing and so on. The only problem was to design a model that will let easy to implement server-side logic. What more the model should let us consume in easy way the models developed for datatable components from ADF (Trinidad) and RichFaces sets.
At the first sight, because of simplicity of solution for server-side filtering we choosed RichFaces approach as our pattern. But then we decided to turn back and start extending
javax.faces.model.DataModel
in our own way. We also provide possibility to consume in our datatable any object which implementats the Trinidad CollectionModel. This works on-the-fly through the wrapping original model and dynamic conversion of the methods calls.