/**
* Copyright (c) 2000-2017 Liferay, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.liferay.faces.util.model;
import java.util.Collection;
import java.util.List;
import javax.faces.model.DataModel;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;
/**
* @author Neil Griffin
*/
public abstract class OnDemandDataModel<E> extends DataModel<E> implements Paginated, Sortable {
// Logger
private static final Logger logger = LoggerFactory.getLogger(OnDemandDataModel.class);
// Private Data Members
private int finishRowIndex = -1;
private int rowCount = -1;
private int rowIndex = -1;
private int rowsPerPage;
private List<SortCriterion> sortCriteria;
private int startRowIndex = -1;
private List<E> wrappedData;
/**
* Returns the total number of rows. Note that this method is called only when necessary, and so the return value
* should not be cached in anyway.
*/
public abstract int countRows();
/**
* Returns a list of rows that is a subset of the entire list of rows.
*
* @param startRow The starting row index.
* @param finishRow The finishing row index.
* @param sortCritieria The sort criteria that is to be applied to the order of the results.
*/
public abstract Collection<E> findRows(int startRow, int finishRow, List<SortCriterion> sortCritieria);
/**
* Returns the index of the finishing row associated with the underlying wrapped data.
*/
public int getFinishRowIndex() {
return finishRowIndex;
}
/**
* @see {@link javax.faces.model.DataModel#getRowCount()}
*/
@Override
public int getRowCount() {
if (rowCount == -1) {
rowCount = countRows();
}
return rowCount;
}
/**
* @see {@link javax.faces.model.DataModel#getRowData()}
*/
@Override
public E getRowData() {
if (getRowIndex() >= 0) {
int adjustedRowIndex = getRowIndex() % getRowsPerPage();
Collection<E> wrappedData = getWrappedData();
if (adjustedRowIndex >= wrappedData.size()) {
logger.error("adjustedRowIndex=[{0}] higher than wrappedData.size=[{1}]", adjustedRowIndex,
wrappedData.size());
return null;
}
return getWrappedData().get(adjustedRowIndex);
}
else {
return null;
}
}
/**
* @see {@link javax.faces.model.DataModel#getRowIndex()}
*/
@Override
public int getRowIndex() {
return rowIndex;
}
/**
* @see {@link Paginated#getRowsPerPage()}
*/
public int getRowsPerPage() {
return rowsPerPage;
}
/**
* @see {@link Sortable#getSortCriteria()}
*/
@Override
public List<SortCriterion> getSortCriteria() {
return sortCriteria;
}
/**
* Returns the index of the starting row associated with the underlying wrapped data.
*/
public int getStartRowIndex() {
return startRowIndex;
}
/**
* @see {@link javax.faces.model.DataModel#getWrappedData()}
*/
@Override
public List<E> getWrappedData() {
if (wrappedData == null) {
int startRowIndex = rowIndex;
int finishRowIndex = Math.min(rowIndex + getRowsPerPage() - 1, getRowCount() - 1);
logger.debug("finding new startRowIndex=[{0}] finishRowIndex=[{1}]", startRowIndex, finishRowIndex);
setWrappedData(findRows(startRowIndex, finishRowIndex, sortCriteria));
setFinishRowIndex(finishRowIndex);
setStartRowIndex(startRowIndex);
}
return wrappedData;
}
/**
* @see {@link javax.faces.model.DataModel#isRowAvailable()}
*/
@Override
public boolean isRowAvailable() {
int rowIndex = getRowIndex();
return (rowIndex >= 0) && (rowIndex < getRowCount());
}
/**
* Resets (clears) the underlying wrapped data.
*/
public void reset() {
setRowCount(-1);
setWrappedData(null);
setStartRowIndex(-1);
setFinishRowIndex(-1);
}
/**
* Sets the finishing row associated with the underlying wrapped data.
*/
public void setFinishRowIndex(int finishRowIndex) {
this.finishRowIndex = finishRowIndex;
}
/**
* Sets the rowCount to the specified value.
*/
public void setRowCount(int rowCount) {
this.rowCount = rowCount;
}
/**
* @see {@link javax.faces.model.DataModel#setRowIndex(int)}
*/
@Override
public void setRowIndex(int rowIndex) {
// If the specified rowIndex is outside the range of cached rows, then clear the cache so that the
// findRows(int startRow, int finishRow) method will be called in order to load the set of rows
// associated with the specified rowIndex.
if (rowIndex >= 0) {
int startRowIndex = getStartRowIndex();
int finishRowIndex = getFinishRowIndex();
if ((startRowIndex >= 0) && (finishRowIndex >= 0)) {
int maxFinishRowIndex = startRowIndex + getRowsPerPage() - 1;
if ((rowIndex < startRowIndex) || (rowIndex > maxFinishRowIndex)) {
if (logger.isDebugEnabled()) {
logger.debug("Clearing cache since rowIndex=[{0}] is outside the range of cached rows.",
rowIndex);
}
reset();
}
}
}
this.rowIndex = rowIndex;
}
/**
* @see {@link Paginated#setRowsPerPage(int)}
*/
public void setRowsPerPage(int rowsPerPage) {
this.rowsPerPage = rowsPerPage;
}
/**
* @see {@link Sortable#setSortCriteria(java.util.List)}
*/
@Override
public void setSortCriteria(List<SortCriterion> sortCriteria) {
this.sortCriteria = sortCriteria;
reset();
}
/**
* Sets the starting row associated with the underlying wrapped data.
*/
public void setStartRowIndex(int startRowIndex) {
this.startRowIndex = startRowIndex;
}
/**
* @see {@link javax.faces.model.DataModel#setWrappedData(Object)}
*/
@Override
@SuppressWarnings("unchecked")
public void setWrappedData(Object wrappedData) {
if (wrappedData == null) {
this.wrappedData = null;
}
else {
this.wrappedData = (List<E>) wrappedData;
}
}
}