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: DefaultFlowController.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 */ 031 package org.jfree.report.flow; 032 033 import org.jfree.report.DataSourceException; 034 import org.jfree.report.ReportDataFactoryException; 035 import org.jfree.report.data.CachingReportDataFactory; 036 import org.jfree.report.data.ExpressionDataRow; 037 import org.jfree.report.data.ExpressionSlot; 038 import org.jfree.report.data.GlobalMasterRow; 039 import org.jfree.report.data.ImportedVariablesDataRow; 040 import org.jfree.report.data.ParameterDataRow; 041 import org.jfree.report.data.PrecomputedValueRegistry; 042 import org.jfree.report.data.PrecomputedValueRegistryBuilder; 043 import org.jfree.report.data.ReportDataRow; 044 import org.jfree.report.util.IntegerCache; 045 import org.jfree.util.FastStack; 046 047 /** 048 * Creation-Date: 20.02.2006, 15:30:21 049 * 050 * @author Thomas Morgner 051 */ 052 public class DefaultFlowController implements FlowController 053 { 054 private static class ReportDataContext 055 { 056 private FastStack markStack; 057 private boolean advanceRequested; 058 059 private ReportDataContext(final FastStack markStack, 060 final boolean advanceRequested) 061 { 062 this.advanceRequested = advanceRequested; 063 this.markStack = markStack; 064 } 065 066 public boolean isAdvanceRequested() 067 { 068 return advanceRequested; 069 } 070 071 public FastStack getMarkStack() 072 { 073 return markStack; 074 } 075 } 076 077 private CachingReportDataFactory reportDataFactory; 078 private GlobalMasterRow dataRow; 079 private boolean advanceRequested; 080 private FastStack reportStack; 081 private FastStack markStack; 082 private FastStack expressionsStack; 083 private String exportDescriptor; 084 private ReportContext reportContext; 085 private ReportJob job; 086 private PrecomputedValueRegistry precomputedValueRegistry; 087 088 public DefaultFlowController(final ReportContext reportContext, 089 final ReportJob job) 090 throws DataSourceException 091 { 092 if (job == null) 093 { 094 throw new NullPointerException(); 095 } 096 if (reportContext == null) 097 { 098 throw new NullPointerException(); 099 } 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 }