This is my take at the way to manage large datasets in @DataModel, without
loading them all in memory. Hopefully, this code will be of use to others
and/or generate useful improvement suggestions. Anyway, here goes:
LazyList.java - implements List interface, allowing its use in @DataModel. Only
holds one page (size can be configured) worth of data, delegating the actual
retrieval to the fetcher interface. Knows the total amount of data, again by
calling the appropriate method in fetcher.
public class LazyList<T> implements List<T> {
| public static final int DEFAULT_PAGE_SIZE = 20;
| private int currentPage;
| private List<T> dataset;
| private int datasetSize;
| private IFetcher<T> fetcher;
| private int pageSize = DEFAULT_PAGE_SIZE;
|
| public LazyList(IFetcher<T> fetcher) {
| this.fetcher = fetcher;
| datasetSize = fetcher.getDatasetSize();
| currentPage = 0;
| }
| public LazyList(IFetcher<T> fetcher, int pageSize) {
| this(fetcher);
| this.pageSize = pageSize;
| }
| public T get(int index) {
| int requestedPage = index / pageSize;
| if (index < 0 || index > datasetSize) {
| throw new IndexOutOfBoundsException();
| }
| if (dataset == null || currentPage != requestedPage) {
| currentPage = requestedPage;
| dataset = fetcher.getDatasetPage(currentPage *
pageSize, pageSize);
| }
| return dataset.get(index % pageSize);
| }
| public boolean isEmpty() {
| return datasetSize == 0;
| }
| public int size() {
| return datasetSize;
| }
| // the rest of the interface methods {
| throw new UnsupportedOperationException("Not implemented");
| }
| }
|
IFetcher.java:
public interface IFetcher<T> {
| /** Fetch a page of data */
| List<T> getDatasetPage(int start, int pageSize);
| /** Fetch total dataset size */
| int getDatasetSize();
| }
|
CriteriaFetcher.java - implemets fetcher interface via Hibernate criteria
calls. Hibernate Session is injected via Seam, the criteria properties neeed to
be specified during fetcher construction (cannot be placed in constructor as
Seam needs a no-arg one). Criterias are used because sorting and filtering can
easily be added to them.
@Name ("fetcher")
| @Scope (ScopeType.CONVERSATION)
| public class CriteriaFetcher<T> implements IFetcher<T>, Serializable {
| @Logger
| private static Log log;
| private DetachedCriteria countCriteria;
| private DetachedCriteria queryCriteria;
| @In
| private Session session;
|
| @SuppressWarnings ("unchecked")
| public List<T> getDatasetPage(int start, int pageSize) {
| log.trace("Fetching #0 records starting from #1", pageSize,
start);
| return
queryCriteria.getExecutableCriteria(session).setFirstResult(start).setMaxResults(pageSize).list();
| }
| @SuppressWarnings ("unchecked")
| public int getDatasetSize() {
| log.trace("Fetching dataset size");
| return (Integer)
countCriteria.getExecutableCriteria(session).uniqueResult();
| }
| public void setCountCriteria(DetachedCriteria countCriteria) {
| this.countCriteria =
countCriteria.setProjection(Projections.rowCount());
| }
| public void setQueryCriteria(DetachedCriteria queryCriteria) {
| this.queryCriteria = queryCriteria;
| }
| }
|
Now any bean would use the paged lists in the following way:
@In (create = true)
| private CriteriaFetcher<T> fetcher;
| @DataModel
| private LazyList<T> records;
|
| protected DetachedCriteria buildCriteria() {
| return DetachedCriteria.forClass(T.class);
| }
| @Factory ("records")
| public void createRecords() {
| fetcher.setCountCriteria(buildCriteria());
| fetcher.setQueryCriteria(buildCriteria());
| records = new LazyList<T>(fetcher, 10);
| }
|
If sorting/filtering is needed, simply recreate the records variable with a
different fetcher that has the necessary sorts/filters built in. Until then,
the constructed LazyList stays in its scope (CONVERSATION is recommended),
fetching data pages as necessary.
Comments/suggestions are welcome - though the code is working already, so I'm
not looking for others to fix it for me :)
Alex
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4032810#4032810
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4032810
_______________________________________________
jboss-user mailing list
[email protected]
https://lists.jboss.org/mailman/listinfo/jboss-user