001: /**
002: * ========================================
003: * JFreeReport : a free Java report library
004: * ========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * $Id: PaginatingReportProcessor.java 3525 2007-10-16 11:43:48Z tmorgner $
027: * ------------
028: * (C) Copyright 2000-2005, by Object Refinery Limited.
029: * (C) Copyright 2005-2007, by Pentaho Corporation.
030: */package org.jfree.report.flow.paginating;
031:
032: import org.jfree.layouting.ChainingLayoutProcess;
033: import org.jfree.layouting.DefaultLayoutProcess;
034: import org.jfree.layouting.LayoutProcess;
035: import org.jfree.layouting.StateException;
036: import org.jfree.layouting.output.pageable.PageableOutputProcessor;
037: import org.jfree.layouting.util.IntList;
038: import org.jfree.report.DataSourceException;
039: import org.jfree.report.ReportDataFactoryException;
040: import org.jfree.report.ReportProcessingException;
041: import org.jfree.report.flow.AbstractReportProcessor;
042: import org.jfree.report.flow.FlowController;
043: import org.jfree.report.flow.LibLayoutReportTarget;
044: import org.jfree.report.flow.ReportContext;
045: import org.jfree.report.flow.ReportJob;
046: import org.jfree.report.flow.ReportTarget;
047: import org.jfree.report.flow.ReportTargetState;
048: import org.jfree.report.flow.layoutprocessor.LayoutController;
049: import org.jfree.report.flow.layoutprocessor.LayoutControllerFactory;
050: import org.jfree.resourceloader.ResourceKey;
051: import org.jfree.resourceloader.ResourceManager;
052: import org.jfree.util.Log;
053:
054: /**
055: * Paginating report processors are multi-pass processors.
056: * <p/>
057: * This is written to use LibLayout. It will never work with other report
058: * targets.
059: *
060: * Be aware that this class is not synchronized.
061: *
062: * @author Thomas Morgner
063: */
064: public abstract class PaginatingReportProcessor extends
065: AbstractReportProcessor {
066: private PageableOutputProcessor outputProcessor;
067: private PageStateList stateList;
068: private IntList physicalMapping;
069: private IntList logicalMapping;
070:
071: protected PaginatingReportProcessor(
072: final PageableOutputProcessor outputProcessor) {
073: this .outputProcessor = outputProcessor;
074: }
075:
076: public PageableOutputProcessor getOutputProcessor() {
077: return outputProcessor;
078: }
079:
080: protected LibLayoutReportTarget createTarget(final ReportJob job) {
081: if (outputProcessor == null) {
082: throw new IllegalStateException(
083: "OutputProcessor is invalid.");
084: }
085: final LayoutProcess layoutProcess = new ChainingLayoutProcess(
086: new DefaultLayoutProcess(outputProcessor));
087: final ResourceManager resourceManager = job
088: .getReportStructureRoot().getResourceManager();
089: final ResourceKey resourceKey = job.getReportStructureRoot()
090: .getBaseResource();
091:
092: return new LibLayoutReportTarget(job, resourceKey,
093: resourceManager, layoutProcess);
094: }
095:
096: // public void processReport(ReportJob job)
097: // throws ReportDataFactoryException,
098: // DataSourceException, ReportProcessingException
099: // {
100: // prepareReportProcessing(job);
101: //
102: // }
103:
104: protected void prepareReportProcessing(final ReportJob job)
105: throws ReportDataFactoryException, DataSourceException,
106: ReportProcessingException {
107: if (job == null) {
108: throw new NullPointerException();
109: }
110:
111: final long start = System.currentTimeMillis();
112: // first, compute the globals
113: processReportRun(job, createTarget(job));
114: if (outputProcessor.isGlobalStateComputed() == false) {
115: throw new ReportProcessingException(
116: "Pagination has not yet been finished.");
117: }
118:
119: // second, paginate
120: processPaginationRun(job, createTarget(job));
121: if (outputProcessor.isPaginationFinished() == false) {
122: throw new ReportProcessingException(
123: "Pagination has not yet been finished.");
124: }
125:
126: if (outputProcessor.isContentGeneratable() == false) {
127: throw new ReportProcessingException("Illegal State.");
128: }
129: final long end = System.currentTimeMillis();
130: // System.out.println("Pagination-Time: " + (end - start));
131: }
132:
133: protected PageStateList processPaginationRun(final ReportJob job,
134: final LibLayoutReportTarget target)
135: throws ReportDataFactoryException, DataSourceException,
136: ReportProcessingException {
137: if (job == null) {
138: throw new NullPointerException();
139: }
140: stateList = new PageStateList(this );
141: physicalMapping = new IntList(40);
142: logicalMapping = new IntList(20);
143:
144: final ReportContext context = createReportContext(job, target);
145: final LayoutControllerFactory layoutFactory = context
146: .getLayoutControllerFactory();
147:
148: // we have the data and we have our position inside the report.
149: // lets generate something ...
150: final FlowController flowController = createFlowControler(
151: context, job);
152:
153: LayoutController layoutController = layoutFactory.create(
154: flowController, job.getReportStructureRoot(), null);
155:
156: try {
157: stateList.add(new PageState(target.saveState(),
158: layoutController, outputProcessor.getPageCursor()));
159: int logPageCount = outputProcessor.getLogicalPageCount();
160: int physPageCount = outputProcessor.getPhysicalPageCount();
161:
162: while (layoutController.isAdvanceable()) {
163: layoutController = layoutController.advance(target);
164: target.commit();
165:
166: while (layoutController.isAdvanceable() == false
167: && layoutController.getParent() != null) {
168: final LayoutController parent = layoutController
169: .getParent();
170: layoutController = parent.join(layoutController
171: .getFlowController());
172: }
173:
174: // check whether a pagebreak has been encountered.
175: if (target.isPagebreakEncountered()) {
176: // So we hit a pagebreak. Store the state for later reuse.
177: // A single state can refer to more than one physical page.
178:
179: final int newLogPageCount = outputProcessor
180: .getLogicalPageCount();
181: final int newPhysPageCount = outputProcessor
182: .getPhysicalPageCount();
183:
184: final int result = stateList.size() - 1;
185: for (; physPageCount < newPhysPageCount; physPageCount++) {
186: physicalMapping.add(result);
187: }
188:
189: for (; logPageCount < newLogPageCount; logPageCount++) {
190: logicalMapping.add(result);
191: }
192:
193: logPageCount = newLogPageCount;
194: physPageCount = newPhysPageCount;
195:
196: final ReportTargetState targetState = target
197: .saveState();
198: final PageState state = new PageState(targetState,
199: layoutController, outputProcessor
200: .getPageCursor());
201: stateList.add(state);
202:
203: // This is an assertation that we do not run into invalid states
204: // later.
205: if (PaginatingReportProcessor.ASSERTATION) {
206: final ReportTarget reportTarget = targetState
207: .restore(outputProcessor);
208: }
209:
210: target.resetPagebreakFlag();
211: }
212: }
213:
214: // And when we reached the end, add the remaining pages ..
215: final int newLogPageCount = outputProcessor
216: .getLogicalPageCount();
217: final int newPhysPageCount = outputProcessor
218: .getPhysicalPageCount();
219:
220: final int result = stateList.size() - 1;
221: for (; physPageCount < newPhysPageCount; physPageCount++) {
222: physicalMapping.add(result);
223: }
224:
225: for (; logPageCount < newLogPageCount; logPageCount++) {
226: logicalMapping.add(result);
227: }
228: } catch (final StateException e) {
229: throw new ReportProcessingException(
230: "Argh, Unable to save the state!");
231: }
232:
233: Log.debug("After pagination we have " + stateList.size()
234: + " states");
235: return stateList;
236: }
237:
238: public boolean isPaginated() {
239: return outputProcessor.isPaginationFinished();
240: }
241:
242: protected PageState getLogicalPageState(final int page) {
243: return stateList.get(logicalMapping.get(page));
244: }
245:
246: protected PageState getPhysicalPageState(final int page) {
247: return stateList.get(physicalMapping.get(page));
248: }
249:
250: public PageState processPage(final PageState previousState)
251: throws StateException, ReportProcessingException,
252: ReportDataFactoryException, DataSourceException {
253: final ReportTargetState targetState = previousState
254: .getTargetState();
255: final LibLayoutReportTarget target = (LibLayoutReportTarget) targetState
256: .restore(outputProcessor);
257: outputProcessor.setPageCursor(previousState.getPageCursor());
258:
259: LayoutController position = previousState.getLayoutController();
260:
261: // we have the data and we have our position inside the report.
262: // lets generate something ...
263:
264: while (position.isAdvanceable()) {
265: position = position.advance(target);
266: target.commit();
267:
268: // else check whether this state is finished, and try to join the subflow
269: // with the parent.
270: while (position.isAdvanceable() == false
271: && position.getParent() != null) {
272: final LayoutController parent = position.getParent();
273: position = parent.join(position.getFlowController());
274: }
275:
276: // check whether a pagebreak has been encountered.
277: if (target.isPagebreakEncountered()) {
278: // So we hit a pagebreak. Store the state for later reuse.
279: // A single state can refer to more than one physical page.
280: final PageState state = new PageState(target
281: .saveState(), position, outputProcessor
282: .getPageCursor());
283: target.resetPagebreakFlag();
284: return state;
285: }
286:
287: }
288:
289: // reached the finish state .. this is bad!
290: return null;
291: }
292:
293: private static final boolean ASSERTATION = true;
294: }
|