1
24 package net.sf.jasperreports.engine.fill;
25
26 import java.io.File;
27 import java.io.InputStream;
28 import java.net.URL;
29 import java.sql.Connection;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37
38 import org.apache.commons.javaflow.api.continuable;
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41
42 import net.sf.jasperreports.annotations.properties.Property;
43 import net.sf.jasperreports.annotations.properties.PropertyScope;
44 import net.sf.jasperreports.data.cache.DataCacheHandler;
45 import net.sf.jasperreports.engine.CommonReturnValue;
46 import net.sf.jasperreports.engine.JRDataSource;
47 import net.sf.jasperreports.engine.JRDatasetParameter;
48 import net.sf.jasperreports.engine.JRException;
49 import net.sf.jasperreports.engine.JRExpression;
50 import net.sf.jasperreports.engine.JRExpressionCollector;
51 import net.sf.jasperreports.engine.JRParameter;
52 import net.sf.jasperreports.engine.JRPrintElement;
53 import net.sf.jasperreports.engine.JRPrintPage;
54 import net.sf.jasperreports.engine.JRPrintRectangle;
55 import net.sf.jasperreports.engine.JRPropertiesUtil;
56 import net.sf.jasperreports.engine.JRRewindableDataSource;
57 import net.sf.jasperreports.engine.JRRuntimeException;
58 import net.sf.jasperreports.engine.JRScriptlet;
59 import net.sf.jasperreports.engine.JRStyle;
60 import net.sf.jasperreports.engine.JRSubreport;
61 import net.sf.jasperreports.engine.JRSubreportParameter;
62 import net.sf.jasperreports.engine.JRSubreportReturnValue;
63 import net.sf.jasperreports.engine.JRVariable;
64 import net.sf.jasperreports.engine.JRVisitor;
65 import net.sf.jasperreports.engine.JasperCompileManager;
66 import net.sf.jasperreports.engine.JasperReport;
67 import net.sf.jasperreports.engine.ReportContext;
68 import net.sf.jasperreports.engine.VariableReturnValue;
69 import net.sf.jasperreports.engine.base.JRVirtualPrintPage;
70 import net.sf.jasperreports.engine.design.JRValidationException;
71 import net.sf.jasperreports.engine.design.JRValidationFault;
72 import net.sf.jasperreports.engine.design.JRVerifier;
73 import net.sf.jasperreports.engine.type.ModeEnum;
74 import net.sf.jasperreports.engine.type.OverflowType;
75 import net.sf.jasperreports.engine.type.SectionTypeEnum;
76 import net.sf.jasperreports.engine.util.JRLoader;
77 import net.sf.jasperreports.engine.util.JRSingletonCache;
78 import net.sf.jasperreports.properties.PropertyConstants;
79 import net.sf.jasperreports.repo.RepositoryResourceContext;
80 import net.sf.jasperreports.repo.RepositoryUtil;
81 import net.sf.jasperreports.repo.ResourceInfo;
82 import net.sf.jasperreports.repo.ResourcePathKey;
83 import net.sf.jasperreports.repo.SimpleRepositoryResourceContext;
84
85
86
89 public class JRFillSubreport extends JRFillElement implements JRSubreport
90 {
91
92 private static final Log log = LogFactory.getLog(JRFillSubreport.class);
93
94 public static final String EXCEPTION_MESSAGE_KEY_PROPERTY_NOT_SET = "fill.subreport.property.not.set";
95 public static final String EXCEPTION_MESSAGE_KEY_NO_REWINDABLE_DATA_SOURCE = "fill.subreport.no.rewindable.data.source";
96 public static final String EXCEPTION_MESSAGE_KEY_UNSUPPORTED_SECTION_TYPE = "fill.subreport.unsupported.section.type";
97 public static final String EXCEPTION_MESSAGE_KEY_UNKNOWN_SOURCE_CLASS = "fill.subreport.unknown.source.class";
98
99
104 @Property(
105 category = PropertyConstants.CATEGORY_FILL,
106 scopes = {PropertyScope.CONTEXT, PropertyScope.DATASET, PropertyScope.ELEMENT},
107 sinceVersion = PropertyConstants.VERSION_6_0_3
108 )
109 public static final String PROPERTY_SUBREPORT_GENERATE_RECTANGLE =
110 JRPropertiesUtil.PROPERTY_PREFIX + "subreport.generate.rectangle";
111
112 public static final String SUBREPORT_GENERATE_RECTANGLE_ALWAYS = "always";
113
114 private static final JRSingletonCache<JRSubreportRunnerFactory> runnerFactoryCache =
115 new JRSingletonCache<JRSubreportRunnerFactory>(JRSubreportRunnerFactory.class);
116
117
120 private Map<String, Object> parameterValues;
121 private JRSubreportParameter[] parameters;
122 private FillDatasetPosition datasetPosition;
123 private boolean cacheIncluded;
124 private Connection connection;
125 private JRDataSource dataSource;
126 private JasperReportSource jasperReportSource;
127 private Object source;
128
129 private Map<JasperReport,JREvaluator> loadedEvaluators;
130
131
134 private FillReturnValues returnValues;
135
136 private FillReturnValues.SourceContext returnValuesContext = new AbstractVariableReturnValueSourceContext()
137 {
138 @Override
139 public Object getValue(CommonReturnValue returnValue) {
140 return subreportFiller.getVariableValue(((VariableReturnValue)returnValue).getFromVariable());
141 }
142
143 @Override
144 public JRFillVariable getToVariable(String name) {
145 return expressionEvaluator.getFillDataset().getVariable(name);
146 }
147
148 @Override
149 public JRVariable getFromVariable(String name) {
150 return subreportFiller.getVariable(name);
151 }
152 };
153
154
157 protected JRBaseFiller subreportFiller;
158 protected FillerSubreportParent subFillerParent;
159 protected JRPrintPage printPage;
160 private int printPageContentsWidth;
161
162 private JRSubreportRunner runner;
163
164
167 private Set<JasperReport> checkedReports;
168
169 private final String defaultGenerateRectangle;
170 private final boolean dynamicGenerateRectangle;
171
172
173
176 protected JRFillSubreport(
177 JRBaseFiller filler,
178 JRSubreport subreport,
179 JRFillObjectFactory factory
180 )
181 {
182 super(filler, subreport, factory);
183
184 parameters = subreport.getParameters();
185 returnValues = new FillReturnValues(subreport.getReturnValues(), factory, filler);
186
187 loadedEvaluators = new HashMap<JasperReport,JREvaluator>();
188 checkedReports = new HashSet<JasperReport>();
189
190 this.defaultGenerateRectangle = filler.getPropertiesUtil().getProperty(
191 PROPERTY_SUBREPORT_GENERATE_RECTANGLE, subreport, filler.getJasperReport());
192
193 this.dynamicGenerateRectangle = hasDynamicProperty(PROPERTY_SUBREPORT_GENERATE_RECTANGLE);
194 }
195
196 protected JRFillSubreport(JRFillSubreport subreport, JRFillCloneFactory factory)
197 {
198 super(subreport, factory);
199
200 parameters = subreport.parameters;
201 returnValues = new FillReturnValues(subreport.returnValues, factory);
202 returnValuesContext = subreport.returnValuesContext;
203
204 loadedEvaluators = new HashMap<JasperReport,JREvaluator>();
205 checkedReports = subreport.checkedReports;
206
207 defaultGenerateRectangle = subreport.defaultGenerateRectangle;
208 dynamicGenerateRectangle = subreport.dynamicGenerateRectangle;
209 }
210
211 @Override
212 protected void setBand(JRFillBand band)
213 {
214 super.setBand(band);
215
216 returnValues.setBand(band);
217 }
218
219
220 @Override
221 public ModeEnum getModeValue()
222 {
223 return getStyleResolver().getMode(this, ModeEnum.TRANSPARENT);
224 }
225
226
229 public boolean usingCache()
230 {
231 Boolean isUsingCache = getUsingCache();
232 if (isUsingCache == null)
233 {
234 return source instanceof String;
235 }
236 return isUsingCache;
237 }
238
239 @Override
240 public Boolean isRunToBottom()
241 {
242 return ((JRSubreport) parent).isRunToBottom();
243 }
244
245 @Override
246 public void setRunToBottom(Boolean runToBottom)
247 {
248 throw new UnsupportedOperationException();
249 }
250
251 @Override
252 public OverflowType getOverflowType()
253 {
254 return ((JRSubreport) parent).getOverflowType();
255 }
256
257 @Override
258 public void setOverflowType(OverflowType overflowType)
259 {
260 throw new UnsupportedOperationException();
261 }
262
263 @Override
264 public JRExpression getParametersMapExpression()
265 {
266 return ((JRSubreport)parent).getParametersMapExpression();
267 }
268
269 @Override
270 public JRSubreportParameter[] getParameters()
271 {
272 return parameters;
273 }
274
275 @Override
276 public JRExpression getConnectionExpression()
277 {
278 return ((JRSubreport)parent).getConnectionExpression();
279 }
280
281 @Override
282 public JRExpression getDataSourceExpression()
283 {
284 return ((JRSubreport)parent).getDataSourceExpression();
285 }
286
287 @Override
288 public JRExpression getExpression()
289 {
290 return ((JRSubreport)parent).getExpression();
291 }
292
293
296 protected JRTemplateRectangle getJRTemplateRectangle()
297 {
298 return (JRTemplateRectangle) getElementTemplate();
299 }
300
301
302 @Override
303 protected JRTemplateElement createElementTemplate()
304 {
305 return new JRTemplateRectangle(getElementOrigin(),
306 filler.getJasperPrint().getDefaultStyleProvider(), this);
307 }
308
309
310
313 protected Collection<JRPrintElement> getPrintElements()
314 {
315 Collection<JRPrintElement> printElements = null;
316
317 if (printPage != null)
318 {
319 printElements = printPage.getElements();
320
321 }
322
323 return printElements;
324 }
325
326 protected int getPrintContentsWidth()
327 {
328 return printPageContentsWidth;
329 }
330
331 public void subreportPageFilled()
332 {
333 if (printPage != null)
334 {
335 if (subreportFiller.delayedActions.hasMasterDelayedActions(printPage))
336 {
337
338 evictReportEvaluator();
339 }
340
341 subreportFiller.subreportPageFilled(printPage);
342 }
343 }
344
345
346 @Override
347 protected void evaluate(
348 byte evaluation
349 ) throws JRException
350 {
351 reset();
352
353 evaluatePrintWhenExpression(evaluation);
354
355 if (isPrintWhenExpressionNull() || isPrintWhenTrue())
356 {
357 evaluateSubreport(evaluation);
358 }
359 }
360
361 protected JasperReportSource evaluateReportSource(byte evaluation) throws JRException
362 {
363 JRExpression expression = getExpression();
364 source = evaluateExpression(expression, evaluation);
365 return getReportSource(source, getUsingCache(), filler);
366 }
367
368 public static JasperReportSource getReportSource(Object source, Boolean isUsingCache,
369 BaseReportFiller filler) throws JRException
370 {
371 JasperReportSource report = null;
372 if (source != null)
373 {
374 if (isUsingCache == null)
375 {
376 isUsingCache = source instanceof String;
377 }
378
379 Object cacheKey = source;
380 if (source instanceof String)
381 {
382 cacheKey = ResourcePathKey.inContext(filler.getRepositoryContext(), (String) source);
383 }
384
385 if (isUsingCache && filler.fillContext.hasLoadedSubreport(cacheKey))
386 {
387 report = filler.fillContext.getLoadedSubreport(cacheKey);
388 }
389 else
390 {
391 if (source instanceof String)
392 {
393 RepositoryUtil repository = RepositoryUtil.getInstance(filler.getRepositoryContext());
394 ResourceInfo resourceInfo = repository.getResourceInfo((String) source);
395 if (resourceInfo == null)
396 {
397 report = loadReportSource(source, null, filler);
398 }
399 else
400 {
401 String reportLocation = resourceInfo.getRepositoryResourceLocation();
402 String contextLocation = resourceInfo.getRepositoryContextLocation();
403 if (log.isDebugEnabled())
404 {
405 log.debug("subreport source " + source + " resolved to " + reportLocation
406 + ", context " + contextLocation);
407 }
408
409 ResourcePathKey absolutePathKey = ResourcePathKey.absolute(reportLocation);
410 if (isUsingCache && filler.fillContext.hasLoadedSubreport(absolutePathKey))
411 {
412 report = filler.fillContext.getLoadedSubreport(absolutePathKey);
413 }
414 else
415 {
416 report = loadReportSource(reportLocation, contextLocation, filler);
417 if (isUsingCache)
418 {
419 filler.fillContext.registerLoadedSubreport(absolutePathKey, report);
420 }
421 }
422 }
423 }
424 else
425 {
426 report = loadReportSource(source, null, filler);
427 }
428
429 if (isUsingCache)
430 {
431 filler.fillContext.registerLoadedSubreport(cacheKey, report);
432 }
433 }
434 }
435
436 return report;
437 }
438
439 protected static JasperReportSource loadReportSource(Object reportSource, String contextLocation,
440 BaseReportFiller filler) throws JRException
441 {
442 JasperReport jasperReport = loadReport(reportSource, filler);
443 JasperReportSource report = null;
444 if (jasperReport != null)
445 {
446 RepositoryResourceContext currentContext = filler.getRepositoryContext().getResourceContext();
447 RepositoryResourceContext reportContext = SimpleRepositoryResourceContext.of(contextLocation,
448 currentContext == null ? null : currentContext.getDerivedContextFallback());
449 report = SimpleJasperReportSource.from(jasperReport,
450 reportSource instanceof String ? (String) reportSource : null,
451 reportContext);
452 }
453 return report;
454 }
455
456 public static JasperReport loadReport(Object source, BaseReportFiller filler) throws JRException
457 {
458 JasperReport report;
459 if (source instanceof net.sf.jasperreports.engine.JasperReport)
460 {
461 report = (JasperReport)source;
462 }
463 else if (source instanceof java.io.InputStream)
464 {
465 report = (JasperReport)JRLoader.loadObject((InputStream)source);
466 }
467 else if (source instanceof java.net.URL)
468 {
469 report = (JasperReport)JRLoader.loadObject((URL)source);
470 }
471 else if (source instanceof java.io.File)
472 {
473 report = (JasperReport)JRLoader.loadObject((File)source);
474 }
475 else if (source instanceof java.lang.String)
476 {
477 report = RepositoryUtil.getInstance(filler.getRepositoryContext()).getReport(filler.getFillContext().getReportContext(), (String)source);
478
479
480
481
482
483
484 }
485 else
486 {
487 throw
488 new JRRuntimeException(
489 EXCEPTION_MESSAGE_KEY_UNSUPPORTED_SECTION_TYPE,
490 new Object[]{source.getClass().getName()}
491 );
492 }
493 return report;
494 }
495
496
499 protected void evaluateSubreport(
500 byte evaluation
501 ) throws JRException
502 {
503 evaluateProperties(evaluation);
504 evaluateStyle(evaluation);
505
506 jasperReportSource = evaluateReportSource(evaluation);
507
508 if (jasperReportSource != null)
509 {
510 JRFillDataset parentDataset = expressionEvaluator.getFillDataset();
511 datasetPosition = new FillDatasetPosition(parentDataset.fillPosition);
512 datasetPosition.addAttribute("subreportUUID", getUUID());
513 parentDataset.setCacheRecordIndex(datasetPosition, evaluation);
514
515
516 connection = (Connection) evaluateExpression(
517 getConnectionExpression(), evaluation);
518
519 String cacheIncludedProp = JRPropertiesUtil.getOwnProperty(this, DataCacheHandler.PROPERTY_INCLUDED);
520 cacheIncluded = JRPropertiesUtil.asBoolean(cacheIncludedProp, true);
521
522 if (filler.fillContext.hasDataSnapshot() && cacheIncluded)
523 {
524
525 dataSource = null;
526 }
527 else
528 {
529 dataSource = (JRDataSource) evaluateExpression(
530 getDataSourceExpression(), evaluation);
531 }
532
533 parameterValues =
534 evaluateParameterValues(evaluation);
535
536 if (subreportFiller != null)
537 {
538 filler.unregisterSubfiller(subreportFiller);
539 }
540
541
542 DatasetExpressionEvaluator evaluator = loadReportEvaluator();
543 initSubreportFiller(evaluator);
544
545 validateReport();
546
547 returnValues.saveReturnVariables();
548 }
549 }
550
551 protected JasperReport getReport()
552 {
553 return jasperReportSource == null ? null : jasperReportSource.getReport();
554 }
555
556 protected Map<String, Object> evaluateParameterValues(byte evaluation) throws JRException
557 {
558 JasperReport jasperReport = getReport();
559 return getParameterValues(
560 filler,
561 expressionEvaluator,
562 getParametersMapExpression(),
563 getParameters(),
564 evaluation,
565 false,
566 jasperReport.getResourceBundle() != null,
567 jasperReport.getFormatFactoryClass() != null
568 );
569 }
570
571 protected DatasetExpressionEvaluator loadReportEvaluator() throws JRException
572 {
573 JasperReport jasperReport = getReport();
574 DatasetExpressionEvaluator evaluator = null;
575 boolean usingCache = usingCache();
576 if (usingCache)
577 {
578 evaluator = loadedEvaluators.get(jasperReport);
579 }
580 if (evaluator == null)
581 {
582 evaluator = createEvaluator();
583 if (usingCache)
584 {
585 loadedEvaluators.put(jasperReport, (JREvaluator)evaluator);
586 }
587 }
588 return evaluator;
589 }
590
591 protected void evictReportEvaluator()
592 {
593 loadedEvaluators.remove(getReport());
594 }
595
596
597 protected DatasetExpressionEvaluator createEvaluator() throws JRException
598 {
599 return JasperCompileManager.getInstance(filler.getJasperReportsContext()).getEvaluator(
600 getReport());
601 }
602
603
604 protected boolean isReorderBandElements()
605 {
606 return false;
607 }
608
609
610 protected void initSubreportFiller(DatasetExpressionEvaluator evaluator) throws JRException
611 {
612 JasperReport jasperReport = getReport();
613 if (log.isDebugEnabled())
614 {
615 log.debug("Fill " + filler.fillerId + ": creating subreport filler for " + jasperReport.getName());
616 }
617
618 SectionTypeEnum subreportSectionType = jasperReport.getSectionType();
619 if (subreportSectionType != null && subreportSectionType != SectionTypeEnum.BAND)
620 {
621 throw
622 new JRRuntimeException(
623 EXCEPTION_MESSAGE_KEY_UNSUPPORTED_SECTION_TYPE,
624 new Object[]{subreportSectionType}
625 );
626 }
627
628 subFillerParent = createFillerParent(evaluator);
629
630 switch (jasperReport.getPrintOrderValue())
631 {
632 case HORIZONTAL :
633 {
634 subreportFiller = new JRHorizontalFiller(filler.getJasperReportsContext(), jasperReportSource, subFillerParent);
635 break;
636 }
637 case VERTICAL :
638 default :
639 {
640 subreportFiller = new JRVerticalFiller(filler.getJasperReportsContext(), jasperReportSource, subFillerParent);
641 break;
642 }
643 }
644
645 subreportFiller.setReorderBandElements(isReorderBandElements());
646
647 runner = getRunnerFactory().createSubreportRunner(this, subreportFiller);
648 subFillerParent.setSubreportRunner(runner);
649
650 subreportFiller.mainDataset.setFillPosition(datasetPosition);
651 subreportFiller.mainDataset.setCacheSkipped(!cacheIncluded);
652 }
653
654 protected FillerSubreportParent createFillerParent(DatasetExpressionEvaluator evaluator) throws JRException
655 {
656 return new FillerSubreportParent(this, evaluator);
657 }
658
659
672 public static Map<String, Object> getParameterValues(
673 BaseReportFiller filler,
674 JRExpression parametersMapExpression,
675 JRDatasetParameter[] subreportParameters,
676 byte evaluation,
677 boolean ignoreNullExpressions,
678 boolean removeResourceBundle,
679 boolean removeFormatFactory
680 ) throws JRException
681 {
682 return getParameterValues(filler, filler.getExpressionEvaluator(),
683 parametersMapExpression, subreportParameters, evaluation,
684 ignoreNullExpressions, removeResourceBundle, removeFormatFactory);
685 }
686
687
701 public static Map<String, Object> getParameterValues(
702
703 BaseReportFiller filler,
704 JRFillExpressionEvaluator expressionEvaluator,
705 JRExpression parametersMapExpression,
706 JRDatasetParameter[] subreportParameters,
707 byte evaluation,
708 boolean ignoreNullExpressions,
709 boolean removeResourceBundle,
710 boolean removeFormatFactory
711 ) throws JRException
712 {
713 Map<String, Object> parameterValues = null;
714 if (parametersMapExpression != null)
715 {
716 parameterValues = (Map<String, Object>) expressionEvaluator.evaluate(parametersMapExpression, evaluation);
717 }
718
719 if (parameterValues != null)
720 {
721
722 if (parameterValues == filler.getParameterValuesMap())
723 {
724
725 parameterValues = new HashMap<String, Object>(parameterValues);
726 }
727
728
729 if (removeResourceBundle)
730 {
731 parameterValues.remove(JRParameter.REPORT_RESOURCE_BUNDLE);
732 }
733 if (removeFormatFactory)
734 {
735 parameterValues.remove(JRParameter.REPORT_FORMAT_FACTORY);
736 }
737
738 parameterValues.remove(JRParameter.JASPER_REPORTS_CONTEXT);
739 parameterValues.remove(JRParameter.JASPER_REPORT);
740 parameterValues.remove(JRParameter.REPORT_CONNECTION);
741 parameterValues.remove(JRParameter.REPORT_MAX_COUNT);
742 parameterValues.remove(JRParameter.REPORT_DATA_SOURCE);
743 parameterValues.remove(JRParameter.REPORT_SCRIPTLET);
744
745
746 JRScriptlet[] scriptlets = filler.getJasperReport().getScriptlets();
747 if (scriptlets != null)
748 {
749 for(int i = 0; i < scriptlets.length; i++)
750 {
751 parameterValues.remove(scriptlets[i].getName()
752 + JRScriptlet.SCRIPTLET_PARAMETER_NAME_SUFFIX);
753 }
754 }
755 parameterValues.remove(JRParameter.REPORT_VIRTUALIZER);
756
757 parameterValues.remove(JRParameter.IS_IGNORE_PAGINATION);
758 parameterValues.remove(JRParameter.SORT_FIELDS);
759 parameterValues.remove(JRParameter.FILTER);
760 parameterValues.remove(JRParameter.REPORT_PARAMETERS_MAP);
761 }
762
763 if (parameterValues == null)
764 {
765 parameterValues = new HashMap<String, Object>();
766 }
767
768
769 if (subreportParameters != null && subreportParameters.length > 0)
770 {
771 Object parameterValue = null;
772 for(int i = 0; i < subreportParameters.length; i++)
773 {
774 JRExpression expression = subreportParameters[i].getExpression();
775 if (expression != null || !ignoreNullExpressions)
776 {
777 parameterValue = expressionEvaluator.evaluate(expression, evaluation);
778 if (parameterValue == null)
779 {
780 parameterValues.remove(subreportParameters[i].getName());
781 }
782 else
783 {
784 parameterValues.put(subreportParameters[i].getName(), parameterValue);
785 }
786 }
787 }
788 }
789
790 if (!parameterValues.containsKey(JRParameter.REPORT_LOCALE))
791 {
792 parameterValues.put(JRParameter.REPORT_LOCALE, filler.getLocale());
793 }
794
795 if (!parameterValues.containsKey(JRParameter.REPORT_TIME_ZONE))
796 {
797 parameterValues.put(JRParameter.REPORT_TIME_ZONE, filler.getTimeZone());
798 }
799
800 if (
801 !parameterValues.containsKey(JRParameter.REPORT_FORMAT_FACTORY)
802 && !removeFormatFactory
803 )
804 {
805 parameterValues.put(JRParameter.REPORT_FORMAT_FACTORY, filler.getFormatFactory());
806 }
807
808 if (!parameterValues.containsKey(JRParameter.REPORT_CONTEXT))
809 {
810 ReportContext context = (ReportContext) filler.getMainDataset().getParameterValue(
811 JRParameter.REPORT_CONTEXT, true);
812 if (context != null)
813 {
814 parameterValues.put(JRParameter.REPORT_CONTEXT, context);
815 }
816 }
817
818 return parameterValues;
819 }
820
821 @continuable
822 protected void fillSubreport() throws JRException
823 {
824 if (getConnectionExpression() != null)
825 {
826 subreportFiller.fill(parameterValues, connection);
827 }
828 else if (getDataSourceExpression() != null)
829 {
830 subreportFiller.fill(parameterValues, dataSource);
831 }
832 else
833 {
834 subreportFiller.fill(parameterValues);
835 }
836 }
837
838
839 @Override
840 protected boolean prepare(
841 int availableHeight,
842 boolean isOverflow
843 ) throws JRException
844 {
845 boolean willOverflow = false;
846
847 super.prepare(availableHeight, isOverflow);
848
849 if (subreportFiller == null)
850 {
851 setToPrint(false);
852 }
853
854 if (!isToPrint())
855 {
856 return willOverflow;
857 }
858
859 int elementHeight = getHeight();
860 if (availableHeight < getRelativeY() + elementHeight)
861 {
862 setToPrint(false);
863 return true;
864 }
865
866
867
868
869
870 boolean filling = runner.isFilling();
871 boolean toPrint = !isOverflow || isPrintWhenDetailOverflows() || !isAlreadyPrinted();
872 boolean reprinted = isOverflow && isPrintWhenDetailOverflows();
873
874
875
876
877
878 if (elementHeight == 0 && availableHeight == getRelativeY()
879
880 && !filling && toPrint
881 && fillContainerContext != null
882 && fillContainerContext.isCurrentOverflow()
883 && fillContainerContext.isCurrentOverflowAllowed())
884 {
885 if (log.isDebugEnabled())
886 {
887 log.debug("zero height subreport at the bottom, not starting");
888 }
889
890 setToPrint(false);
891 return true;
892 }
893
894 if (!filling && toPrint && reprinted)
895 {
896 rewind();
897 }
898
899 if (printPage instanceof JRVirtualPrintPage)
900 {
901
902
903
904 ((JRVirtualPrintPage) printPage).dispose();
905 }
906
907 int pageHeight;
908 OverflowType overflowType = getOverflowType();
909 if (overflowType == OverflowType.NO_STRETCH && !filler.isIgnorePagination())
910 {
911
912
913 pageHeight = elementHeight;
914 }
915 else
916 {
917
918 pageHeight = availableHeight - getRelativeY();
919 }
920 subreportFiller.setPageHeight(pageHeight);
921
922 synchronized (subreportFiller)
923 {
924 JRSubreportRunResult result;
925 if (filling)
926 {
927 if (log.isDebugEnabled())
928 {
929 log.debug("Fill " + filler.fillerId + ": resuming " + subreportFiller.fillerId);
930 }
931
932 result = runner.resume();
933 }
934 else if (toPrint)
935 {
936 setReprinted(reprinted);
937
938 if (log.isDebugEnabled())
939 {
940 log.debug("Fill " + filler.fillerId + ": starting " + subreportFiller.fillerId);
941 }
942
943 result = runner.start();
944 }
945 else
946 {
947 printPage = null;
948 printPageContentsWidth = 0;
949 setPrepareHeight(getHeight());
950 setToPrint(false);
951
952 return willOverflow;
953 }
954
955 if (result.getException() != null)
956 {
957 Throwable error = result.getException();
958
959 if (log.isErrorEnabled())
960 {
961 log.error("Fill " + filler.fillerId + ": exception", error);
962 }
963
964 if (error instanceof RuntimeException)
965 {
966 throw (RuntimeException) error;
967 }
968
969 throw new JRRuntimeException(error);
970 }
971
972 if (result.hasFinished())
973 {
974 if (log.isDebugEnabled())
975 {
976 log.debug("Fill " + filler.fillerId + ": subreport " + subreportFiller.fillerId + " finished");
977 }
978
979 returnValues.copyValues(returnValuesContext);
980 }
981 else
982 {
983 if (log.isDebugEnabled())
984 {
985 log.debug("Fill " + filler.fillerId + ": subreport " + subreportFiller.fillerId + " to continue");
986 }
987 }
988
989 printPage = subreportFiller.getCurrentPage();
990 printPageContentsWidth = subreportFiller.getCurrentPageContentsWidth();
991 setPrepareHeight(result.hasFinished() ? subFillerParent.getCurrentPageStretchHeight() : pageHeight);
992
993
994
995 willOverflow = !result.hasFinished();
996
997 if (!willOverflow)
998 {
999
1000 runner.reset();
1001 }
1002 }
1003
1004 Collection<JRPrintElement> printElements = getPrintElements();
1005 if (
1006 (printElements == null || printElements.size() == 0) &&
1007 isRemoveLineWhenBlank()
1008 )
1009 {
1010 setToPrint(false);
1011 }
1012
1013 return willOverflow;
1014 }
1015
1016
1017 @Override
1018 public void rewind() throws JRException
1019 {
1020 if (subreportFiller == null)
1021 {
1022 return;
1023 }
1024
1025 cancelSubreportFill();
1026
1027 initSubreportFiller(null);
1028
1029 if (getConnectionExpression() == null && dataSource != null)
1030 {
1031 if(dataSource instanceof JRRewindableDataSource)
1032 {
1033 ((JRRewindableDataSource) dataSource).moveFirst();
1034 }
1035 else
1036 {
1037
1038
1039 throw
1040 new JRException(
1041 EXCEPTION_MESSAGE_KEY_NO_REWINDABLE_DATA_SOURCE,
1042 (Object[])null
1043 );
1044 }
1045 }
1046 }
1047
1048
1049 protected void cancelSubreportFill() throws JRException
1050 {
1051 if (log.isDebugEnabled())
1052 {
1053 log.debug("Fill " + filler.fillerId + ": cancelling " + subreportFiller.fillerId);
1054 }
1055
1056
1057 subreportFiller.setInterrupted(true);
1058
1059 synchronized (subreportFiller)
1060 {
1061
1062 runner.cancel();
1063 runner.reset();
1064 }
1065
1066 filler.unregisterSubfiller(subreportFiller);
1067 }
1068
1069
1070 @Override
1071 protected JRPrintElement fill()
1072 {
1073
1074 JRPrintRectangle printRectangle = new JRTemplatePrintRectangle(getJRTemplateRectangle(), printElementOriginator);
1075
1076 if (printRectangle.getModeValue() == ModeEnum.TRANSPARENT && !printRectangle.hasProperties())
1077 {
1078 String generateRectangle = generateRectangleOption();
1079 if (log.isDebugEnabled())
1080 {
1081 log.debug("empty rectangle, generate option: " + generateRectangle);
1082 }
1083
1084 if (generateRectangle == null || !generateRectangle.equals(SUBREPORT_GENERATE_RECTANGLE_ALWAYS))
1085 {
1086
1087 return null;
1088 }
1089 }
1090
1091 printRectangle.setUUID(getUUID());
1092 printRectangle.setX(getX());
1093 printRectangle.setY(getRelativeY());
1094 printRectangle.setWidth(getWidth());
1095 printRectangle.setHeight(getStretchHeight());
1096
1097 return printRectangle;
1098 }
1099
1100 protected String generateRectangleOption()
1101 {
1102 String generateRectangle = defaultGenerateRectangle;
1103 if (dynamicGenerateRectangle)
1104 {
1105 String generateRectangleProp = getDynamicProperties().getProperty(PROPERTY_SUBREPORT_GENERATE_RECTANGLE);
1106 if (generateRectangleProp != null)
1107 {
1108 generateRectangle = generateRectangleProp;
1109 }
1110 }
1111 return generateRectangle;
1112 }
1113
1114
1115 @Override
1116 public void collectExpressions(JRExpressionCollector collector)
1117 {
1118 collector.collect(this);
1119 }
1120
1121 @Override
1122 public void visit(JRVisitor visitor)
1123 {
1124 visitor.visitSubreport(this);
1125 }
1126
1127
1128 @Override
1129 public JRSubreportReturnValue[] getReturnValues()
1130 {
1131 return ((JRSubreport) parent).getReturnValues();
1132 }
1133
1134 protected void validateReport() throws JRException
1135 {
1136 JasperReport jasperReport = getReport();
1137 if (!checkedReports.contains(jasperReport))
1138 {
1139 verifyBandHeights();
1140 returnValues.checkReturnValues(returnValuesContext);
1141
1142 if (usingCache())
1143 {
1144 checkedReports.add(jasperReport);
1145 }
1146 }
1147 }
1148
1149 protected void verifyBandHeights() throws JRException
1150 {
1151 if (!filler.isIgnorePagination())
1152 {
1153 JasperReport jasperReport = getReport();
1154
1155 int pageHeight;
1156 int topMargin = jasperReport.getTopMargin();
1157 int bottomMargin = jasperReport.getBottomMargin();
1158
1159 JRBaseFiller parentFiller = filler;
1160 do
1161 {
1162
1163 pageHeight = parentFiller.jasperReport.getPageHeight();
1164
1165
1166 topMargin += parentFiller.jasperReport.getTopMargin();
1167 bottomMargin += parentFiller.jasperReport.getBottomMargin();
1168
1169 parentFiller =
1170 parentFiller.parent != null && parentFiller.parent.getFiller() instanceof JRBaseFiller
1171 ? (JRBaseFiller) parentFiller.parent.getFiller()
1172 : null;
1173 }
1174 while (parentFiller != null);
1175
1176 List<JRValidationFault> brokenRules = new ArrayList<JRValidationFault>();
1177 JRVerifier.verifyBandHeights(brokenRules,
1178 jasperReport, pageHeight, topMargin, bottomMargin);
1179
1180 if (!brokenRules.isEmpty())
1181 {
1182 throw new JRValidationException("Band height validation for subreport \""
1183 + jasperReport.getName() + "\" failed in the current page context "
1184 + "(height = " + pageHeight + ", top margin = " + topMargin
1185 + ", bottom margin = " + bottomMargin + ") : ",
1186 brokenRules);
1187 }
1188 else if (log.isDebugEnabled())
1189 {
1190 log.debug("Band height validation for subreport \""
1191 + jasperReport.getName() + "\" succeeded in the current page context "
1192 + "(height = " + pageHeight + ", top margin = " + topMargin
1193 + ", bottom margin = " + bottomMargin + ")");
1194 }
1195 }
1196 }
1197
1198
1199 @Override
1200 protected void resolveElement (JRPrintElement element, byte evaluation)
1201 {
1202
1203 }
1204
1205
1206 @Override
1207 public Boolean getUsingCache()
1208 {
1209 return ((JRSubreport)parent).getUsingCache();
1210 }
1211
1212
1213 @Override
1214 public void setUsingCache(Boolean isUsingCache)
1215 {
1216 }
1217
1218
1219 @Override
1220 public JRFillCloneable createClone(JRFillCloneFactory factory)
1221 {
1222 return new JRFillSubreport(this, factory);
1223 }
1224
1225 protected JRSubreportRunnerFactory getRunnerFactory() throws JRException
1226 {
1227 String factoryClassName = filler.getPropertiesUtil().getProperty(JRSubreportRunnerFactory.SUBREPORT_RUNNER_FACTORY);
1228 if (factoryClassName == null)
1229 {
1230 throw
1231 new JRException(
1232 EXCEPTION_MESSAGE_KEY_PROPERTY_NOT_SET,
1233 new Object[]{JRSubreportRunnerFactory.SUBREPORT_RUNNER_FACTORY}
1234 );
1235 }
1236 return runnerFactoryCache.getCachedInstance(factoryClassName);
1237 }
1238
1239 protected int getContentsStretchHeight()
1240 {
1241 return subFillerParent.getCurrentPageStretchHeight();
1242 }
1243
1244 protected String getReportLocation()
1245 {
1246 return jasperReportSource == null ? null : jasperReportSource.getReportLocation();
1247 }
1248
1249 protected void registerReportStyles(List<JRStyle> styles)
1250 {
1251
1252 }
1253
1254 protected String getReportName()
1255 {
1256 return getReport().getName();
1257 }
1258
1259 protected boolean isSplitTypePreventInhibited(boolean isTopLevelCall)
1260 {
1261 return fillContainerContext.isSplitTypePreventInhibited(isTopLevelCall);
1262 }
1263 }
1264