[jboss-user] [JBoss Seam] - Large Data Tables in Seam - feedback welcome

ASavitsky do-not-reply at jboss.com
Thu Mar 29 10:46:30 EDT 2007


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



More information about the jboss-user mailing list