1
24 package net.sf.jasperreports.engine.fill;
25
26 import java.sql.Connection;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.Map;
35 import java.util.ResourceBundle;
36 import java.util.Set;
37 import java.util.TimeZone;
38 import java.util.UUID;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43 import net.sf.jasperreports.data.cache.CachedDataset;
44 import net.sf.jasperreports.data.cache.DataCacheHandler;
45 import net.sf.jasperreports.data.cache.DataRecorder;
46 import net.sf.jasperreports.data.cache.DataSnapshot;
47 import net.sf.jasperreports.data.cache.DataSnapshotException;
48 import net.sf.jasperreports.data.cache.DatasetRecorder;
49 import net.sf.jasperreports.engine.DatasetFilter;
50 import net.sf.jasperreports.engine.DatasetPropertyExpression;
51 import net.sf.jasperreports.engine.DefaultJasperReportsContext;
52 import net.sf.jasperreports.engine.EvaluationType;
53 import net.sf.jasperreports.engine.JRAbstractScriptlet;
54 import net.sf.jasperreports.engine.JRDataSource;
55 import net.sf.jasperreports.engine.JRDataset;
56 import net.sf.jasperreports.engine.JRDefaultScriptlet;
57 import net.sf.jasperreports.engine.JRException;
58 import net.sf.jasperreports.engine.JRExpression;
59 import net.sf.jasperreports.engine.JRField;
60 import net.sf.jasperreports.engine.JRGroup;
61 import net.sf.jasperreports.engine.JRParameter;
62 import net.sf.jasperreports.engine.JRPropertiesHolder;
63 import net.sf.jasperreports.engine.JRPropertiesMap;
64 import net.sf.jasperreports.engine.JRPropertiesUtil;
65 import net.sf.jasperreports.engine.JRQuery;
66 import net.sf.jasperreports.engine.JRRuntimeException;
67 import net.sf.jasperreports.engine.JRScriptlet;
68 import net.sf.jasperreports.engine.JRSortField;
69 import net.sf.jasperreports.engine.JRVariable;
70 import net.sf.jasperreports.engine.JasperCompileManager;
71 import net.sf.jasperreports.engine.JasperReport;
72 import net.sf.jasperreports.engine.JasperReportsContext;
73 import net.sf.jasperreports.engine.ParameterContributor;
74 import net.sf.jasperreports.engine.ParameterContributorContext;
75 import net.sf.jasperreports.engine.ParameterContributorFactory;
76 import net.sf.jasperreports.engine.data.IndexedDataSource;
77 import net.sf.jasperreports.engine.design.JRDesignVariable;
78 import net.sf.jasperreports.engine.query.JRQueryExecuter;
79 import net.sf.jasperreports.engine.query.QueryExecuterFactory;
80 import net.sf.jasperreports.engine.query.SimpleQueryExecutionContext;
81 import net.sf.jasperreports.engine.scriptlets.ScriptletFactory;
82 import net.sf.jasperreports.engine.scriptlets.ScriptletFactoryContext;
83 import net.sf.jasperreports.engine.type.CalculationEnum;
84 import net.sf.jasperreports.engine.type.IncrementTypeEnum;
85 import net.sf.jasperreports.engine.type.ParameterEvaluationTimeEnum;
86 import net.sf.jasperreports.engine.type.PropertyEvaluationTimeEnum;
87 import net.sf.jasperreports.engine.type.ResetTypeEnum;
88 import net.sf.jasperreports.engine.type.WhenResourceMissingTypeEnum;
89 import net.sf.jasperreports.engine.util.DigestUtils;
90 import net.sf.jasperreports.engine.util.JRDataUtils;
91 import net.sf.jasperreports.engine.util.JRQueryExecuterUtils;
92 import net.sf.jasperreports.engine.util.JRResourcesUtil;
93 import net.sf.jasperreports.engine.util.MD5Digest;
94 import net.sf.jasperreports.repo.RepositoryContext;
95 import net.sf.jasperreports.repo.SimpleRepositoryContext;
96
97
100 public class JRFillDataset implements JRDataset, DatasetFillContext
101 {
102
103 private static final Log log = LogFactory.getLog(JRFillDataset.class);
104
105 public static final String EXCEPTION_MESSAGE_KEY_NO_SUCH_FIELD = "fill.dataset.no.such.field";
106 public static final String EXCEPTION_MESSAGE_KEY_NO_SUCH_PARAMETER = "fill.dataset.no.such.parameter";
107 public static final String EXCEPTION_MESSAGE_KEY_NO_SUCH_SNAPSHOT_DATA = "fill.dataset.no.such.snapshot.data";
108 public static final String EXCEPTION_MESSAGE_KEY_NO_SUCH_SNAPSHOT_PARAMETER = "fill.dataset.no.such.snapshot.parameter";
109 public static final String EXCEPTION_MESSAGE_KEY_NO_SUCH_VARIABLE = "fill.dataset.no.such.variable";
110
111
114 private final BaseReportFiller filler;
115
116
119 private JasperReportsContext jasperReportsContext;
120
121 private JRPropertiesUtil propertiesUtil;
122
123
126 private final JRDataset parent;
127
128
131 private final boolean isMain;
132
133
136 protected JRQuery query;
137
138 private boolean useDatasourceParamValue;
139 private boolean useConnectionParamValue;
140
141
144 protected JRFillParameter[] parameters;
145
146
149 protected Map<String,JRFillParameter> parametersMap;
150
151
154 protected JRFillField[] fields;
155
156
159 protected Map<String,JRFillField> fieldsMap;
160
161
164 protected JRFillVariable[] variables;
165
166
169 protected Map<String,JRFillVariable> variablesMap;
170
171
174 protected Set<VariableCalculationReq> variableCalculationReqs;
175
176
179 protected JRFillElementDataset[] elementDatasets;
180
181
185 protected JRFillElementDataset[] origElementDatasets;
186
187
190 protected JRFillGroup[] groups;
191
192
195 protected String resourceBundleBaseName;
196
197
200 protected WhenResourceMissingTypeEnum whenResourceMissingType;
201
202
205 protected String scriptletClassName;
206
207
210 protected JRDataSource dataSource;
211
212
215 protected Locale locale;
216
217
220 protected ResourceBundle resourceBundle;
221
222
225 protected TimeZone timeZone;
226
227
230 protected int reportCount;
231
232
235 protected JRCalculator calculator;
236
237
240 protected List<JRAbstractScriptlet> scriptlets;
241
242 protected List<DatasetPropertyExpression> propertyExpressions;
243 protected JRPropertiesMap staticProperties;
244 protected JRPropertiesMap mergedProperties;
245
246
249 protected JRAbstractScriptlet delegateScriptlet = new JRFillDatasetScriptlet();
250
251
254 protected Integer reportMaxCount;
255
256 private JRQueryExecuter queryExecuter;
257 private List<ParameterContributor> parameterContributors;
258
259 protected DatasetFilter filter;
260
261 protected FillDatasetPosition fillPosition;
262 protected DatasetRecorder dataRecorder;
263
264 private Map<Integer, CacheRecordIndexCallback> cacheRecordIndexCallbacks;
265 private boolean cacheSkipped;
266 private CachedDataset cachedDataset;
267 private boolean sortedDataSource;
268
269 private boolean ended;
270 private int cacheRecordCount;
271 private int previousCacheRecordIndex;
272 private int currentCacheRecordIndex;
273
274
280 public JRFillDataset(BaseReportFiller filler, JRDataset dataset, JRFillObjectFactory factory)
281 {
282 factory.put(dataset, this);
283
284 this.filler = filler;
285 this.propertiesUtil = filler == null ? JRPropertiesUtil.getInstance(DefaultJasperReportsContext.getInstance())
286 : filler.getPropertiesUtil();
287 this.parent = dataset;
288 this.isMain = dataset.isMainDataset();
289
290 scriptletClassName = dataset.getScriptletClass();
291 resourceBundleBaseName = dataset.getResourceBundle();
292 whenResourceMissingType = dataset.getWhenResourceMissingTypeValue();
293
294 query = dataset.getQuery();
295
296 setParameters(dataset, factory);
297
298 setFields(dataset, factory);
299
300 setVariables(dataset, factory);
301
302 setGroups(dataset, factory);
303
304 staticProperties = dataset.hasProperties() ? dataset.getPropertiesMap().cloneProperties() : null;
305 mergedProperties = staticProperties;
306
307 DatasetPropertyExpression[] datasetPropertyExpressions = dataset.getPropertyExpressions();
308 propertyExpressions =
309 datasetPropertyExpressions == null
310 ? new ArrayList<DatasetPropertyExpression>(0)
311 : new ArrayList<DatasetPropertyExpression>(Arrays.asList(datasetPropertyExpressions));
312 }
313
314
315 public BaseReportFiller getFiller()
316 {
317 return filler;
318 }
319
320
321 private void setParameters(JRDataset dataset, JRFillObjectFactory factory)
322 {
323 JRParameter[] jrParameters = dataset.getParameters();
324 if (jrParameters != null && jrParameters.length > 0)
325 {
326 parameters = new JRFillParameter[jrParameters.length];
327 parametersMap = new HashMap<String,JRFillParameter>();
328 for (int i = 0; i < parameters.length; i++)
329 {
330 parameters[i] = factory.getParameter(jrParameters[i]);
331 parametersMap.put(parameters[i].getName(), parameters[i]);
332 }
333 }
334 }
335
336
337 private void setGroups(JRDataset dataset, JRFillObjectFactory factory)
338 {
339 JRGroup[] jrGroups = dataset.getGroups();
340 if (jrGroups != null && jrGroups.length > 0)
341 {
342 groups = new JRFillGroup[jrGroups.length];
343 for (int i = 0; i < groups.length; i++)
344 {
345 groups[i] = factory.getGroup(jrGroups[i]);
346 }
347 }
348 }
349
350
351 private void setVariables(JRDataset dataset, JRFillObjectFactory factory)
352 {
353 JRVariable[] jrVariables = dataset.getVariables();
354 if (jrVariables != null && jrVariables.length > 0)
355 {
356 List<JRFillVariable> variableList = new ArrayList<JRFillVariable>(jrVariables.length * 3);
357
358 variablesMap = new HashMap<String,JRFillVariable>();
359 for (int i = 0; i < jrVariables.length; i++)
360 {
361 addVariable(jrVariables[i], variableList, factory);
362 }
363
364 setVariables(variableList);
365 }
366 }
367
368
369 private JRFillVariable addVariable(JRVariable parentVariable, List<JRFillVariable> variableList, JRFillObjectFactory factory)
370 {
371 JRFillVariable variable = factory.getVariable(parentVariable);
372
373 CalculationEnum calculation = variable.getCalculationValue();
374 switch (calculation)
375 {
376 case AVERAGE:
377 case VARIANCE:
378 {
379 JRVariable countVar = createHelperVariable(parentVariable, "_COUNT", CalculationEnum.COUNT);
380 JRFillVariable fillCountVar = addVariable(countVar, variableList, factory);
381 variable.setHelperVariable(fillCountVar, JRCalculable.HELPER_COUNT);
382
383 JRVariable sumVar = createHelperVariable(parentVariable, "_SUM", CalculationEnum.SUM);
384 JRFillVariable fillSumVar = addVariable(sumVar, variableList, factory);
385 variable.setHelperVariable(fillSumVar, JRCalculable.HELPER_SUM);
386
387 break;
388 }
389 case STANDARD_DEVIATION:
390 {
391 JRVariable varianceVar = createHelperVariable(parentVariable, "_VARIANCE", CalculationEnum.VARIANCE);
392 JRFillVariable fillVarianceVar = addVariable(varianceVar, variableList, factory);
393 variable.setHelperVariable(fillVarianceVar, JRCalculable.HELPER_VARIANCE);
394
395 break;
396 }
397 case DISTINCT_COUNT:
398 {
399 JRVariable countVar = createDistinctCountHelperVariable(parentVariable);
400 JRFillVariable fillCountVar = addVariable(countVar, variableList, factory);
401 variable.setHelperVariable(fillCountVar, JRCalculable.HELPER_COUNT);
402
403 break;
404 }
405 }
406
407 variableList.add(variable);
408 return variable;
409 }
410
411 private JRVariable createHelperVariable(JRVariable variable, String nameSuffix, CalculationEnum calculation)
412 {
413 JRDesignVariable helper = new JRDesignVariable();
414 helper.setName(variable.getName() + nameSuffix);
415 helper.setValueClassName(variable.getValueClassName());
416 helper.setIncrementerFactoryClassName(variable.getIncrementerFactoryClassName());
417 helper.setResetType(variable.getResetTypeValue());
418 helper.setResetGroup(variable.getResetGroup());
419 helper.setIncrementType(variable.getIncrementTypeValue());
420 helper.setIncrementGroup(variable.getIncrementGroup());
421 helper.setCalculation(calculation);
422 helper.setSystemDefined(true);
423 helper.setExpression(variable.getExpression());
424
425 return helper;
426 }
427
428 private JRVariable createDistinctCountHelperVariable(JRVariable variable)
429 {
430 JRDesignVariable helper = new JRDesignVariable();
431 helper.setName(variable.getName() + "_DISTINCT_COUNT");
432 helper.setValueClassName(variable.getValueClassName());
433 helper.setIncrementerFactoryClassName(JRDistinctCountIncrementerFactory.class.getName());
434 helper.setResetType(ResetTypeEnum.REPORT);
435
436 if (variable.getIncrementTypeValue() != IncrementTypeEnum.NONE)
437 {
438 helper.setResetType(ResetTypeEnum.getByValue(variable.getIncrementTypeValue().getValue()));
439 }
440 helper.setResetGroup(variable.getIncrementGroup());
441 helper.setCalculation(CalculationEnum.NOTHING);
442 helper.setSystemDefined(true);
443 helper.setExpression(variable.getExpression());
444
445 return helper;
446 }
447
448 private void setVariables(List<JRFillVariable> variableList)
449 {
450 variables = new JRFillVariable[variableList.size()];
451 variables = variableList.toArray(variables);
452
453 for (int i = 0; i < variables.length; i++)
454 {
455 variablesMap.put(variables[i].getName(), variables[i]);
456 }
457 }
458
459
460 private void setFields(JRDataset dataset, JRFillObjectFactory factory)
461 {
462 JRField[] jrFields = dataset.getFields();
463 if (jrFields != null && jrFields.length > 0)
464 {
465 fields = new JRFillField[jrFields.length];
466 fieldsMap = new HashMap<String,JRFillField>();
467 for (int i = 0; i < fields.length; i++)
468 {
469 fields[i] = factory.getField(jrFields[i]);
470 fieldsMap.put(fields[i].getName(), fields[i]);
471 }
472 }
473 }
474
475
476
481 public void createCalculator(JasperReport jasperReport) throws JRException
482 {
483 setCalculator(createCalculator(getJasperReportsContext(), jasperReport, this));
484 }
485
486 protected void setCalculator(JRCalculator calculator)
487 {
488 this.calculator = calculator;
489 }
490
491 protected static JRCalculator createCalculator(JasperReportsContext jasperReportsContext, JasperReport jasperReport, JRDataset dataset) throws JRException
492 {
493 JREvaluator evaluator = JasperCompileManager.getInstance(jasperReportsContext).getEvaluator(jasperReport, dataset);
494 return new JRCalculator(evaluator);
495 }
496
497
498
503 public void initCalculator() throws JRException
504 {
505 calculator.init(this);
506 }
507
508
509
512 public void inheritFromMain()
513 {
514 if (resourceBundleBaseName == null && !isMain)
515 {
516 resourceBundleBaseName = filler.jasperReport.getResourceBundle();
517 whenResourceMissingType = filler.jasperReport.getWhenResourceMissingTypeValue();
518 }
519 }
520
521
522
528 protected List<JRAbstractScriptlet> createScriptlets(Map<String,Object> parameterValues) throws JRException
529 {
530 ScriptletFactoryContext context = new ScriptletFactoryContext(getJasperReportsContext(), this, parameterValues);
531
532 scriptlets = new ArrayList<JRAbstractScriptlet>();
533
534 List<ScriptletFactory> factories = getJasperReportsContext().getExtensions(ScriptletFactory.class);
535 for (Iterator<ScriptletFactory> it = factories.iterator(); it.hasNext();)
536 {
537 ScriptletFactory factory = it.next();
538 List<JRAbstractScriptlet> tmpScriptlets = factory.getScriplets(context);
539 if (tmpScriptlets != null)
540 {
541 scriptlets.addAll(tmpScriptlets);
542 }
543 }
544
545 if (scriptlets.size() == 0)
546 {
547 scriptlets.add(0, new JRDefaultScriptlet());
548 }
549
550 return scriptlets;
551 }
552
553
554
559 protected void initElementDatasets(JRFillObjectFactory factory)
560 {
561 elementDatasets = factory.getElementDatasets(this);
562 }
563
564
565
572 protected void filterElementDatasets(JRFillElementDataset elementDataset)
573 {
574 origElementDatasets = elementDatasets;
575 elementDatasets = new JRFillElementDataset[]{elementDataset};
576 }
577
578
579
584 protected void restoreElementDatasets()
585 {
586 if (origElementDatasets != null)
587 {
588 elementDatasets = origElementDatasets;
589 origElementDatasets = null;
590 }
591 }
592
593
594
597 protected ResourceBundle loadResourceBundle()
598 {
599 ResourceBundle loadedBundle;
600 if (resourceBundleBaseName == null)
601 {
602 loadedBundle = null;
603 }
604 else
605 {
606 loadedBundle = JRResourcesUtil.loadResourceBundle(getRepositoryContext(), resourceBundleBaseName, locale);
607 }
608 return loadedBundle;
609 }
610
611
612
618 public void setParameterValues(Map<String,Object> parameterValues) throws JRException
619 {
620 parameterValues.put(JRParameter.REPORT_PARAMETERS_MAP, parameterValues);
621
622 parameterValues.put(JRParameter.JASPER_REPORTS_CONTEXT, getJasperReportsContext());
623
624 if (filler != null)
625 {
626
627
628 parameterValues.put(JRParameter.JASPER_REPORT, filler.getJasperReport());
629 }
630
631 reportMaxCount = (Integer) parameterValues.get(JRParameter.REPORT_MAX_COUNT);
632
633 locale = (Locale) parameterValues.get(JRParameter.REPORT_LOCALE);
634 if (locale == null)
635 {
636 locale = defaultLocale();
637 parameterValues.put(JRParameter.REPORT_LOCALE, locale);
638 }
639
640 resourceBundle = (ResourceBundle) parameterValues.get(JRParameter.REPORT_RESOURCE_BUNDLE);
641 if (resourceBundle == null)
642 {
643 resourceBundle = loadResourceBundle();
644 if (resourceBundle != null)
645 {
646 parameterValues.put(JRParameter.REPORT_RESOURCE_BUNDLE, resourceBundle);
647 }
648 }
649
650 timeZone = (TimeZone) parameterValues.get(JRParameter.REPORT_TIME_ZONE);
651 if (timeZone == null)
652 {
653 timeZone = defaultTimeZone();
654 parameterValues.put(JRParameter.REPORT_TIME_ZONE, timeZone);
655 }
656
657 scriptlets = createScriptlets(parameterValues);
658 delegateScriptlet.setData(this);
659
660
661 cacheInit();
662
663 setFillParameterValuesFromMap(parameterValues, true);
664 setFillParameterValuesFromCache(parameterValues);
665 evaluateParameterValues(ParameterEvaluationTimeEnum.EARLY, parameterValues);
666
667 mergedProperties = staticProperties;
668 evaluateProperties(PropertyEvaluationTimeEnum.EARLY);
669
670
671 contributeParameters(parameterValues);
672
673 setFillParameterValuesFromMap(parameterValues, false);
674 evaluateParameterValues(ParameterEvaluationTimeEnum.LATE, parameterValues);
675
676 evaluateProperties(PropertyEvaluationTimeEnum.LATE);
677
678 filter = (DatasetFilter) parameterValues.get(JRParameter.FILTER);
679
680
681 cacheInitRecording();
682
683
684 if (filter != null)
685 {
686 filter.init(this);
687 }
688 }
689
690 protected Locale defaultLocale()
691 {
692 String localeCode = propertiesUtil.getProperty(this, JRFiller.PROPERTY_DEFAULT_LOCALE);
693 Locale locale = (localeCode == null || localeCode.isEmpty()) ? Locale.getDefault()
694 : JRDataUtils.getLocale(localeCode);
695 return locale;
696 }
697
698 protected TimeZone defaultTimeZone()
699 {
700 String timezoneId = propertiesUtil.getProperty(this, JRFiller.PROPERTY_DEFAULT_TIMEZONE);
701 TimeZone timezone = (timezoneId == null || timezoneId.isEmpty()) ? TimeZone.getDefault()
702 : JRDataUtils.getTimeZone(timezoneId);
703 return timezone;
704 }
705
706
707
716 public void initDatasource() throws JRException
717 {
718 queryExecuter = null;
719 dataSource = null;
720
721 if (cachedDataset != null)
722 {
723
724 dataSource = cachedDataset.getDataSource();
725 }
726
727 if (dataSource == null)
728 {
729 dataSource = (JRDataSource) getParameterValue(JRParameter.REPORT_DATA_SOURCE);
730 if (!useDatasourceParamValue && (useConnectionParamValue || dataSource == null))
731 {
732 dataSource = createQueryDatasource();
733 setParameter(JRParameter.REPORT_DATA_SOURCE, dataSource);
734 }
735 }
736
737 if (DatasetSortUtil.needSorting(this))
738 {
739 dataSource = DatasetSortUtil.getSortedDataSource(filler, this, locale);
740 setParameter(JRParameter.REPORT_DATA_SOURCE, dataSource);
741 sortedDataSource = true;
742 }
743 }
744
745 public FillDatasetPosition getFillPosition()
746 {
747 return fillPosition;
748 }
749
750 public void setFillPosition(FillDatasetPosition fillPosition)
751 {
752 if (fillPosition != null)
753 {
754
755 fillPosition.addAttribute("datasetUUID", getUUID());
756
757 if (query != null)
758 {
759 MD5Digest queryMD5 = DigestUtils.instance().md5(query.getText());
760 fillPosition.addAttribute("queryMD5", queryMD5);
761 }
762
763 }
764
765 this.fillPosition = fillPosition;
766 }
767
768
769 public void setCacheSkipped(boolean cacheSkipped)
770 {
771 this.cacheSkipped = cacheSkipped;
772
773 if (cacheSkipped && log.isDebugEnabled())
774 {
775 log.debug("data cache skipped at position " + fillPosition);
776 }
777 }
778
779 protected void cacheInit() throws DataSnapshotException
780 {
781
782 cachedDataset = null;
783 dataRecorder = null;
784
785 if (fillPosition == null)
786 {
787 log.debug("No fill position present, not using the data cache");
788 return;
789 }
790
791 if (filler != null)
792 {
793
794 cacheInitSnapshot();
795 }
796 }
797
798 protected void cacheInitSnapshot() throws DataSnapshotException
799 {
800 if (cacheSkipped)
801 {
802 return;
803 }
804
805 DataSnapshot dataSnapshot = filler.fillContext.getDataSnapshot();
806 if (dataSnapshot != null)
807 {
808
809 cachedDataset = dataSnapshot.getCachedData(fillPosition);
810 if (cachedDataset == null)
811 {
812 throw
813 new DataSnapshotException(
814 EXCEPTION_MESSAGE_KEY_NO_SUCH_SNAPSHOT_DATA,
815 new Object[]{fillPosition});
816 }
817
818 if (log.isDebugEnabled())
819 {
820 log.debug("Using cached data for " + fillPosition);
821 }
822 }
823 }
824
825 protected void cacheInitRecording()
826 {
827 if (cacheSkipped)
828 {
829 return;
830 }
831
832 if (cachedDataset != null)
833 {
834
835 return;
836 }
837
838 if (filler == null)
839 {
840
841 return;
842 }
843
844
845 DataRecorder cacheRecorder = filler.fillContext.getDataRecorder();
846 if (cacheRecorder != null && cacheRecorder.isEnabled())
847 {
848
849 boolean dataRecorable = JRPropertiesUtil.getInstance(getJasperReportsContext()).getBooleanProperty(
850 this, DataCacheHandler.PROPERTY_DATA_RECORDABLE, true);
851 if (dataRecorable)
852 {
853
854 boolean dataPersistable = JRPropertiesUtil.getInstance(getJasperReportsContext()).getBooleanProperty(
855 this, DataCacheHandler.PROPERTY_DATA_PERSISTABLE, true);
856 if (!dataPersistable)
857 {
858 if (log.isDebugEnabled())
859 {
860 log.debug("data not persistable by property for " + fillPosition);
861 }
862
863 cacheRecorder.disablePersistence();
864 }
865
866
867 dataRecorder = cacheRecorder.createRecorder();
868
869 dataRecorder.start(parent.getFields());
870
871 if (log.isDebugEnabled())
872 {
873 log.debug("Populating data cache for " + fillPosition);
874 }
875
876
877 for (JRFillParameter parameter : parameters)
878 {
879 if (parameter.hasProperties())
880 {
881 boolean includedInCache = isIncludedInDataCache(parameter);
882 if (includedInCache)
883 {
884 if (log.isDebugEnabled())
885 {
886 log.debug("storing value of paramter " + parameter.getName()
887 + " in data snapshot");
888 }
889
890 Object value = parameter.getValue();
891
892 dataRecorder.addParameter(parameter.getName(), value);
893 }
894 }
895 }
896
897 cacheRecordIndexCallbacks = new HashMap<Integer, CacheRecordIndexCallback>();
898 }
899 else
900 {
901 if (log.isDebugEnabled())
902 {
903 log.debug("data recording inhibited by property for " + fillPosition);
904 }
905
906
907 cacheRecorder.disableRecording();
908 }
909 }
910 }
911
912 protected boolean isIncludedInDataCache(JRFillParameter parameter)
913 {
914 String includedProp = JRPropertiesUtil.getOwnProperty(parameter, DataCacheHandler.PROPERTY_INCLUDED);
915 return JRPropertiesUtil.asBoolean(includedProp);
916 }
917
918 protected ParameterEvaluationTimeEnum getDefaultParameterEvaluationTime()
919 {
920 String evalTimeProp =
921 propertiesUtil.getProperty(
922 ParameterEvaluationTimeEnum.PROPERTY_EVALUATION_TIME,
923 this
924 );
925 return ParameterEvaluationTimeEnum.byName(evalTimeProp);
926 }
927
928 protected PropertyEvaluationTimeEnum getDefaultPropertyEvaluationTime()
929 {
930 String evalTimeProp =
931 propertiesUtil.getProperty(
932 PropertyEvaluationTimeEnum.PROPERTY_EVALUATION_TIME,
933 this
934 );
935 return PropertyEvaluationTimeEnum.byName(evalTimeProp);
936 }
937
938 protected void cacheRecord()
939 {
940 if (dataRecorder != null && !dataRecorder.hasEnded())
941 {
942 Object[] values;
943 if (fields == null)
944 {
945 values = new Object[0];
946 }
947 else
948 {
949 values = new Object[fields.length];
950 for (int i = 0; i < fields.length; i++)
951 {
952 values[i] = fields[i].getValue();
953 }
954 }
955
956 dataRecorder.addRecord(values);
957 }
958 }
959
960 protected void cacheEnd()
961 {
962 if (dataRecorder != null && !dataRecorder.hasEnded())
963 {
964
965 if (sortedDataSource)
966 {
967 if (log.isDebugEnabled())
968 {
969 log.debug("populating unsorted cache");
970 }
971
972 int recordIndex = 0;
973
974 List<SortedDataSource.SortRecord> sortRecords = ((SortedDataSource) dataSource).getRecords();
975 for (SortedDataSource.SortRecord sortRecord : sortRecords)
976 {
977 if (sortRecord.isFiltered())
978 {
979 Object[] recordValues = sortRecord.getValues();
980 Object[] fieldValues;
981
982 if (fields.length == recordValues.length)
983 {
984 fieldValues = recordValues;
985 }
986 else
987 {
988 fieldValues = new Object[fields.length];
989 System.arraycopy(recordValues, 0, fieldValues, 0, fields.length);
990 }
991
992
993 dataRecorder.addRecord(fieldValues);
994
995
996 ++recordIndex;
997 int originalIndex = sortRecord.getRecordIndex() + 1;
998
999 if (log.isDebugEnabled())
1000 {
1001 log.debug("unsorted index " + recordIndex + " for original index " + originalIndex);
1002 }
1003
1004
1005 CacheRecordIndexCallback recordIndexCallback = cacheRecordIndexCallbacks.get(originalIndex);
1006 if (recordIndexCallback != null)
1007 {
1008 recordIndexCallback.cacheRecordIndexAvailable(recordIndex);
1009 }
1010 }
1011 }
1012 }
1013
1014 Object recorded = dataRecorder.end();
1015 if (recorded != null)
1016 {
1017
1018 filler.fillContext.addDataRecordResult(fillPosition, recorded);
1019 }
1020 }
1021 }
1022
1023
1024
1030 private void evaluateParameterValues(ParameterEvaluationTimeEnum evaluationTime, Map<String,Object> parameterValues) throws JRException
1031 {
1032 if (parameters != null && parameters.length > 0)
1033 {
1034 ParameterEvaluationTimeEnum defaultEvaluationTime = getDefaultParameterEvaluationTime();
1035 for (int i = 0; i < parameters.length; i++)
1036 {
1037 JRFillParameter parameter = parameters[i];
1038 String paramName = parameter.getName();
1039 ParameterEvaluationTimeEnum paramEvalTime = parameter.getEvaluationTime() == null ? defaultEvaluationTime : parameter.getEvaluationTime();
1040
1041 if (
1042 !parameterValues.containsKey(paramName)
1043 && !parameter.isSystemDefined()
1044 && evaluationTime == paramEvalTime
1045 && (!isIncludedInDataCache(parameter) || cachedDataset == null)
1046 )
1047 {
1048 Object value = calculator.evaluate(parameter.getDefaultValueExpression(), JRExpression.EVALUATION_DEFAULT);
1049 if (value != null)
1050 {
1051 parameterValues.put(paramName, value);
1052 }
1053 setParameter(parameter, value);
1054 }
1055 }
1056 }
1057 }
1058
1059
1060
1063 private void setFillParameterValuesFromMap(Map<String,Object> parameterValues, boolean reset) throws JRException
1064 {
1065 if (parameters != null && parameters.length > 0)
1066 {
1067 for (int i = 0; i < parameters.length; i++)
1068 {
1069 JRFillParameter parameter = parameters[i];
1070 String paramName = parameter.getName();
1071
1072 Object value = null;
1073 if (parameterValues.containsKey(paramName))
1074 {
1075 value = parameterValues.get(paramName);
1076 setParameter(parameter, value);
1077 }
1078 else if (reset)
1079 {
1080 setParameter(parameter, null);
1081 }
1082 }
1083 }
1084 }
1085
1086
1087
1093 private void setFillParameterValuesFromCache(Map<String,Object> parameterValues) throws JRException
1094 {
1095 if (parameters != null && parameters.length > 0)
1096 {
1097 for (int i = 0; i < parameters.length; i++)
1098 {
1099 JRFillParameter parameter = parameters[i];
1100 String paramName = parameter.getName();
1101
1102 if (
1103 !parameterValues.containsKey(paramName)
1104 && !parameter.isSystemDefined()
1105 )
1106 {
1107 if (isIncludedInDataCache(parameter) && cachedDataset != null)
1108 {
1109
1110
1111 if (!cachedDataset.hasParameter(paramName))
1112 {
1113
1114 throw
1115 new DataSnapshotException(
1116 EXCEPTION_MESSAGE_KEY_NO_SUCH_SNAPSHOT_PARAMETER,
1117 new Object[]{paramName});
1118 }
1119
1120 if (log.isDebugEnabled())
1121 {
1122 log.debug("loading parameter " + paramName + " value from data snapshot");
1123 }
1124
1125 Object value = cachedDataset.getParameterValue(paramName);
1126 setParameter(parameter, value);
1127 }
1128 }
1129 }
1130 }
1131 }
1132
1133
1134
1137 public void evaluateFieldProperties() throws JRException
1138 {
1139 if (fields != null && fields.length > 0)
1140 {
1141 for (JRFillField field : fields)
1142 {
1143 field.evaluateProperties();
1144 }
1145 }
1146 }
1147
1148
1149
1152 public void contributeParameters(Map<String,Object> parameterValues) throws JRException
1153 {
1154 parameterContributors = getParameterContributors(new ParameterContributorContext(getRepositoryContext(), this, parameterValues));
1155 if (parameterContributors != null)
1156 {
1157 for(ParameterContributor contributor : parameterContributors)
1158 {
1159 contributor.contributeParameters(parameterValues);
1160 }
1161 }
1162 }
1163
1164 public void setJasperReportsContext(JasperReportsContext jasperReportsContext)
1165 {
1166 this.jasperReportsContext = jasperReportsContext;
1167 if (jasperReportsContext != null)
1168 {
1169 this.propertiesUtil = JRPropertiesUtil.getInstance(jasperReportsContext);
1170 }
1171 }
1172
1173 protected JasperReportsContext getJasperReportsContext()
1174 {
1175 return filler == null
1176 ? (jasperReportsContext == null ? DefaultJasperReportsContext.getInstance() : jasperReportsContext)
1177 : filler.getJasperReportsContext();
1178 }
1179
1180 protected RepositoryContext getRepositoryContext()
1181 {
1182 return filler == null
1183 ? SimpleRepositoryContext.of(jasperReportsContext == null ? DefaultJasperReportsContext.getInstance() : jasperReportsContext)
1184 : filler.getRepositoryContext();
1185 }
1186
1187
1190 public void disposeParameterContributors()
1191 {
1192 if (parameterContributors != null)
1193 {
1194 for(ParameterContributor contributor : parameterContributors)
1195 {
1196 contributor.dispose();
1197 }
1198 }
1199 }
1200
1201
1202
1205 private List<ParameterContributor> getParameterContributors(ParameterContributorContext context) throws JRException
1206 {
1207 List<ParameterContributor> allContributors = null;
1208 List<?> factories = getJasperReportsContext().getExtensions(ParameterContributorFactory.class);
1209 if (factories != null && factories.size() > 0)
1210 {
1211 allContributors = new ArrayList<ParameterContributor>();
1212 for (Iterator<?> it = factories.iterator(); it.hasNext();)
1213 {
1214 ParameterContributorFactory factory = (ParameterContributorFactory)it.next();
1215 List<ParameterContributor> contributors = factory.getContributors(context);
1216 if (contributors != null)
1217 {
1218 allContributors.addAll(contributors);
1219 }
1220 }
1221 }
1222 return allContributors;
1223 }
1224
1225
1226
1231 protected Map<String,Object> getParameterValuesMap()
1232 {
1233 JRFillParameter paramValuesParameter = parametersMap.get(JRParameter.REPORT_PARAMETERS_MAP);
1234 return (Map<String,Object>) paramValuesParameter.getValue();
1235 }
1236
1237
1243 private JRDataSource createQueryDatasource() throws JRException
1244 {
1245 if (query == null)
1246 {
1247 return null;
1248 }
1249
1250 try
1251 {
1252 if (log.isDebugEnabled())
1253 {
1254 log.debug("Fill " + filler.fillerId + ": Creating " + query.getLanguage() + " query executer");
1255 }
1256
1257 QueryExecuterFactory queryExecuterFactory = JRQueryExecuterUtils.getInstance(getJasperReportsContext()).getExecuterFactory(query.getLanguage());
1258 SimpleQueryExecutionContext queryExecutionContext = SimpleQueryExecutionContext.of(
1259 getJasperReportsContext(), getRepositoryContext());
1260 queryExecuter = queryExecuterFactory.createQueryExecuter(queryExecutionContext, this, parametersMap);
1261 filler.fillContext.setRunningQueryExecuter(queryExecuter);
1262
1263 return queryExecuter.createDatasource();
1264 }
1265 finally
1266 {
1267 filler.fillContext.clearRunningQueryExecuter();
1268 }
1269 }
1270
1271
1272 protected void reset()
1273 {
1274 useDatasourceParamValue = false;
1275 useConnectionParamValue = false;
1276 }
1277
1278
1279
1285 public void setDatasourceParameterValue(Map<String,Object> parameterValues, JRDataSource ds)
1286 {
1287 useDatasourceParamValue = true;
1288
1289 if (ds != null)
1290 {
1291 parameterValues.put(JRParameter.REPORT_DATA_SOURCE, ds);
1292 }
1293 }
1294
1295
1296
1302 public void setConnectionParameterValue(Map<String,Object> parameterValues, Connection conn)
1303 {
1304 useConnectionParamValue = true;
1305
1306 if (conn != null)
1307 {
1308 parameterValues.put(JRParameter.REPORT_CONNECTION, conn);
1309 }
1310 }
1311
1312
1313
1319 public void closeDatasource()
1320 {
1321 closeQueryExecuter();
1322 reset();
1323
1324 if (ended)
1325 {
1326
1327 cacheEnd();
1328 }
1329 }
1330
1331 protected void closeQueryExecuter()
1332 {
1333 if (queryExecuter != null)
1334 {
1335 if (log.isDebugEnabled())
1336 {
1337 log.debug("Fill " + filler.fillerId + ": closing query executer");
1338 }
1339
1340 queryExecuter.close();
1341 queryExecuter = null;
1342 }
1343 }
1344
1345
1346
1349 public void start()
1350 {
1351
1352
1353 resetVariables();
1354
1355 reportCount = 0;
1356 ended = false;
1357
1358 cacheRecordCount = 0;
1359 previousCacheRecordIndex = 0;
1360 currentCacheRecordIndex = 0;
1361 }
1362
1363
1364 protected void resetVariables()
1365 {
1366 if (variables != null)
1367 {
1368 for (JRFillVariable variable : variables)
1369 {
1370 variable.reset();
1371 }
1372 }
1373 }
1374
1375
1376
1382 public boolean next() throws JRException
1383 {
1384 return next(false);
1385 }
1386
1387
1388
1395 protected boolean next(boolean sorting) throws JRException
1396 {
1397 boolean hasNext = false;
1398
1399 if (dataSource != null)
1400 {
1401 boolean includeRow = true;
1402 do
1403 {
1404
1405 hasNext = advanceDataSource(!sorting);
1406 if (hasNext)
1407 {
1408 setOldValues();
1409
1410 calculator.estimateVariables();
1411
1412
1413 if (!sorting)
1414 {
1415 includeRow = true;
1416
1417
1418 JRExpression filterExpression = getFilterExpression();
1419 if (filterExpression != null)
1420 {
1421 Boolean filterExprResult = (Boolean) calculator.evaluate(
1422 filterExpression, JRExpression.EVALUATION_ESTIMATED);
1423 includeRow = filterExprResult != null && filterExprResult;
1424 }
1425
1426 if (includeRow)
1427 {
1428 advanceCacheRecordIndexes();
1429
1430 if (sortedDataSource)
1431 {
1432
1433
1434 ((SortedDataSource) dataSource).setRecordFilteredIndex(cacheRecordCount - 1);
1435 }
1436 else
1437 {
1438
1439
1440
1441 cacheRecord();
1442 }
1443
1444 if (filter != null)
1445 {
1446 includeRow = filter.matches(EvaluationType.ESTIMATED);
1447 if (log.isDebugEnabled())
1448 {
1449 log.debug("Record matched by filter: " + includeRow);
1450 }
1451 }
1452 }
1453 }
1454
1455 if (!includeRow)
1456 {
1457 revertToOldValues();
1458 }
1459 }
1460 }
1461 while(hasNext && !includeRow);
1462
1463 if (hasNext)
1464 {
1465 ++reportCount;
1466 }
1467 }
1468
1469 if (!hasNext)
1470 {
1471 ended = true;
1472 }
1473
1474 return hasNext;
1475 }
1476
1477 protected void advanceCacheRecordIndexes()
1478 {
1479 ++cacheRecordCount;
1480 previousCacheRecordIndex = currentCacheRecordIndex;
1481
1482
1483
1484 if (cachedDataset != null)
1485 {
1486
1487 int dataSourceIndex = ((IndexedDataSource) dataSource).getRecordIndex();
1488
1489 currentCacheRecordIndex = dataSourceIndex + 1;
1490 }
1491 else
1492 {
1493 currentCacheRecordIndex = cacheRecordCount;
1494 }
1495 }
1496
1497
1498 protected void setOldValues() throws JRException
1499 {
1500 if (fields != null && fields.length > 0)
1501 {
1502 for (int i = 0; i < fields.length; i++)
1503 {
1504 JRFillField field = fields[i];
1505 field.setPreviousOldValue(field.getOldValue());
1506 field.setOldValue(field.getValue());
1507 field.setValue(dataSource.getFieldValue(field));
1508 }
1509 }
1510
1511 if (variables != null && variables.length > 0)
1512 {
1513 for (int i = 0; i < variables.length; i++)
1514 {
1515 JRFillVariable variable = variables[i];
1516 variable.setPreviousOldValue(variable.getOldValue());
1517 variable.setOldValue(variable.getValue());
1518 }
1519 }
1520 }
1521
1522
1523 protected void revertToOldValues()
1524 {
1525 if (fields != null && fields.length > 0)
1526 {
1527 for (int i = 0; i < fields.length; i++)
1528 {
1529 JRFillField field = fields[i];
1530 field.setValue(field.getOldValue());
1531 field.setOldValue(field.getPreviousOldValue());
1532 }
1533 }
1534
1535 revertVariablesToOldValues();
1536 }
1537
1538
1539 protected void revertVariablesToOldValues()
1540 {
1541 if (variables != null && variables.length > 0)
1542 {
1543 for (int i = 0; i < variables.length; i++)
1544 {
1545 JRFillVariable variable = variables[i];
1546 variable.setValue(variable.getOldValue());
1547 variable.setOldValue(variable.getPreviousOldValue());
1548 }
1549 }
1550 }
1551
1552
1553 protected boolean advanceDataSource(boolean limit) throws JRException
1554 {
1555 boolean hasNext;
1556 if (limit && reportMaxCount != null && reportCount >= reportMaxCount)
1557 {
1558 hasNext = false;
1559 }
1560 else
1561 {
1562 hasNext = dataSource.next();
1563 }
1564 return hasNext;
1565 }
1566
1567
1574 protected void setParameter(String parameterName, Object value) throws JRException
1575 {
1576 JRFillParameter parameter = parametersMap.get(parameterName);
1577 if (parameter != null)
1578 {
1579 setParameter(parameter, value);
1580 }
1581 }
1582
1583
1584
1591 protected void setParameter(JRFillParameter parameter, Object value) throws JRException
1592 {
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612 parameter.setValue(value);
1613
1614 }
1615
1616 public JRFillVariable getVariable(String variableName)
1617 {
1618 return variablesMap.get(variableName);
1619 }
1620
1621
1627 public Object getVariableValue(String variableName)
1628 {
1629 return getVariableValue(variableName, EvaluationType.DEFAULT);
1630 }
1631
1632 @Override
1633 public Object getVariableValue(String variableName, EvaluationType evaluation)
1634 {
1635 JRFillVariable var = variablesMap.get(variableName);
1636 if (var == null)
1637 {
1638 throw
1639 new JRRuntimeException(
1640 EXCEPTION_MESSAGE_KEY_NO_SUCH_VARIABLE,
1641 new Object[]{variableName}
1642 );
1643 }
1644 return var.getValue(evaluation.getType());
1645 }
1646
1647 public JRFillVariable getFillVariable(String variableName)
1648 {
1649 return variablesMap.get(variableName);
1650 }
1651
1652
1658 @Override
1659 public Object getParameterValue(String parameterName)
1660 {
1661 return getParameterValue(parameterName, false);
1662 }
1663
1664
1665
1672 public Object getParameterValue(String parameterName, boolean ignoreMissing)
1673 {
1674 JRFillParameter param = parametersMap.get(parameterName);
1675 Object value;
1676 if (param == null)
1677 {
1678 if (!ignoreMissing)
1679 {
1680 throw
1681 new JRRuntimeException(
1682 EXCEPTION_MESSAGE_KEY_NO_SUCH_PARAMETER,
1683 new Object[]{parameterName}
1684 );
1685 }
1686
1687
1688 Map<String, Object> valuesMap = getParameterValuesMap();
1689 value = valuesMap == null ? null : valuesMap.get(parameterName);
1690 }
1691 else
1692 {
1693 value = param.getValue();
1694 }
1695 return value;
1696 }
1697
1698
1699
1705 public Object getFieldValue(String fieldName)
1706 {
1707 return getFieldValue(fieldName, EvaluationType.DEFAULT);
1708 }
1709
1710 @Override
1711 public Object getFieldValue(String fieldName, EvaluationType evaluation)
1712 {
1713 JRFillField field = fieldsMap.get(fieldName);
1714 if (field == null)
1715 {
1716 throw
1717 new JRRuntimeException(
1718 EXCEPTION_MESSAGE_KEY_NO_SUCH_FIELD,
1719 new Object[]{fieldName}
1720 );
1721 }
1722 return field.getValue(evaluation.getType());
1723 }
1724
1725 public JRFillField getFillField(String fieldName)
1726 {
1727 return fieldsMap.get(fieldName);
1728 }
1729
1730
1733 protected static class VariableCalculationReq
1734 {
1735 String variableName;
1736
1737 CalculationEnum calculation;
1738
1739 VariableCalculationReq(String variableName, CalculationEnum calculation)
1740 {
1741 this.variableName = variableName;
1742 this.calculation = calculation;
1743 }
1744
1745 @Override
1746 public boolean equals(Object o)
1747 {
1748 if (o == null || !(o instanceof VariableCalculationReq))
1749 {
1750 return false;
1751 }
1752
1753 VariableCalculationReq r = (VariableCalculationReq) o;
1754
1755 return variableName.equals(r.variableName) && calculation == r.calculation;
1756 }
1757
1758 @Override
1759 public int hashCode()
1760 {
1761 return 31 * calculation.ordinal() + variableName.hashCode();
1762 }
1763 }
1764
1765
1766
1772 protected void addVariableCalculationReq(String variableName, CalculationEnum calculation)
1773 {
1774 if (variableCalculationReqs == null)
1775 {
1776 variableCalculationReqs = new HashSet<VariableCalculationReq>();
1777 }
1778
1779 variableCalculationReqs.add(new VariableCalculationReq(variableName, calculation));
1780 }
1781
1782
1783
1788 protected void checkVariableCalculationReqs(JRFillObjectFactory factory)
1789 {
1790 if (variableCalculationReqs != null && !variableCalculationReqs.isEmpty())
1791 {
1792 List<JRFillVariable> variableList = new ArrayList<JRFillVariable>(variables.length * 2);
1793
1794 for (int i = 0; i < variables.length; i++)
1795 {
1796 JRFillVariable variable = variables[i];
1797 checkVariableCalculationReq(variable, variableList, factory);
1798 }
1799
1800 setVariables(variableList);
1801 }
1802 }
1803
1804
1805 private void checkVariableCalculationReq(JRFillVariable variable, List<JRFillVariable> variableList, JRFillObjectFactory factory)
1806 {
1807 JRVariable parentVariable = variable.getParent();
1808
1809 if (hasVariableCalculationReq(variable, CalculationEnum.AVERAGE) || hasVariableCalculationReq(variable, CalculationEnum.VARIANCE))
1810 {
1811 if (variable.getHelperVariable(JRCalculable.HELPER_COUNT) == null)
1812 {
1813 JRVariable countVar = createHelperVariable(parentVariable, "_COUNT", CalculationEnum.COUNT);
1814 JRFillVariable fillCountVar = factory.getVariable(countVar);
1815 checkVariableCalculationReq(fillCountVar, variableList, factory);
1816 variable.setHelperVariable(fillCountVar, JRCalculable.HELPER_COUNT);
1817 }
1818
1819 if (variable.getHelperVariable(JRCalculable.HELPER_SUM) == null)
1820 {
1821 JRVariable sumVar = createHelperVariable(parentVariable, "_SUM", CalculationEnum.SUM);
1822 JRFillVariable fillSumVar = factory.getVariable(sumVar);
1823 checkVariableCalculationReq(fillSumVar, variableList, factory);
1824 variable.setHelperVariable(fillSumVar, JRCalculable.HELPER_SUM);
1825 }
1826 }
1827
1828 if (hasVariableCalculationReq(variable, CalculationEnum.STANDARD_DEVIATION))
1829 {
1830 if (variable.getHelperVariable(JRCalculable.HELPER_VARIANCE) == null)
1831 {
1832 JRVariable varianceVar = createHelperVariable(parentVariable, "_VARIANCE", CalculationEnum.VARIANCE);
1833 JRFillVariable fillVarianceVar = factory.getVariable(varianceVar);
1834 checkVariableCalculationReq(fillVarianceVar, variableList, factory);
1835 variable.setHelperVariable(fillVarianceVar, JRCalculable.HELPER_VARIANCE);
1836 }
1837 }
1838
1839 if (hasVariableCalculationReq(variable, CalculationEnum.DISTINCT_COUNT))
1840 {
1841 if (variable.getHelperVariable(JRCalculable.HELPER_COUNT) == null)
1842 {
1843 JRVariable countVar = createDistinctCountHelperVariable(parentVariable);
1844 JRFillVariable fillCountVar = factory.getVariable(countVar);
1845 checkVariableCalculationReq(fillCountVar, variableList, factory);
1846 variable.setHelperVariable(fillCountVar, JRCalculable.HELPER_COUNT);
1847 }
1848 }
1849
1850 variableList.add(variable);
1851 }
1852
1853
1854 private boolean hasVariableCalculationReq(JRVariable var, CalculationEnum calculation)
1855 {
1856 return variableCalculationReqs.contains(new VariableCalculationReq(var.getName(), calculation));
1857 }
1858
1859 @Override
1860 public UUID getUUID()
1861 {
1862 return parent.getUUID();
1863 }
1864
1865 @Override
1866 public String getName()
1867 {
1868 return parent.getName();
1869 }
1870
1871 @Override
1872 public String getScriptletClass()
1873 {
1874 return parent.getScriptletClass();
1875 }
1876
1877 @Override
1878 public JRScriptlet[] getScriptlets()
1879 {
1880 return parent.getScriptlets();
1881 }
1882
1883 @Override
1884 public JRParameter[] getParameters()
1885 {
1886 return parameters;
1887 }
1888
1889 public Map<String,JRFillParameter> getParametersMap()
1890 {
1891 return parametersMap;
1892 }
1893
1894 @Override
1895 public JRQuery getQuery()
1896 {
1897 return query;
1898 }
1899
1900 @Override
1901 public JRField[] getFields()
1902 {
1903 return fields;
1904 }
1905
1906 public Map<String,JRFillField> getFieldsMap()
1907 {
1908 return fieldsMap;
1909 }
1910
1911 @Override
1912 public JRSortField[] getSortFields()
1913 {
1914 return parent.getSortFields();
1915 }
1916
1917 @Override
1918 public JRVariable[] getVariables()
1919 {
1920 return variables;
1921 }
1922
1923 public Map<String,JRFillVariable> getVariablesMap()
1924 {
1925 return variablesMap;
1926 }
1927
1928 @Override
1929 public JRGroup[] getGroups()
1930 {
1931 return groups;
1932 }
1933
1934 @Override
1935 public boolean isMainDataset()
1936 {
1937 return isMain;
1938 }
1939
1940 @Override
1941 public String getResourceBundle()
1942 {
1943 return parent.getResourceBundle();
1944 }
1945
1946
1947 @Override
1948 public WhenResourceMissingTypeEnum getWhenResourceMissingTypeValue()
1949 {
1950 return whenResourceMissingType;
1951 }
1952
1953
1954 @Override
1955 public void setWhenResourceMissingType(WhenResourceMissingTypeEnum whenResourceMissingType)
1956 {
1957 this.whenResourceMissingType = whenResourceMissingType;
1958 }
1959
1960
1961 @Override
1962 public boolean hasProperties()
1963 {
1964 return mergedProperties != null && mergedProperties.hasProperties();
1965 }
1966
1967
1968 @Override
1969 public JRPropertiesMap getPropertiesMap()
1970 {
1971 return mergedProperties;
1972 }
1973
1974
1975 @Override
1976 public JRPropertiesHolder getParentProperties()
1977 {
1978
1979 return
1980 isMain
1981 ? (filler == null || filler.parent == null ? null : filler.parent.getParentProperties())
1982 : filler.getMainDataset();
1983 }
1984
1985
1986 @Override
1987 public DatasetPropertyExpression[] getPropertyExpressions()
1988 {
1989 return propertyExpressions.toArray(new DatasetPropertyExpression[propertyExpressions.size()]);
1990 }
1991
1992
1993
1996 protected void evaluateProperties(PropertyEvaluationTimeEnum evaluationTime) throws JRException
1997 {
1998 if (!propertyExpressions.isEmpty())
1999 {
2000 JRPropertiesMap dynamicProperties = new JRPropertiesMap();
2001
2002 PropertyEvaluationTimeEnum defaultEvaluationTime = getDefaultPropertyEvaluationTime();
2003 for (DatasetPropertyExpression prop : propertyExpressions)
2004 {
2005 PropertyEvaluationTimeEnum propEvalTime = prop.getEvaluationTime() == null ? defaultEvaluationTime : prop.getEvaluationTime();
2006 if (evaluationTime == propEvalTime)
2007 {
2008 String value = (String) evaluateExpression(prop.getValueExpression(), JRExpression.EVALUATION_DEFAULT);
2009
2010 {
2011 dynamicProperties.setProperty(prop.getName(), value);
2012 }
2013 }
2014 }
2015
2016 JRPropertiesMap newMergedProperties = dynamicProperties.cloneProperties();
2017 newMergedProperties.setBaseProperties(mergedProperties);
2018 mergedProperties = newMergedProperties;
2019 }
2020 }
2021
2022
2023 @Override
2024 public JRExpression getFilterExpression()
2025 {
2026 return parent.getFilterExpression();
2027 }
2028
2029 @Override
2030 public Object clone()
2031 {
2032 throw new UnsupportedOperationException();
2033 }
2034
2035
2042 public Object evaluateExpression(JRExpression expression, byte evaluation) throws JRException
2043 {
2044 return calculator.evaluate(expression, evaluation);
2045 }
2046
2047 @Override
2048 public Locale getLocale()
2049 {
2050 return locale;
2051 }
2052
2053 public TimeZone getTimeZone()
2054 {
2055 return timeZone;
2056 }
2057
2058 public FillDatasetPosition getDatasetPosition()
2059 {
2060 return fillPosition;
2061 }
2062
2063 protected static interface CacheRecordIndexCallback
2064 {
2065 void cacheRecordIndexAvailable(int recordIndex);
2066 }
2067
2068 protected static class FillDatasetPositionRecordIndexCallback implements CacheRecordIndexCallback
2069 {
2070 protected static void setRecordIndex(FillDatasetPosition position, int recordIndex)
2071 {
2072 position.addAttribute("rowIndex", recordIndex);
2073 }
2074
2075 private final FillDatasetPosition position;
2076
2077 public FillDatasetPositionRecordIndexCallback(FillDatasetPosition position)
2078 {
2079 this.position = position;
2080 }
2081
2082 @Override
2083 public void cacheRecordIndexAvailable(int recordIndex)
2084 {
2085 setRecordIndex(position, recordIndex);
2086 }
2087 }
2088
2089 protected static class CacheRecordIndexChainedCallback implements CacheRecordIndexCallback
2090 {
2091 private final CacheRecordIndexCallback first;
2092 private final CacheRecordIndexCallback second;
2093
2094 public CacheRecordIndexChainedCallback(CacheRecordIndexCallback first,
2095 CacheRecordIndexCallback second)
2096 {
2097 this.first = first;
2098 this.second = second;
2099 }
2100
2101 @Override
2102 public void cacheRecordIndexAvailable(int recordIndex)
2103 {
2104 first.cacheRecordIndexAvailable(recordIndex);
2105 second.cacheRecordIndexAvailable(recordIndex);
2106 }
2107 }
2108
2109 protected void addCacheRecordIndexCallback(int recordIndex, CacheRecordIndexCallback callback)
2110 {
2111 CacheRecordIndexCallback existingCallback = cacheRecordIndexCallbacks.get(recordIndex);
2112 if (existingCallback == null)
2113 {
2114 cacheRecordIndexCallbacks.put(recordIndex, callback);
2115 }
2116 else
2117 {
2118 CacheRecordIndexChainedCallback chainedCallback = new CacheRecordIndexChainedCallback(
2119 existingCallback, callback);
2120 cacheRecordIndexCallbacks.put(recordIndex, chainedCallback);
2121 }
2122 }
2123
2124 public void setCacheRecordIndex(FillDatasetPosition position, byte evaluationType)
2125 {
2126 int recordIndex;
2127 switch (evaluationType)
2128 {
2129 case JRExpression.EVALUATION_OLD:
2130 recordIndex = previousCacheRecordIndex;
2131 break;
2132 default:
2133 recordIndex = currentCacheRecordIndex;
2134 break;
2135 }
2136
2137 if (sortedDataSource && dataRecorder != null)
2138 {
2139
2140
2141 FillDatasetPositionRecordIndexCallback callback = new FillDatasetPositionRecordIndexCallback(position);
2142 addCacheRecordIndexCallback(recordIndex, callback);
2143
2144 if (log.isDebugEnabled())
2145 {
2146 log.debug("registered cache callback for index " + recordIndex);
2147 }
2148 }
2149 else
2150 {
2151 FillDatasetPositionRecordIndexCallback.setRecordIndex(position, recordIndex);
2152 }
2153 }
2154 }
2155