Frames | No Frames |
1: /** 2: * ======================================== 3: * JFreeReport : a free Java report library 4: * ======================================== 5: * 6: * Project Info: http://reporting.pentaho.org/ 7: * 8: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors. 9: * 10: * This library is free software; you can redistribute it and/or modify it under the terms 11: * of the GNU Lesser General Public License as published by the Free Software Foundation; 12: * either version 2.1 of the License, or (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 15: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16: * See the GNU Lesser General Public License for more details. 17: * 18: * You should have received a copy of the GNU Lesser General Public License along with this 19: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 20: * Boston, MA 02111-1307, USA. 21: * 22: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 23: * in the United States and other countries.] 24: * 25: * ------------ 26: * $Id: PageStateList.java 2754 2007-04-10 15:01:40Z taqua $ 27: * ------------ 28: * (C) Copyright 2000-2005, by Object Refinery Limited. 29: * (C) Copyright 2005-2007, by Pentaho Corporation. 30: */ 31: 32: package org.jfree.report.flow.paginating; 33: 34: import java.util.ArrayList; 35: 36: import org.jfree.layouting.StateException; 37: import org.jfree.report.DataSourceException; 38: import org.jfree.report.ReportDataFactoryException; 39: import org.jfree.report.ReportProcessingException; 40: import org.jfree.report.util.WeakReferenceList; 41: 42: 43: /** 44: * The ReportState list stores a report states for the beginning of every page. The list 45: * is filled on repagination and read when a report or a page of the report is printed. 46: * <p/> 47: * Important: This list stores page start report states, not arbitary report states. These 48: * ReportStates are special: they can be reproduced by calling processPage on the report. 49: * <p/> 50: * Internally this list is organized as a list of WeakReferenceLists, where every 51: * WeakReferenceList stores a certain number of page states. The first 20 states are 52: * stored in an ordinary list with strong-references, so these states never get 53: * GarbageCollected (and so they must never be restored by reprocessing them). The next 54: * 100 states are stored in 4-element ReferenceLists, so if a reference is lost, only 4 55: * states have to be reprocessed. All other states are stored in 10-element lists. 56: * 57: * @author Thomas Morgner 58: */ 59: public class PageStateList 60: { 61: /** 62: * The position of the master element in the list. A greater value will reduce the 63: * not-freeable memory used by the list, but restoring a single page will require more 64: * time. 65: */ 66: 67: /** 68: * The maxmimum masterposition size. 69: */ 70: private static final int MASTERPOSITIONS_MAX = 10; 71: 72: /** 73: * The medium masterposition size. 74: */ 75: private static final int MASTERPOSITIONS_MED = 4; 76: 77: /** 78: * The max index that will be stored in the primary list. 79: */ 80: private static final int PRIMARY_MAX = 20; 81: 82: /** 83: * The max index that will be stored in the master4 list. 84: */ 85: private static final int MASTER4_MAX = 120; 86: 87: /** 88: * Internal WeakReferenceList that is capable to restore its elements. The elements in 89: * this list are page start report states. 90: */ 91: private static final class MasterList extends WeakReferenceList 92: { 93: /** 94: * The master list. 95: */ 96: private final PageStateList master; 97: 98: /** 99: * Creates a new master list. 100: * 101: * @param list the list. 102: * @param maxChildCount the maximum number of elements in this list. 103: */ 104: private MasterList (final PageStateList list, final int maxChildCount) 105: { 106: super(maxChildCount); 107: this.master = list; 108: } 109: 110: /** 111: * Function to restore the state of a child after the child was garbage collected. 112: * 113: * @param index the index. 114: * @return the restored ReportState of the given index, or null, if the state could 115: * not be restored. 116: */ 117: protected Object restoreChild (final int index) 118: { 119: final PageState master = (PageState) getMaster(); 120: if (master == null) 121: { 122: return null; 123: } 124: final int max = getChildPos(index); 125: try 126: { 127: return this.restoreState(max, master); 128: } 129: catch (Exception rpe) 130: { 131: return null; 132: } 133: } 134: 135: /** 136: * Internal handler function restore a state. Count denotes the number of pages 137: * required to be processed to restore the page, when the reportstate master is used 138: * as source element. 139: * 140: * @param count the count. 141: * @param rootstate the root state. 142: * @return the report state. 143: * 144: * @throws ReportProcessingException if there was a problem processing the report. 145: */ 146: private PageState restoreState (final int count, final PageState rootstate) 147: throws ReportProcessingException, StateException, 148: ReportDataFactoryException, DataSourceException 149: { 150: if (rootstate == null) 151: { 152: throw new NullPointerException("Master is null"); 153: } 154: PageState state = rootstate; 155: for (int i = 0; i <= count; i++) 156: { 157: final PaginatingReportProcessor pageProcess = master.getPageProcess(); 158: state = pageProcess.processPage(state); 159: set(state, i + 1); 160: // todo: How to prevent endless loops. Should we prevent them at all? 161: } 162: return state; 163: } 164: } 165: 166: /** 167: * The list of master states. This is a list of WeakReferenceLists. These 168: * WeakReferenceLists contain their master state as first child. The weakReferenceLists 169: * have a maxSize of 10, so every 10th state will protected from being 170: * garbageCollected. 171: */ 172: private ArrayList masterStates10; // all states > 120 173: /** 174: * The list of master states. This is a list of WeakReferenceLists. These 175: * WeakReferenceLists contain their master state as first child. The weakReferenceLists 176: * have a maxSize of 4, so every 4th state will protected from being garbageCollected. 177: */ 178: private ArrayList masterStates4; // all states from 20 - 120 179: 180: /** 181: * The list of primary states. This is a list of ReportStates and is used to store the 182: * first 20 elements of this state list. 183: */ 184: private ArrayList primaryStates; // all states from 0 - 20 185: 186: /** 187: * The number of elements in this list. 188: */ 189: private int size; 190: 191: private PaginatingReportProcessor pageProcess; 192: 193: /** 194: * Creates a new reportstatelist. The list will be filled using the specified report and 195: * output target. Filling of the list is done elsewhere. 196: * 197: * @param proc the reportprocessor used to restore lost states (null not permitted). 198: * @throws NullPointerException if the report processor is <code>null</code>. 199: */ 200: public PageStateList (final PaginatingReportProcessor proc) 201: { 202: if (proc == null) 203: { 204: throw new NullPointerException("ReportProcessor null"); 205: } 206: 207: this.pageProcess = proc; 208: 209: primaryStates = new ArrayList(); 210: masterStates4 = new ArrayList(); 211: masterStates10 = new ArrayList(); 212: 213: } 214: 215: /** 216: * Returns the index of the WeakReferenceList in the master list. 217: * 218: * @param pos the position. 219: * @param maxListSize the maximum list size. 220: * @return the position within the masterStateList. 221: */ 222: private int getMasterPos (final int pos, final int maxListSize) 223: { 224: //return (int) Math.floor(pos / maxListSize); 225: return (pos / maxListSize); 226: } 227: 228: protected PaginatingReportProcessor getPageProcess () 229: { 230: return pageProcess; 231: } 232: 233: /** 234: * Returns the number of elements in this list. 235: * 236: * @return the number of elements in the list. 237: */ 238: public int size () 239: { 240: return this.size; 241: } 242: 243: /** 244: * Adds this report state to the end of the list. 245: * 246: * @param state the report state. 247: */ 248: public void add (final PageState state) 249: { 250: if (state == null) 251: { 252: throw new NullPointerException(); 253: } 254: 255: // the first 20 Elements are stored directly into an ArrayList 256: if (size() < PRIMARY_MAX) 257: { 258: primaryStates.add(state); 259: this.size++; 260: } 261: // the next 100 Elements are stored into a list of 4-element weakReference 262: //list. So if an Element gets lost (GCd), only 4 states need to be replayed. 263: else if (size() < MASTER4_MAX) 264: { 265: final int secPos = size() - PRIMARY_MAX; 266: final int masterPos = getMasterPos(secPos, MASTERPOSITIONS_MED); 267: if (masterPos >= masterStates4.size()) 268: { 269: final MasterList master = new MasterList(this, MASTERPOSITIONS_MED); 270: masterStates4.add(master); 271: master.add(state); 272: } 273: else 274: { 275: final MasterList master = (MasterList) masterStates4.get(masterPos); 276: master.add(state); 277: } 278: this.size++; 279: } 280: // all other Elements are stored into a list of 10-element weakReference 281: //list. So if an Element gets lost (GCd), 10 states need to be replayed. 282: else 283: { 284: final int thirdPos = size() - MASTER4_MAX; 285: final int masterPos = getMasterPos(thirdPos, MASTERPOSITIONS_MAX); 286: if (masterPos >= masterStates10.size()) 287: { 288: final MasterList master = new MasterList(this, MASTERPOSITIONS_MAX); 289: masterStates10.add(master); 290: master.add(state); 291: } 292: else 293: { 294: final MasterList master = (MasterList) masterStates10.get(masterPos); 295: master.add(state); 296: } 297: this.size++; 298: } 299: } 300: 301: /** 302: * Removes all elements in the list. 303: */ 304: public void clear () 305: { 306: masterStates10.clear(); 307: masterStates4.clear(); 308: primaryStates.clear(); 309: this.size = 0; 310: } 311: 312: /** 313: * Retrieves the element on position <code>index</code> in this list. 314: * 315: * @param index the index. 316: * @return the report state. 317: */ 318: public PageState get (int index) 319: { 320: if (index >= size() || index < 0) 321: { 322: throw new IndexOutOfBoundsException 323: ("Index is invalid. Index was " + index + "; size was " + size()); 324: } 325: if (index < PRIMARY_MAX) 326: { 327: return (PageState) primaryStates.get(index); 328: } 329: else if (index < MASTER4_MAX) 330: { 331: index -= PRIMARY_MAX; 332: final MasterList master 333: = (MasterList) masterStates4.get(getMasterPos(index, MASTERPOSITIONS_MED)); 334: return (PageState) master.get(index); 335: } 336: else 337: { 338: index -= MASTER4_MAX; 339: final MasterList master 340: = (MasterList) masterStates10.get(getMasterPos(index, MASTERPOSITIONS_MAX)); 341: return (PageState) master.get(index); 342: } 343: } 344: }