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,v 1.10 2007/05/09 12:28:24 taqua Exp $
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 public ReportDataContext(final FastStack markStack,
060 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(FlowControlOperation operation)
131 throws DataSourceException
132 {
133 if (operation == FlowControlOperation.ADVANCE)
134 {
135 if (dataRow.isAdvanceable() && advanceRequested == false)
136 {
137 DefaultFlowController fc = new DefaultFlowController(this, dataRow);
138 fc.advanceRequested = true;
139 return fc;
140 }
141 }
142 else if (operation == FlowControlOperation.MARK)
143 {
144 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 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 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 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 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 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 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 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 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 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 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 }