Century
Century

Reputation: 303

rich:dataScroller seems to still load all the data without pagination

I'm trying to implement pagination for a project that loads a large set of data from the database. I've done a lot of searching on the internet already to get db-pagination to work, but for some reason I still don't get it working the way I want.

I've followed the example as described in this topic: JSF, RichFaces, pagination

The data is loaded, so that works; cache also seems to work. However, it seems to still load all the data. The sr.getRows() in the walk-method is always -1, so the call to the database also uses -1 for maxResults. I get all my data, but no pagination.

I don't want to introduce another dependency if I can avoid it.

Some of my data:

BatchDataModel

public abstract class BatchDataModel<T> extends ExtendedDataModel<T> {
private SequenceRange cachedRange;
private Integer cachedRowCount;
private List<T> cachedList;
private Object rowKey;

public abstract List<T> getDataList(int firstRow, int numRows);
public abstract Object getKey(T t);
public abstract int getTotalCount();

@Override
public void walk(FacesContext ctx, DataVisitor dv, Range range, Object argument) {

    SequenceRange sr = (SequenceRange) range;

    if (cachedList == null || !equalRanges(cachedRange, sr)) {
        cachedList = getDataList(sr.getFirstRow(), sr.getRows());
        cachedRange = sr;
    }

    for (T t : cachedList) {
        if (getKey(t) == null) {
            /*
            * the 2nd param is used to build the client id of the table
            * row, i.e. mytable:234:inputname, so don't let it be null.
            */
            throw new IllegalStateException("found null key");
        }
        dv.process(ctx, getKey(t), argument);
    }

}


/*
* The rowKey is the id from getKey, presumably obtained from
* dv.process(...).
*/
@Override
public void setRowKey(Object rowKey) {
    this.rowKey = rowKey;
}

@Override
public Object getRowKey() {
    return rowKey;
}

@Override
public boolean isRowAvailable() {
    return (getRowData() != null);
}

@Override
public int getRowCount() {
    if (cachedRowCount == null) {
        cachedRowCount = getTotalCount();
    }
    return cachedRowCount;
}

@Override
public T getRowData() {
    for (T t : cachedList) {
        if (getKey(t).equals(this.getRowKey())) {
            return t;
        }
    }
    return null;
}

protected static boolean equalRanges(SequenceRange range1, SequenceRange range2) {
    if (range1 == null || range2 == null) {
        return range1 == null && range2 == null;
    } else {
        return range1.getFirstRow() == range2.getFirstRow() && range1.getRows() == range2.getRows();
    }
}



/*
* get/setRowIndex are used when doing multiple select in an
* extendedDataTable, apparently. Not tested. Actually, the get method is
* used when using iterationStatusVar="it" & #{it.index}.
*/
@Override
public int getRowIndex() {
    if (cachedList != null) {
        ListIterator<T> it = cachedList.listIterator();
        while (it.hasNext()) {
            T t = it.next();
            if (getKey(t).equals(this.getRowKey())) {
                return it.previousIndex() + cachedRange.getFirstRow();
            }
        }
    }
    return -1;
}

@Override
public void setRowIndex(int rowIndex) {
    int upperBound = cachedRange.getFirstRow() + cachedRange.getRows();
    if (rowIndex >= cachedRange.getFirstRow() && rowIndex < upperBound) {
        int index = rowIndex % cachedRange.getRows();
        T t = cachedList.get(index);
        setRowKey(getKey(t));
    }
}

@Override
public Object getWrappedData() {
    throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void setWrappedData(Object data) {
    throw new UnsupportedOperationException("Not supported yet.");

}

public List<T> getCachedList() {
    return cachedList;
} 

Bean (part)

private ListState state;
private BatchDataModel<Batch> model;

public BatchDataModel<Batch> getModel(){
    return model;
}

public int getCurrentPage() {
    return state.getPage();
}

public void setCurrentPage(int page) {
    state.setPage(page);
}

public void setBatchService(BatchService batchService) {
    this.batchService = batchService;
}

/**
 * Initialize the variables, before the page is shown.
 */
@PostConstruct
private void init() {
    filter = new Filter();
    sorter = new Sorter();

    state = getFromSession("batchList", null);
    if (state == null) {
        state = new ListState();
        storeInSession("batchList", state);
    }
}

public void loadBatches(boolean search) {
       BatchDataModel<Batch> model = new BatchDataModel<Batch>(){
             @Override
                public List<Batch> getDataList(int firstRow, int numRows) {
                    try {
                        List <Batch> test;
                        test =  batchService.selectBatches(userBean.getUser(), firstRow, numRows);
                        return test;
                    } catch (NozemException e) {
                        LOGGER.error(e.getMessage());
                        sendMessage(e.getMessage(), true);
                        return null;
                    }
                }

                @Override
                public Object getKey(Batch batch) {
                    return batch.getBatchId();
                }

                @Override
                public int getTotalCount() {
                   try {
                    return batchService.countBatches(userBean.getUser());
                } catch (NozemException e) {
                    LOGGER.error(e.getMessage());
                    sendMessage(e.getMessage(), true);
                    return 0;
                }
                }
        };
 }

xhtml (part)

<rich:dataTable id="batchesTable" rows="2"
                value="#{batchBean.model}" var="batch" first="#{batchBean.currentPage}"
                styleClass="table" rowClasses="odd-row, even-row"
                onrowmouseover="this.style.backgroundColor='#88B5F9'"
                onrowmouseout="this.style.backgroundColor='#{a4jSkin.rowBackgroundColor}'">

(...)

<f:facet name="footer">
                        <rich:dataScroller page="#{batchBean.currentPage}" />
                </f:facet>

Upvotes: 0

Views: 504

Answers (1)

Century
Century

Reputation: 303

ArrangeableModel is the key. This class needs to be implemented in the BatchDataModel class, together with a method and function. This way the same state is used and the walk-method gets the correct values in SequenceRange.

public abstract class BatchDataModel<T> extends ExtendedDataModel<T> implements Arrangeable {

  private ArrangeableState arrangeableState;

  public void arrange(FacesContext context, ArrangeableState state) {
    arrangeableState = state;
  }

  protected ArrangeableState getArrangeableState() {
    return arrangeableState;
  }
}

Upvotes: 0

Related Questions