/* * Copyright 2013 GiavaCms.org. * * Licensed under the Eclipse Public License version 1.0, available at * http://www.eclipse.org/legal/epl-v10.html */ package org.giavacms.common.model; import java.util.logging.Logger; import javax.faces.model.DataModel; /** * A special type of JSF DataModel to allow a datatable and datascroller to page through a large set of data without * having to hold the entire set of data in memory at once. * <p> * Any time a managed bean wants to avoid holding an entire dataset, the managed bean should declare an inner class * which extends this class and implements the fetchData method. This method is called as needed when the table requires * data that isn't available in the current data page held by this object. * <p> * This does require the managed bean (and in general the business method that the managed bean uses) to provide the * data wrapped in a DataPage object that provides info on the full size of the dataset. */ public abstract class PagedListDataModel<T> extends DataModel<T> { Logger log = Logger.getLogger(PagedListDataModel.class.getName()); // mantiene la posizione del cursore nel datamodel. usato in alternativa a // rowIndex a sua volta usato dal data table public int entityIndex; // mantiene il puntatore al numero di pagina corrente public int currentPage; public int lastPage; int pageSize; int rowIndex; DataPage<T> page; /* * Create a datamodel that pages through the data showing the specified number of rows on each page. */ public PagedListDataModel(int pageSize) { super(); this.pageSize = pageSize; this.rowIndex = -1; this.page = null; } /** * Not used in this class; data is fetched via a callback to the fetchData method rather than by explicitly assigning * a list. */ @Override public void setWrappedData(Object o) { throw new UnsupportedOperationException("setWrappedData"); } @Override public int getRowIndex() { return rowIndex; } /** * Specify what the "current row" within the dataset is. Note that the UIData component will repeatedly call this * method followed by getRowData to obtain the objects to render in the table. */ @Override public void setRowIndex(int index) { rowIndex = index; } /** * Return the total number of rows of data available (not just the number of rows in the current page!). */ @Override public int getRowCount() { return getPage().getDatasetSize(); } /** * Return a DataPage object; if one is not currently available then fetch one. Note that this doesn't ensure that the * datapage returned includes the current rowIndex row; see getRowData. */ private DataPage<T> getPage() { if (page != null) return page; int rowIndex = getRowIndex(); int startRow = rowIndex; if (rowIndex == -1) { // even when no row is selected, we still need a page // object so that we know the amount of data available. startRow = 0; } // invoke method on enclosing class page = fetchPage(startRow, pageSize); return page; } /** * Return the object corresponding to the current rowIndex. If the DataPage object currently cached doesn't include * that index then fetchPage is called to retrieve the appropriate page. */ @Override public T getRowData() { if (rowIndex < 0) { throw new IllegalArgumentException( "Invalid rowIndex for PagedListDataModel; not within page"); } // ensure page exists; if rowIndex is beyond dataset size, then // we should still get back a DataPage object with the dataset size // in it... if (page == null) { page = fetchPage(rowIndex, pageSize); } // imposta l'indice locale del dataset setEntityIndex(rowIndex % getPageSize()); // righe in dataset int datasetSize = page.getDatasetSize(); int startRow = page.getStartRow(); int nRows = page.getData().size(); int endRow = startRow + nRows; if (rowIndex >= datasetSize) { throw new IllegalArgumentException("Invalid rowIndex"); } if (rowIndex < startRow) { page = fetchPage(rowIndex, pageSize); startRow = page.getStartRow(); } else if (rowIndex >= endRow) { page = fetchPage(rowIndex, pageSize); startRow = page.getStartRow(); } int num = rowIndex - startRow; if (num < 0) { return null; } return page.getData().get(num); } @Override public Object getWrappedData() { return page.getData(); } /** * Return true if the rowIndex value is currently set to a value that matches some element in the dataset. Note that * it may match a row that is not in the currently cached DataPage; if so then when getRowData is called the required * DataPage will be fetched by calling fetchData. */ @Override public boolean isRowAvailable() { DataPage<T> page = getPage(); if (page == null) return false; int rowIndex = getRowIndex(); if (rowIndex < 0) { return false; } else if (rowIndex >= page.getDatasetSize()) { return false; } else { return true; } } public int getNumPages() { int num = getRowCount() / getPageSize(); if (num * getPageSize() < getRowCount()) { // ultima pagina non completa: ritorna // il numero di pagine complete +1 return num + 1; } // anche l'ultima pagina รจ completa return num; } public int getCurrentPage() { return currentPage; } public void invalidateSession() { log.info("invalidatye entityIndex: " + entityIndex); log.info("invalidatye rowIndex: " + rowIndex); log.info("invalidatye pageSize: " + pageSize); log.info("invalidatye getDatasetSize: " + page.getDatasetSize()); log.info("invalidatye currentPage: " + currentPage); log.info("invalidatye getStartRow: " + page.getStartRow()); setRowIndex(lastPage + 1); setCurrentPage(0); log.info("invalidatye rowIndex: " + rowIndex); this.page = null; } public void setCurrentPage(int cp) { currentPage = cp; if (currentPage < 0) currentPage = 0; } protected void setCurrentPage(int startRow, int pageSize) { setCurrentPage(startRow / pageSize); } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getEntityIndex() { return entityIndex; } public void setEntityIndex(int ei) { entityIndex = ei; if (entityIndex < 0) entityIndex = 0; if (entityIndex >= getRowCount()) entityIndex = getRowCount() - 1; } /** * Method which must be implemented in cooperation with the managed bean class to fetch data on demand. */ public abstract DataPage<T> fetchPage(int startRow, int pageSize); }