/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.core.domain.util; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import javax.xml.bind.annotation.XmlRootElement; /** * Tracks the result set for a paginated data lookup. Includes the data and the total rows that are available. * * @author Greg Hinkle */ @XmlRootElement public class PageList<E> extends ArrayList<E> implements Serializable { private static final long serialVersionUID = 1L; private int totalSize = 0; private boolean isUnbounded; // Is the total size of the list known? private PageControl pageControl; public PageList() { } /** * Using this constructor one obtains a {@code PageList} instance that contains no data but it has an associated * page control. * <p/> * Such constructor can be used if you don't know or care about the total number of results in the list and * want to add the members of the list at some later point in time. * <p/> * <b>Note:</b> This constructor sets up the {@code PageList} to be {@link #isUnbounded() unbounded}. * * @param pageControl the page control to associate with the {@code PageList} */ public PageList(PageControl pageControl) { super(); this.isUnbounded = true; this.pageControl = pageControl; } /** * Used to represent the cardinality of a result set when the data is not needed. * <p/> * In another words you can use this constructor to setup the {@code PageList} such that it correctly declares * the {@link #getTotalSize() total size}, is NOT {@link #isUnbounded() unbounded} and has an associated page * control, but actually contains no data (the data can be added later on of course). * * @param totalSize the total number of records of which this instance contains a subset of * @param pageControl defines what subset of data is contained in this instance * * @see org.rhq.core.domain.criteria.Criteria.Restriction#COUNT_ONLY */ public PageList(int totalSize, PageControl pageControl) { super(); this.totalSize = totalSize; this.pageControl = pageControl; } /** * Used to represent a result set when the cardinality of the data is not needed. * <p/> * In another words you can use this constructor to setup a {@code PageList} which IS {@link #isUnbounded() * unbounded} and has an associated page control. * * @param collection the data contained in this instance - a shallow copy of the collection will be inserted into * this instance * @param pageControl defines what subset of the total number of items is present in this instance * * @see org.rhq.core.domain.criteria.Criteria.Restriction#COLLECTION_ONLY */ public PageList(Collection<? extends E> collection, PageControl pageControl) { super(collection); isUnbounded = true; this.pageControl = pageControl; } /** * This constructor creates a fully configured {@code PageList} that contains the page control, the subset of the * records that conforms to that page control, as well as the information about the total number of records. * <p/> * Note that it is perfectly legal for the collection to be empty, even though the {@code totalSize} is > 0. * This can be caused by a couple of things: * <ul> * <li>the page control used to obtain this page list points "past" the total size,</li> * <li>there has been a drastic change in the database between obtaining the previous "page" and the next * page using the same page control resulting essentially in the previous case,</li> * <li>there has been a concurrent DB activity while obtaining the data and totalSize of the list, resulting * in the two being based on different DB state. There is an attempt to mitigate this condition in the while * performing the criteria queries but due to the nature of the READ_COMMITTED transaction isolation level, * this cannot be completely prevented.</li> * </ul> * @param collection the subset of the records as described by the {@code pageControl} * @param totalSize the total number of records, the {@code collection} is subset of * @param pageControl the page control object describing the subset */ public PageList(Collection<? extends E> collection, int totalSize, PageControl pageControl) { super(collection); this.totalSize = totalSize; this.isUnbounded = false; this.pageControl = pageControl; } public PageControl getPageControl() { return pageControl; } public void setPageControl(PageControl pageControl) { this.pageControl = pageControl; } public ArrayList<E> getValues() { return this; } public void setValues(ArrayList<E> values) { this.clear(); this.addAll(values); } /** * Returns the total size of the "master list" that this page is a subset of. * <p/> * <b>Note:</b> This method merely returns the size of this list if it is {@link #isUnbounded() unbounded}. * @return the total size */ public int getTotalSize() { return Math.max(this.size(), this.totalSize); } /** * Sets the total size of the "master list" that this page is a subset of. * * @param totalSize New value of property totalSize. */ public void setTotalSize(int totalSize) { this.isUnbounded = false; this.totalSize = totalSize; } /** * @return whether the total size of the list is known or not */ public boolean isUnbounded() { return this.isUnbounded; } public void setUnbounded(boolean isUnbounded) { this.isUnbounded = isUnbounded; if (isUnbounded) { //reset this to 0, so that #getTotalSize() behaves consistently totalSize = 0; } } /** * @see PageControl#isConsistentWith(PageList) * * @return true if this page list is consistent with its page control */ public boolean isConsistent() { return pageControl == null || pageControl.isConsistentWith(this); } @Override public String toString() { return "PageList" + super.toString(); } }