/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License 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 for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.util.pager; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * Implements a generic pager. What is a pager? Let's say you * have a large collection of objects. You're interested in breaking the * mammoth list out into a number pages, each with 25 items on it. * You're interested in returning page #17 of such a collection. * Why bother implementing the "skip past a bunch of things, then * return pagesize items in the resultant colleciton" over and over * again. * * You can also have the elements go through a _processor that you * supply as they move from the source collection to the * destination collection. */ // TODO: G public class Pager { public static final String DEFAULT_PROCESSOR_CLASSNAME = DefaultPagerProcessor.class.getName(); private static final Map PAGER_PROCESSOR_MAP = Collections.synchronizedMap(new HashMap()); private PagerProcessor _processor; private boolean _skipNulls = false; private PagerEventHandler _eventHandler; public Pager(PagerProcessor processor) { _processor = processor; _skipNulls = false; _eventHandler = null; if (_processor instanceof PagerProcessorExt) { _skipNulls = ((PagerProcessorExt) _processor).skipNulls(); _eventHandler = ((PagerProcessorExt) _processor).getEventHandler(); } } public static Pager getDefaultPager() { try { return getPager(DEFAULT_PROCESSOR_CLASSNAME); } catch (Exception e) { throw new RuntimeException("This should never happen", e); } } /** * Get a pager based on the PagerProcessor supplied. */ public static Pager getPager(String className) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Pager p = (Pager) PAGER_PROCESSOR_MAP.get(className); if (p == null) { PagerProcessor processor = (PagerProcessor) Class.forName(className).newInstance(); p = new Pager(processor); PAGER_PROCESSOR_MAP.put(className, p); } return p; } /** * Seek to the specified pagenum in the source collection and * return pagsize numberof of elements in the List. * If pagenum or pagesize is -1, then everything in the * source collection will be returned. * * @param source The source collection to seek through. * @param pagenum The page number to seek to. If there not * enough pages in the collection, then an empty list will be * returned. * @param pagesize The size of each page. * @return PageList containing results of seek. */ public PageList seek(Collection source, int pagenum, int pagesize) { return seek(source, pagenum, pagesize, null); } /** * Seek to the specified pagenum in the source collection and return pagsize * numberof of elements in the List, as specified the PageControl object. * If pagenum or pagesize is -1, then everything in the * source collection will be returned. * * @param source The source collection to seek through. * @param pc The PageControl object to use to control paging. * @return PageList containing results of seek. */ public PageList seek(Collection source, PageControl pc) { if (pc == null) pc = PageControl.PAGE_ALL; return seek(source, pc.getPagenum(), pc.getPagesize(), null); } public PageList seek(Collection source, PageControl pc, Object procData) { if (pc == null) pc = PageControl.PAGE_ALL; return seek(source, pc.getPagenum(), pc.getPagesize(), procData); } /** * Seek to the specified pagenum in the source collection and * return pagsize numberof of elements in the List. * If pagenum or pagesize is -1, then everything in the * source collection will be returned. * * @param source The source collection to seek through. * @param pagenum The page number to seek to. If there not * enough pages in the collection, then an empty list will be * returned. * @param pagesize The size of each page. * @param procData - any data object required by the _processor. * @return PageList containing results of seek. */ public PageList seek(Collection source, int pagenum, int pagesize, Object procData) { PageList dest = new PageList(); dest.setTotalSize(seek(source, dest, pagenum, pagesize, procData)); return dest; } /** * Seek to the specified pagenum in the source collection and place * pagesize number of elements into the dest collection. * If pagenum or pagesize is -1, then everything in the * source collection will be placed in the dest collection. * * @param source The source collection to seek through. * @param dest The collection to place results into. * @param pagenum The page number to seek to. If there not * enough pages in the collection, then an empty list will be * returned. * @param pagesize The size of each page. */ public void seek(Collection source, Collection dest, int pagenum, int pagesize) { seek(source, dest, pagenum, pagesize, null); } /** * Seek to the specified pagenum in the source collection and place * pagesize number of elements into the dest collection. * If pagenum or pagesize is -1, then everything in the * source collection will be placed in the dest collection. * * @param source The source collection to seek through. * @param dest The collection to place results into. * @param pagenum The page number to seek to. If there not * enough pages in the collection, then an empty list will be * returned. * @param pagesize The size of each page. * @param procData any object required to process the item. */ public int seek(Collection source, Collection dest, int pagenum, int pagesize, Object procData) { Iterator iter = source.iterator(); int i, currentPage, size = source.size(); if (pagesize == -1 || pagenum == -1) { pagenum = 0; pagesize = Integer.MAX_VALUE; } for (i = 0, currentPage = 0; iter.hasNext() && currentPage < pagenum; i++, currentPage += (i % pagesize == 0) ? 1 : 0) { iter.next(); } if (_eventHandler != null) _eventHandler.init(); if (_skipNulls) { Object elt; while (iter.hasNext()) { if (_processor instanceof PagerProcessorExt) elt = ((PagerProcessorExt) _processor) .processElement(iter.next(), procData); else elt = _processor.processElement(iter.next()); if (elt == null) { size--; continue; } // Need to keep accurate count, so gotta keep checking if (dest.size() < pagesize) { dest.add(elt); } else if (procData == null) { break; } } } else { while (iter.hasNext() && dest.size() < pagesize) { dest.add(_processor.processElement(iter.next())); } } if (_eventHandler != null) _eventHandler.cleanup(); return size; } /** * Seek to the specified pagenum in the source collection and place * pagesize number of elements into the dest collection. Unlike, * seek(), all items are passed to the Processor or ProcessorExt * regardless whether they are placed in dest collection. If pagenum * or pagesize is -1, then everything in the source collection will * be placed in the dest collection. * * @param source The source collection to seek through. * @param pagenum The page number to seek to. If there not * enough pages in the collection, then an empty list will be * returned. * @param pagesize The size of each page. * @param procData any object required to process the item. */ public PageList seekAll(Collection source, int pagenum, int pagesize, Object procData) { PageList dest = new PageList(); dest.setTotalSize(seekAll(source, dest, pagenum, pagesize, procData)); return dest; } /** * Seek to the specified pagenum in the source collection and place * pagesize number of elements into the dest collection. Unlike, * seek(), all items are passed to the Processor or ProcessorExt * regardless whether they are placed in dest collection. If pagenum * or pagesize is -1, then everything in the source collection will * be placed in the dest collection. * * @param source The source collection to seek through. * @param dest The collection to place results into. * @param pagenum The page number to seek to. If there not * enough pages in the collection, then an empty list will be * returned. * @param pagesize The size of each page. * @param procData any object required to process the item. */ public int seekAll(Collection source, Collection dest, int pagenum, int pagesize, Object procData) { Iterator iter = source.iterator(); int i, currentPage, size = source.size(); if (pagesize == -1 || pagenum == -1) { pagenum = 0; pagesize = Integer.MAX_VALUE; } // PR:8434 : Multi-part paging fixes. // 1.) Invoke the pager _processor external which in many cases may // be keeping track of element [in|ex]clusion. // 2.) The counter 'i' is used with modulus arithmetic to determine // which page we should be on. Don't increment it if the proc-ext // indicated that the element should not be paged. // 3.) 'i' begins it's existance at 0. Zero modulus anything yields // zero. So the ternary expression needs to check for this initial // condition and not increment the page number. for (i = 0, currentPage = 0; iter.hasNext() && currentPage < pagenum; currentPage += (i != 0 && i % pagesize == 0) ? 1 : 0) { Object ret = null; if (_processor instanceof PagerProcessorExt) { ret = ((PagerProcessorExt) _processor).processElement(iter.next(), procData); } else { ret = _processor.processElement(iter.next()); } if (ret != null) { i++; } } if (_eventHandler != null) _eventHandler.init(); if (_skipNulls) { Object elt; while (iter.hasNext()) { if (_processor instanceof PagerProcessorExt) elt = ((PagerProcessorExt) _processor) .processElement(iter.next(), procData); else elt = _processor.processElement(iter.next()); if (elt == null) { size--; continue; } if (dest.size() < pagesize) dest.add(elt); } } else { while (iter.hasNext()) { Object elt = _processor.processElement(iter.next()); if (dest.size() < pagesize) dest.add(elt); } } if (_eventHandler != null) _eventHandler.cleanup(); return size; } /** * Process all objects in the source page list and return the destination * page list with the same total size */ public PageList processAll(PageList source) { PageList dest = new PageList(); int size = source.getTotalSize(); for (Iterator it = source.iterator(); it.hasNext();) { Object elt = this._processor.processElement(it.next()); if (elt == null) { size--; continue; } dest.add(elt); } dest.setTotalSize(size); return dest; } public Object processOne(Object one) { return _processor.processElement(one); } }