Source for org.jfree.report.flow.DefaultFlowController

   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: DefaultFlowController.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;
  32: 
  33: import org.jfree.report.DataSourceException;
  34: import org.jfree.report.ReportDataFactoryException;
  35: import org.jfree.report.data.CachingReportDataFactory;
  36: import org.jfree.report.data.ExpressionDataRow;
  37: import org.jfree.report.data.ExpressionSlot;
  38: import org.jfree.report.data.GlobalMasterRow;
  39: import org.jfree.report.data.ImportedVariablesDataRow;
  40: import org.jfree.report.data.ParameterDataRow;
  41: import org.jfree.report.data.PrecomputedValueRegistry;
  42: import org.jfree.report.data.PrecomputedValueRegistryBuilder;
  43: import org.jfree.report.data.ReportDataRow;
  44: import org.jfree.report.util.IntegerCache;
  45: import org.jfree.util.FastStack;
  46: 
  47: /**
  48:  * Creation-Date: 20.02.2006, 15:30:21
  49:  *
  50:  * @author Thomas Morgner
  51:  */
  52: public class DefaultFlowController implements FlowController
  53: {
  54:   private static class ReportDataContext
  55:   {
  56:     private FastStack markStack;
  57:     private boolean advanceRequested;
  58: 
  59:     private ReportDataContext(final FastStack markStack,
  60:                              final boolean advanceRequested)
  61:     {
  62:       this.advanceRequested = advanceRequested;
  63:       this.markStack = markStack;
  64:     }
  65: 
  66:     public boolean isAdvanceRequested()
  67:     {
  68:       return advanceRequested;
  69:     }
  70: 
  71:     public FastStack getMarkStack()
  72:     {
  73:       return markStack;
  74:     }
  75:   }
  76: 
  77:   private CachingReportDataFactory reportDataFactory;
  78:   private GlobalMasterRow dataRow;
  79:   private boolean advanceRequested;
  80:   private FastStack reportStack;
  81:   private FastStack markStack;
  82:   private FastStack expressionsStack;
  83:   private String exportDescriptor;
  84:   private ReportContext reportContext;
  85:   private ReportJob job;
  86:   private PrecomputedValueRegistry precomputedValueRegistry;
  87: 
  88:   public DefaultFlowController(final ReportContext reportContext,
  89:                                final ReportJob job)
  90:       throws DataSourceException
  91:   {
  92:     if (job == null)
  93:     {
  94:       throw new NullPointerException();
  95:     }
  96:     if (reportContext == null)
  97:     {
  98:       throw new NullPointerException();
  99:     }
 100: 
 101:     this.reportContext = reportContext;
 102:     this.job = job;
 103:     this.exportDescriptor = reportContext.getExportDescriptor();
 104:     this.reportDataFactory = new CachingReportDataFactory(job.getDataFactory());
 105:     this.reportStack = new FastStack();
 106:     this.markStack = new FastStack();
 107:     this.expressionsStack = new FastStack();
 108:     this.advanceRequested = false;
 109:     this.dataRow = GlobalMasterRow.createReportRow(reportContext);
 110:     this.dataRow.setParameterDataRow(new ParameterDataRow(job.getParameters()));
 111:     this.precomputedValueRegistry = new PrecomputedValueRegistryBuilder();
 112:   }
 113: 
 114:   protected DefaultFlowController(final DefaultFlowController fc,
 115:                                   final GlobalMasterRow dataRow)
 116:   {
 117:     this.reportContext = fc.reportContext;
 118:     this.job = fc.job;
 119:     this.exportDescriptor = fc.exportDescriptor;
 120:     this.reportDataFactory = fc.reportDataFactory;
 121:     this.reportStack = (FastStack) fc.reportStack.clone();
 122:     this.markStack = (FastStack) fc.markStack.clone();
 123:     this.expressionsStack = (FastStack) fc.expressionsStack.clone();
 124:     this.advanceRequested = fc.advanceRequested;
 125:     this.dataRow = dataRow;
 126:     this.precomputedValueRegistry = fc.precomputedValueRegistry;
 127:   }
 128: 
 129: 
 130:   public FlowController performOperation(final FlowControlOperation operation)
 131:       throws DataSourceException
 132:   {
 133:     if (operation == FlowControlOperation.ADVANCE)
 134:     {
 135:       if (dataRow.isAdvanceable() && advanceRequested == false)
 136:       {
 137:         final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 138:         fc.advanceRequested = true;
 139:         return fc;
 140:       }
 141:     }
 142:     else if (operation == FlowControlOperation.MARK)
 143:     {
 144:       final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 145:       fc.markStack.push(dataRow);
 146:       return fc;
 147:     }
 148:     else if (operation == FlowControlOperation.RECALL)
 149:     {
 150:       if (markStack.isEmpty())
 151:       {
 152:         return this;
 153:       }
 154: 
 155:       final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 156:       fc.dataRow = (GlobalMasterRow) fc.markStack.pop();
 157:       fc.advanceRequested = false;
 158:       return fc;
 159:     }
 160:     else if (operation == FlowControlOperation.DONE)
 161:     {
 162:       // do not change the current data row..
 163: 
 164:       final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 165:       fc.markStack.pop();
 166:       return fc;
 167:     }
 168:     else if (operation == FlowControlOperation.COMMIT)
 169:     {
 170:       if (isAdvanceRequested())
 171:       {
 172:         final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 173:         fc.dataRow = dataRow.advance();
 174:         fc.advanceRequested = false;
 175:         return fc;
 176:       }
 177:     }
 178:     return this;
 179:   }
 180: 
 181:   public GlobalMasterRow getMasterRow()
 182:   {
 183:     return dataRow;
 184:   }
 185: 
 186: 
 187:   public boolean isAdvanceRequested()
 188:   {
 189:     return advanceRequested;
 190:   }
 191: 
 192:   /**
 193:    * This should be called only once per report processing. A JFreeReport object
 194:    * defines the global master report - all other reports are subreport
 195:    * instances.
 196:    * <p/>
 197:    * The global master report receives its parameter set from the
 198:    * Job-Definition, while subreports will read their parameters from the
 199:    * current datarow state.
 200:    *
 201:    * @param query
 202:    * @return
 203:    * @throws ReportDataFactoryException
 204:    * @throws DataSourceException
 205:    */
 206:   public FlowController performQuery(final String query)
 207:       throws ReportDataFactoryException, DataSourceException
 208:   {
 209: 
 210:     final GlobalMasterRow masterRow =
 211:         GlobalMasterRow.createReportRow(dataRow, reportContext);
 212:     masterRow.setParameterDataRow(new ParameterDataRow
 213:         (getReportJob().getParameters()));
 214: 
 215:     masterRow.setReportDataRow(ReportDataRow.createDataRow
 216:         (reportDataFactory, query, dataRow.getGlobalView()));
 217: 
 218:     final DefaultFlowController fc = new DefaultFlowController(this, masterRow);
 219:     fc.reportStack.push(new ReportDataContext(fc.markStack, advanceRequested));
 220:     fc.markStack = new FastStack();
 221:     fc.dataRow = masterRow;
 222:     return fc;
 223:   }
 224: 
 225:   public FlowController performSubReportQuery(final String query,
 226:                                               final ParameterMapping[] inputParameters,
 227:                                               final ParameterMapping[] outputParameters
 228:                                               )
 229:       throws ReportDataFactoryException, DataSourceException
 230:   {
 231:     final GlobalMasterRow outerRow = dataRow.derive();
 232: 
 233:     // create a view for the parameters of the report ...
 234:     final GlobalMasterRow masterRow =
 235:         GlobalMasterRow.createReportRow(outerRow, reportContext);
 236: 
 237:     masterRow.setParameterDataRow
 238:         (new ParameterDataRow(inputParameters, outerRow.getGlobalView()));
 239: 
 240:     // perform the query ...
 241:     // add the resultset ...
 242:     masterRow.setReportDataRow(ReportDataRow.createDataRow
 243:         (reportDataFactory, query, masterRow.getGlobalView()));
 244: 
 245:     if (outputParameters == null)
 246:     {
 247:       outerRow.setExportedDataRow(new ImportedVariablesDataRow(masterRow));
 248:     }
 249:     else
 250:     {
 251:       // check and rebuild the parameter mapping from the inner to the outer
 252:       // context. Only deep-traversal expressions will be able to see these
 253:       // values (unless they have been defined as local variables).
 254:       outerRow.setExportedDataRow(new ImportedVariablesDataRow
 255:           (masterRow, outputParameters));
 256:     }
 257: 
 258:     final DefaultFlowController fc = new DefaultFlowController(this, masterRow);
 259:     fc.reportStack.push(new ReportDataContext(fc.markStack, advanceRequested));
 260:     fc.markStack = new FastStack();
 261:     fc.dataRow = masterRow;
 262:     return fc;
 263:   }
 264: 
 265:   public FlowController activateExpressions(final ExpressionSlot[] expressions)
 266:       throws DataSourceException
 267:   {
 268:     if (expressions.length == 0)
 269:     {
 270:       final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 271:       fc.expressionsStack.push(IntegerCache.getInteger(0));
 272:       return fc;
 273:     }
 274: 
 275:     final GlobalMasterRow dataRow = this.dataRow.derive();
 276:     final ExpressionDataRow edr = dataRow.getExpressionDataRow();
 277:     edr.pushExpressions(expressions);
 278: 
 279:     final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 280:     final Integer exCount = IntegerCache.getInteger(expressions.length);
 281:     fc.expressionsStack.push(exCount);
 282:     return fc;
 283:   }
 284: 
 285:   public FlowController deactivateExpressions() throws DataSourceException
 286:   {
 287:     final Integer counter = (Integer) this.expressionsStack.peek();
 288:     final int counterRaw = counter.intValue();
 289:     if (counterRaw == 0)
 290:     {
 291:       final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 292:       fc.expressionsStack.pop();
 293:       return fc;
 294:     }
 295: 
 296:     final GlobalMasterRow dataRow = this.dataRow.derive();
 297:     final ExpressionDataRow edr = dataRow.getExpressionDataRow();
 298: 
 299:     final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 300:     fc.expressionsStack.pop();
 301:     edr.popExpressions(counterRaw);
 302:     return fc;
 303:   }
 304: 
 305:   public FlowController performReturnFromQuery() throws DataSourceException
 306:   {
 307:     final DefaultFlowController fc = new DefaultFlowController(this, dataRow);
 308:     final ReportDataRow reportDataRow = dataRow.getReportDataRow();
 309:     if (reportDataRow == null)
 310:     {
 311:       return this;
 312:     }
 313:     // We dont close the report data, as some previously saved states may
 314:     // still reference it. (The caching report data factory takes care of
 315:     // that later.)
 316: 
 317:     final ReportDataContext context = (ReportDataContext) fc.reportStack.pop();
 318:     fc.dataRow = dataRow.getParentDataRow();
 319:     fc.dataRow = fc.dataRow.derive();
 320:     fc.dataRow.setExportedDataRow(null);
 321:     fc.markStack = context.getMarkStack();
 322:     fc.advanceRequested = context.isAdvanceRequested();
 323:     return fc;
 324:   }
 325: 
 326:   public ReportJob getReportJob()
 327:   {
 328:     return job;
 329:   }
 330: 
 331:   public String getExportDescriptor()
 332:   {
 333:     return exportDescriptor;
 334:   }
 335: 
 336:   public ReportContext getReportContext()
 337:   {
 338:     return reportContext;
 339:   }
 340: 
 341:   /**
 342:    * Returns the current expression slots of all currently active expressions.
 343:    *
 344:    * @return
 345:    * @throws org.jfree.report.DataSourceException
 346:    *
 347:    */
 348:   public ExpressionSlot[] getActiveExpressions() throws DataSourceException
 349:   {
 350:     return dataRow.getExpressionDataRow().getSlots();
 351:   }
 352: 
 353:   public FlowController createPrecomputeInstance() throws DataSourceException
 354:   {
 355:     final DefaultFlowController precompute = new DefaultFlowController(this, dataRow.derive());
 356:     precompute.precomputedValueRegistry = new PrecomputedValueRegistryBuilder();
 357:     return precompute;
 358:   }
 359: 
 360:   public PrecomputedValueRegistry getPrecomputedValueRegistry()
 361:   {
 362:     return precomputedValueRegistry;
 363:   }
 364: }