Source for org.jfree.report.flow.paginating.PaginatingReportProcessor

   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: PaginatingReportProcessor.java 3525 2007-10-16 11:43:48Z tmorgner $
  27:  * ------------
  28:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  29:  * (C) Copyright 2005-2007, by Pentaho Corporation.
  30:  */
  31: package org.jfree.report.flow.paginating;
  32: 
  33: import org.jfree.layouting.ChainingLayoutProcess;
  34: import org.jfree.layouting.DefaultLayoutProcess;
  35: import org.jfree.layouting.LayoutProcess;
  36: import org.jfree.layouting.StateException;
  37: import org.jfree.layouting.output.pageable.PageableOutputProcessor;
  38: import org.jfree.layouting.util.IntList;
  39: import org.jfree.report.DataSourceException;
  40: import org.jfree.report.ReportDataFactoryException;
  41: import org.jfree.report.ReportProcessingException;
  42: import org.jfree.report.flow.AbstractReportProcessor;
  43: import org.jfree.report.flow.FlowController;
  44: import org.jfree.report.flow.LibLayoutReportTarget;
  45: import org.jfree.report.flow.ReportContext;
  46: import org.jfree.report.flow.ReportJob;
  47: import org.jfree.report.flow.ReportTarget;
  48: import org.jfree.report.flow.ReportTargetState;
  49: import org.jfree.report.flow.layoutprocessor.LayoutController;
  50: import org.jfree.report.flow.layoutprocessor.LayoutControllerFactory;
  51: import org.jfree.resourceloader.ResourceKey;
  52: import org.jfree.resourceloader.ResourceManager;
  53: import org.jfree.util.Log;
  54: 
  55: /**
  56:  * Paginating report processors are multi-pass processors.
  57:  * <p/>
  58:  * This is written to use LibLayout. It will never work with other report
  59:  * targets.
  60:  *
  61:  * Be aware that this class is not synchronized.
  62:  *
  63:  * @author Thomas Morgner
  64:  */
  65: public abstract class PaginatingReportProcessor extends AbstractReportProcessor
  66: {
  67:   private PageableOutputProcessor outputProcessor;
  68:   private PageStateList stateList;
  69:   private IntList physicalMapping;
  70:   private IntList logicalMapping;
  71: 
  72:   protected PaginatingReportProcessor(final PageableOutputProcessor outputProcessor)
  73:   {
  74:     this.outputProcessor = outputProcessor;
  75:   }
  76: 
  77:   public PageableOutputProcessor getOutputProcessor()
  78:   {
  79:     return outputProcessor;
  80:   }
  81: 
  82:   protected LibLayoutReportTarget createTarget(final ReportJob job)
  83:   {
  84:     if (outputProcessor == null)
  85:     {
  86:       throw new IllegalStateException("OutputProcessor is invalid.");
  87:     }
  88:     final LayoutProcess layoutProcess =
  89:         new ChainingLayoutProcess(new DefaultLayoutProcess(outputProcessor));
  90:     final ResourceManager resourceManager = job.getReportStructureRoot().getResourceManager();
  91:     final ResourceKey resourceKey = job.getReportStructureRoot().getBaseResource();
  92: 
  93:     return new LibLayoutReportTarget
  94:         (job, resourceKey, resourceManager, layoutProcess);
  95:   }
  96: 
  97: //  public void processReport(ReportJob job)
  98: //      throws ReportDataFactoryException,
  99: //      DataSourceException, ReportProcessingException
 100: //  {
 101: //    prepareReportProcessing(job);
 102: //
 103: //  }
 104: 
 105:   protected void prepareReportProcessing(final ReportJob job)
 106:       throws ReportDataFactoryException, DataSourceException, ReportProcessingException
 107:   {
 108:     if (job == null)
 109:     {
 110:       throw new NullPointerException();
 111:     }
 112: 
 113:     final long start = System.currentTimeMillis();
 114:     // first, compute the globals
 115:     processReportRun(job, createTarget(job));
 116:     if (outputProcessor.isGlobalStateComputed() == false)
 117:     {
 118:       throw new ReportProcessingException
 119:           ("Pagination has not yet been finished.");
 120:     }
 121: 
 122:     // second, paginate
 123:     processPaginationRun(job, createTarget(job));
 124:     if (outputProcessor.isPaginationFinished() == false)
 125:     {
 126:       throw new ReportProcessingException
 127:           ("Pagination has not yet been finished.");
 128:     }
 129: 
 130:     if (outputProcessor.isContentGeneratable() == false)
 131:     {
 132:       throw new ReportProcessingException
 133:           ("Illegal State.");
 134:     }
 135:     final long end = System.currentTimeMillis();
 136: //    System.out.println("Pagination-Time: " + (end - start));
 137:   }
 138: 
 139:   protected PageStateList processPaginationRun(final ReportJob job,
 140:                                                final LibLayoutReportTarget target)
 141:       throws ReportDataFactoryException,
 142:       DataSourceException, ReportProcessingException
 143:   {
 144:     if (job == null)
 145:     {
 146:       throw new NullPointerException();
 147:     }
 148:     stateList = new PageStateList(this);
 149:     physicalMapping = new IntList(40);
 150:     logicalMapping = new IntList(20);
 151: 
 152:     final ReportContext context = createReportContext(job, target);
 153:     final LayoutControllerFactory layoutFactory =
 154:         context.getLayoutControllerFactory();
 155: 
 156:     // we have the data and we have our position inside the report.
 157:     // lets generate something ...
 158:     final FlowController flowController = createFlowControler(context, job);
 159: 
 160:     LayoutController layoutController =
 161:         layoutFactory.create(flowController, job.getReportStructureRoot(), null);
 162: 
 163:     try
 164:     {
 165:       stateList.add(new PageState(target.saveState(), layoutController,
 166:           outputProcessor.getPageCursor()));
 167:       int logPageCount = outputProcessor.getLogicalPageCount();
 168:       int physPageCount = outputProcessor.getPhysicalPageCount();
 169: 
 170:       while (layoutController.isAdvanceable())
 171:       {
 172:         layoutController = layoutController.advance(target);
 173:         target.commit();
 174: 
 175:         while (layoutController.isAdvanceable() == false &&
 176:                layoutController.getParent() != null)
 177:         {
 178:           final LayoutController parent = layoutController.getParent();
 179:           layoutController = parent.join(layoutController.getFlowController());
 180:         }
 181: 
 182:         // check whether a pagebreak has been encountered.
 183:         if (target.isPagebreakEncountered())
 184:         {
 185:           // So we hit a pagebreak. Store the state for later reuse.
 186:           // A single state can refer to more than one physical page.
 187: 
 188:           final int newLogPageCount = outputProcessor.getLogicalPageCount();
 189:           final int newPhysPageCount = outputProcessor.getPhysicalPageCount();
 190: 
 191:           final int result = stateList.size() - 1;
 192:           for (; physPageCount < newPhysPageCount; physPageCount++)
 193:           {
 194:             physicalMapping.add(result);
 195:           }
 196: 
 197:           for (; logPageCount < newLogPageCount; logPageCount++)
 198:           {
 199:             logicalMapping.add(result);
 200:           }
 201: 
 202:           logPageCount = newLogPageCount;
 203:           physPageCount = newPhysPageCount;
 204: 
 205:           final ReportTargetState targetState = target.saveState();
 206:           final PageState state =
 207:               new PageState (targetState, layoutController,
 208:               outputProcessor.getPageCursor());
 209:           stateList.add(state);
 210: 
 211:           // This is an assertation that we do not run into invalid states
 212:           // later.
 213:           if (PaginatingReportProcessor.ASSERTATION)
 214:           {
 215:             final ReportTarget reportTarget =
 216:               targetState.restore(outputProcessor);
 217:           }
 218: 
 219:           target.resetPagebreakFlag();
 220:         }
 221:       }
 222: 
 223:       // And when we reached the end, add the remaining pages ..
 224:       final int newLogPageCount = outputProcessor.getLogicalPageCount();
 225:       final int newPhysPageCount = outputProcessor.getPhysicalPageCount();
 226: 
 227:       final int result = stateList.size() - 1;
 228:       for (; physPageCount < newPhysPageCount; physPageCount++)
 229:       {
 230:         physicalMapping.add(result);
 231:       }
 232: 
 233:       for (; logPageCount < newLogPageCount; logPageCount++)
 234:       {
 235:         logicalMapping.add(result);
 236:       }
 237:     }
 238:     catch (final StateException e)
 239:     {
 240:       throw new ReportProcessingException("Argh, Unable to save the state!");
 241:     }
 242: 
 243:     Log.debug("After pagination we have " + stateList.size() + " states");
 244:     return stateList;
 245:   }
 246: 
 247:   public boolean isPaginated()
 248:   {
 249:     return outputProcessor.isPaginationFinished();
 250:   }
 251: 
 252:   protected PageState getLogicalPageState (final int page)
 253:   {
 254:     return stateList.get(logicalMapping.get(page));
 255:   }
 256: 
 257:   protected PageState getPhysicalPageState (final int page)
 258:   {
 259:     return stateList.get(physicalMapping.get(page));
 260:   }
 261: 
 262:   public PageState processPage(final PageState previousState)
 263:       throws StateException, ReportProcessingException,
 264:       ReportDataFactoryException, DataSourceException
 265:   {
 266:     final ReportTargetState targetState = previousState.getTargetState();
 267:     final LibLayoutReportTarget target =
 268:         (LibLayoutReportTarget) targetState.restore(outputProcessor);
 269:     outputProcessor.setPageCursor(previousState.getPageCursor());
 270: 
 271:     LayoutController position = previousState.getLayoutController();
 272: 
 273:     // we have the data and we have our position inside the report.
 274:     // lets generate something ...
 275: 
 276:     while (position.isAdvanceable())
 277:     {
 278:       position = position.advance(target);
 279:       target.commit();
 280: 
 281:       // else check whether this state is finished, and try to join the subflow
 282:       // with the parent.
 283:       while (position.isAdvanceable() == false &&
 284:              position.getParent() != null)
 285:       {
 286:         final LayoutController parent = position.getParent();
 287:         position = parent.join(position.getFlowController());
 288:       }
 289: 
 290:       // check whether a pagebreak has been encountered.
 291:       if (target.isPagebreakEncountered())
 292:       {
 293:         // So we hit a pagebreak. Store the state for later reuse.
 294:         // A single state can refer to more than one physical page.
 295:         final PageState state = new PageState
 296:             (target.saveState(), position, outputProcessor.getPageCursor());
 297:         target.resetPagebreakFlag();
 298:         return state;
 299:       }
 300: 
 301:     }
 302: 
 303:     // reached the finish state .. this is bad!
 304:     return null;
 305:   }
 306: 
 307:   private static final boolean ASSERTATION = true;
 308: }