1 28 package net.sf.jasperreports.engine.fill; 29 30 import java.io.File ; 31 import java.io.IOException ; 32 import java.io.InputStream ; 33 import java.net.URL ; 34 import java.sql.Connection ; 35 import java.util.ArrayList ; 36 import java.util.Collection ; 37 import java.util.HashMap ; 38 import java.util.HashSet ; 39 import java.util.List ; 40 import java.util.Map ; 41 import java.util.Set ; 42 43 import net.sf.jasperreports.engine.JRAbstractObjectFactory; 44 import net.sf.jasperreports.engine.JRChild; 45 import net.sf.jasperreports.engine.JRDataSource; 46 import net.sf.jasperreports.engine.JRDatasetParameter; 47 import net.sf.jasperreports.engine.JRException; 48 import net.sf.jasperreports.engine.JRExpression; 49 import net.sf.jasperreports.engine.JRExpressionCollector; 50 import net.sf.jasperreports.engine.JRParameter; 51 import net.sf.jasperreports.engine.JRPrintElement; 52 import net.sf.jasperreports.engine.JRPrintPage; 53 import net.sf.jasperreports.engine.JRPrintRectangle; 54 import net.sf.jasperreports.engine.JRReport; 55 import net.sf.jasperreports.engine.JRRewindableDataSource; 56 import net.sf.jasperreports.engine.JRRuntimeException; 57 import net.sf.jasperreports.engine.JRStyle; 58 import net.sf.jasperreports.engine.JRSubreport; 59 import net.sf.jasperreports.engine.JRSubreportParameter; 60 import net.sf.jasperreports.engine.JRSubreportReturnValue; 61 import net.sf.jasperreports.engine.JRVariable; 62 import net.sf.jasperreports.engine.JasperReport; 63 import net.sf.jasperreports.engine.design.JRDefaultCompiler; 64 import net.sf.jasperreports.engine.design.JRDesignSubreportReturnValue; 65 import net.sf.jasperreports.engine.util.JRLoader; 66 import net.sf.jasperreports.engine.util.JRProperties; 67 import net.sf.jasperreports.engine.util.JRSingletonCache; 68 import net.sf.jasperreports.engine.util.JRStyleResolver; 69 import net.sf.jasperreports.engine.xml.JRXmlWriter; 70 71 import org.apache.commons.logging.Log; 72 import org.apache.commons.logging.LogFactory; 73 74 75 79 public class JRFillSubreport extends JRFillElement implements JRSubreport 80 { 81 82 83 86 private static final Log log = LogFactory.getLog(JRFillSubreport.class); 87 88 private static final JRSingletonCache runnerFactoryCache = new JRSingletonCache(JRSubreportRunnerFactory.class); 89 90 93 private Map parameterValues = null; 94 private JRSubreportParameter[] parameters = null; 95 private Connection connection = null; 96 private JRDataSource dataSource = null; 97 private JasperReport jasperReport = null; 98 99 private Map loadedEvaluators = null; 100 101 104 private JRFillSubreportReturnValue[] returnValues = null; 105 106 109 protected JRBaseFiller subreportFiller = null; 110 private JRPrintPage printPage = null; 111 112 private JRSubreportRunner runner; 113 114 117 private Set checkedReports; 118 119 120 123 protected JRFillSubreport( 124 JRBaseFiller filler, 125 JRSubreport subreport, 126 JRFillObjectFactory factory 127 ) 128 { 129 super(filler, subreport, factory); 130 131 parameters = subreport.getParameters(); 132 JRSubreportReturnValue[] subrepReturnValues = subreport.getReturnValues(); 133 if (subrepReturnValues != null) 134 { 135 List returnValuesList = new ArrayList (subrepReturnValues.length * 2); 136 137 returnValues = new JRFillSubreportReturnValue[subrepReturnValues.length]; 138 for (int i = 0; i < subrepReturnValues.length; i++) 139 { 140 addReturnValue(subrepReturnValues[i], returnValuesList, factory); 141 } 142 143 returnValues = new JRFillSubreportReturnValue[returnValuesList.size()]; 144 returnValuesList.toArray(returnValues); 145 } 146 147 loadedEvaluators = new HashMap (); 148 checkedReports = new HashSet (); 149 } 150 151 152 155 public byte getMode() 156 { 157 return JRStyleResolver.getMode(this, MODE_TRANSPARENT); 158 } 159 160 163 public boolean isUsingCache() 164 { 165 return ((JRSubreport)parent).isUsingCache(); 166 } 167 168 171 public void setUsingCache(boolean isUsingCache) 172 { 173 } 174 175 178 public JRExpression getParametersMapExpression() 179 { 180 return ((JRSubreport)parent).getParametersMapExpression(); 181 } 182 183 186 public JRSubreportParameter[] getParameters() 187 { 188 return parameters; 189 } 190 191 194 public JRExpression getConnectionExpression() 195 { 196 return ((JRSubreport)parent).getConnectionExpression(); 197 } 198 199 202 public JRExpression getDataSourceExpression() 203 { 204 return ((JRSubreport)parent).getDataSourceExpression(); 205 } 206 207 210 public JRExpression getExpression() 211 { 212 return ((JRSubreport)parent).getExpression(); 213 } 214 215 218 protected JRTemplateRectangle getJRTemplateRectangle() 219 { 220 JRStyle style = getStyle(); 221 JRTemplateRectangle template = (JRTemplateRectangle) getTemplate(style); 222 if (template == null) 223 { 224 template = new JRTemplateRectangle(filler.getJasperPrint().getDefaultStyleProvider(), this); 225 registerTemplate(style, template); 226 } 227 return template; 228 } 229 230 231 234 protected Collection getPrintElements() 235 { 236 Collection printElements = null; 237 238 if (printPage != null) 239 { 240 printElements = printPage.getElements(); 241 } 242 243 return printElements; 244 } 245 246 247 250 protected void evaluate( 251 byte evaluation 252 ) throws JRException 253 { 254 reset(); 255 256 evaluatePrintWhenExpression(evaluation); 257 258 if ( 259 (isPrintWhenExpressionNull() || 260 (!isPrintWhenExpressionNull() && 261 isPrintWhenTrue())) 262 ) 263 { 264 JRExpression expression = getExpression(); 265 Object source = evaluateExpression(expression, evaluation); 266 if (source != null) { 268 JREvaluator evaluator = null; 269 270 if (isUsingCache() && filler.loadedSubreports.containsKey(source)) 271 { 272 jasperReport = (JasperReport)filler.loadedSubreports.get(source); 273 evaluator = (JREvaluator)loadedEvaluators.get(jasperReport); 274 275 if (evaluator == null) 276 { 277 evaluator = JRDefaultCompiler.getInstance().loadEvaluator(jasperReport); 278 loadedEvaluators.put(jasperReport, evaluator); 279 } 280 } 281 else 282 { 283 Class expressionClass = expression.getValueClass(); 284 285 if (expressionClass.equals(net.sf.jasperreports.engine.JasperReport.class)) 286 { 287 jasperReport = (JasperReport)source; 288 } 289 else if (expressionClass.equals(java.io.InputStream .class)) 290 { 291 jasperReport = (JasperReport)JRLoader.loadObject((InputStream )source); 292 } 293 else if (expressionClass.equals(java.net.URL .class)) 294 { 295 jasperReport = (JasperReport)JRLoader.loadObject((URL )source); 296 } 297 else if (expressionClass.equals(java.io.File .class)) 298 { 299 jasperReport = (JasperReport)JRLoader.loadObject((File )source); 300 } 301 else if (expressionClass.equals(java.lang.String .class)) 302 { 303 jasperReport = (JasperReport)JRLoader.loadObjectFromLocation((String )source, filler.reportClassLoader, 304 filler.urlHandlerFactory); 305 } 306 307 if (jasperReport != null) 308 { 309 evaluator = JRDefaultCompiler.getInstance().loadEvaluator(jasperReport); 310 } 311 312 if (isUsingCache()) 313 { 314 filler.loadedSubreports.put(source, jasperReport); 315 loadedEvaluators.put(jasperReport, evaluator); 316 } 317 } 318 319 if (jasperReport != null) 320 { 321 322 expression = getConnectionExpression(); 323 connection = (Connection ) evaluateExpression(expression, evaluation); 324 325 326 expression = getDataSourceExpression(); 327 dataSource = (JRDataSource) evaluateExpression(expression, evaluation); 328 329 parameterValues = 330 getParameterValues( 331 filler, 332 getParametersMapExpression(), 333 getParameters(), 334 evaluation, 335 false, 336 jasperReport.getResourceBundle() != null, jasperReport.getFormatFactoryClass() != null ); 339 340 if (subreportFiller != null) 341 { 342 filler.unregisterSubfiller(subreportFiller); 343 } 344 345 346 initSubreportFiller(evaluator); 347 348 checkReturnValues(); 349 } 350 } 351 } 352 } 353 354 355 protected void initSubreportFiller(JREvaluator evaluator) throws JRException 356 { 357 switch (jasperReport.getPrintOrder()) 358 { 359 case JRReport.PRINT_ORDER_HORIZONTAL : 360 { 361 subreportFiller = new JRHorizontalFiller(jasperReport, evaluator, filler); 362 break; 363 } 364 case JRReport.PRINT_ORDER_VERTICAL : 365 { 366 subreportFiller = new JRVerticalFiller(jasperReport, evaluator, filler); 367 break; 368 } 369 default : 370 { 371 throw new JRRuntimeException("Unkown print order " + jasperReport.getPrintOrder() + "."); 372 } 373 } 374 375 runner = getRunnerFactory().createSubreportRunner(this, subreportFiller); 376 subreportFiller.setSubreportRunner(runner); 377 } 378 379 380 393 public static Map getParameterValues( 394 JRBaseFiller filler, 395 JRExpression parametersMapExpression, 396 JRDatasetParameter[] subreportParameters, 397 byte evaluation, 398 boolean ignoreNullExpressions, 399 boolean removeResourceBundle, 400 boolean removeFormatFactory 401 ) throws JRException 402 { 403 Map parameterValues = null; 404 if (parametersMapExpression != null) 405 { 406 parameterValues = (Map ) filler.evaluateExpression(parametersMapExpression, evaluation); 407 } 408 409 if (parameterValues != null) 410 { 411 if (removeResourceBundle) 413 { 414 parameterValues.remove(JRParameter.REPORT_RESOURCE_BUNDLE); 415 } 416 if (removeFormatFactory) 417 { 418 parameterValues.remove(JRParameter.REPORT_FORMAT_FACTORY); 419 } 420 parameterValues.remove(JRParameter.REPORT_CONNECTION); 422 parameterValues.remove(JRParameter.REPORT_MAX_COUNT); 423 parameterValues.remove(JRParameter.REPORT_DATA_SOURCE); 424 parameterValues.remove(JRParameter.REPORT_SCRIPTLET); 425 parameterValues.remove(JRParameter.REPORT_VIRTUALIZER); 426 parameterValues.remove(JRParameter.IS_IGNORE_PAGINATION); 428 parameterValues.remove(JRParameter.REPORT_PARAMETERS_MAP); 429 } 430 431 if (parameterValues == null) 432 { 433 parameterValues = new HashMap (); 434 } 435 436 437 if (subreportParameters != null && subreportParameters.length > 0) 438 { 439 Object parameterValue = null; 440 for(int i = 0; i < subreportParameters.length; i++) 441 { 442 JRExpression expression = subreportParameters[i].getExpression(); 443 if (expression != null || !ignoreNullExpressions) 444 { 445 parameterValue = filler.evaluateExpression(expression, evaluation); 446 if (parameterValue == null) 447 { 448 parameterValues.remove(subreportParameters[i].getName()); 449 } 450 else 451 { 452 parameterValues.put(subreportParameters[i].getName(), parameterValue); 453 } 454 } 455 } 456 } 457 458 if (!parameterValues.containsKey(JRParameter.REPORT_LOCALE)) 459 { 460 parameterValues.put(JRParameter.REPORT_LOCALE, filler.getLocale()); 461 } 462 463 if (!parameterValues.containsKey(JRParameter.REPORT_TIME_ZONE)) 464 { 465 parameterValues.put(JRParameter.REPORT_TIME_ZONE, filler.getTimeZone()); 466 } 467 468 if ( 469 !parameterValues.containsKey(JRParameter.REPORT_FORMAT_FACTORY) 470 && !removeFormatFactory 471 ) 472 { 473 parameterValues.put(JRParameter.REPORT_FORMAT_FACTORY, filler.getFormatFactory()); 474 } 475 476 if (!parameterValues.containsKey(JRParameter.REPORT_CLASS_LOADER) && 477 filler.reportClassLoader != null) 478 { 479 parameterValues.put(JRParameter.REPORT_CLASS_LOADER, filler.reportClassLoader); 480 } 481 482 if (!parameterValues.containsKey(JRParameter.REPORT_URL_HANDLER_FACTORY) && 483 filler.urlHandlerFactory != null) 484 { 485 parameterValues.put(JRParameter.REPORT_URL_HANDLER_FACTORY, filler.urlHandlerFactory); 486 } 487 488 return parameterValues; 489 } 490 491 protected void fillSubreport() throws JRException 492 { 493 if (getConnectionExpression() != null) 494 { 495 subreportFiller.fill(parameterValues, connection); 496 } 497 else if (getDataSourceExpression() != null) 498 { 499 subreportFiller.fill(parameterValues, dataSource); 500 } 501 else 502 { 503 subreportFiller.fill(parameterValues); 504 } 505 } 506 507 508 511 protected boolean prepare( 512 int availableStretchHeight, 513 boolean isOverflow 514 ) throws JRException 515 { 516 boolean willOverflow = false; 517 518 super.prepare(availableStretchHeight, isOverflow); 519 520 if (subreportFiller == null) 521 { 522 setToPrint(false); 523 } 524 525 if (!isToPrint()) 526 { 527 return willOverflow; 528 } 529 530 if (availableStretchHeight < getRelativeY() - getY() - getBandBottomY()) 531 { 532 setToPrint(false); 533 return true; } 535 536 538 540 boolean filling = runner.isFilling(); 541 boolean toPrint = !isOverflow || isPrintWhenDetailOverflows() || !isAlreadyPrinted(); 542 boolean reprinted = isOverflow && isPrintWhenDetailOverflows(); 543 544 if (!filling && toPrint && reprinted) 545 { 546 rewind(); 547 } 548 549 int availableHeight = getHeight() + availableStretchHeight - getRelativeY() + getY() + getBandBottomY(); 550 subreportFiller.setPageHeight(availableHeight); 551 552 synchronized (subreportFiller) 553 { 554 JRSubreportRunResult result; 555 if (filling) 556 { 557 result = runner.resume(); 558 } 559 else if (toPrint) 560 { 561 setReprinted(reprinted); 562 563 result = runner.start(); 564 } 565 else 566 { 567 printPage = null; 568 setStretchHeight(getHeight()); 569 setToPrint(false); 570 571 return willOverflow; 572 } 573 574 if (result.getException() != null) 575 { 576 Throwable error = result.getException(); 577 if (error instanceof RuntimeException ) 578 { 579 throw (RuntimeException ) error; 580 } 581 582 throw new JRRuntimeException(error); 583 } 584 585 if (result.hasFinished()) 586 { 587 copyValues(); 588 } 589 590 printPage = subreportFiller.getCurrentPage(); 591 setStretchHeight(result.hasFinished() ? subreportFiller.getCurrentPageStretchHeight() : availableHeight); 592 593 willOverflow = !result.hasFinished(); 596 597 if (!willOverflow) 598 { 599 runner.reset(); 601 } 602 } 604 Collection printElements = getPrintElements(); 605 if ( 606 (printElements == null || printElements.size() == 0) && 607 isRemoveLineWhenBlank() ) 609 { 610 setToPrint(false); 611 } 612 613 return willOverflow; 614 } 615 616 617 620 public void rewind() throws JRException 621 { 622 if (subreportFiller == null) 623 { 624 return; 625 } 626 627 subreportFiller.setInterrupted(true); 629 630 synchronized (subreportFiller) 631 { 632 runner.cancel(); 634 runner.reset(); 635 } 636 637 filler.unregisterSubfiller(subreportFiller); 638 639 initSubreportFiller(null); 641 if (getConnectionExpression() == null && dataSource != null) 642 { 643 if(dataSource instanceof JRRewindableDataSource) 644 { 645 ((JRRewindableDataSource) dataSource).moveFirst(); 646 } 647 else 648 { 649 if (log.isDebugEnabled()) 650 log.debug("The subreport is placed on a non-splitting band, but it does not have a rewindable data source."); 651 } 652 } 653 } 654 655 656 659 protected JRPrintElement fill() 660 { 661 JRPrintRectangle printRectangle = new JRTemplatePrintRectangle(getJRTemplateRectangle()); 662 663 printRectangle.setX(getX()); 664 printRectangle.setY(getRelativeY()); 665 printRectangle.setWidth(getWidth()); 666 printRectangle.setHeight(getStretchHeight()); 667 668 return printRectangle; 669 } 670 671 672 675 public JRChild getCopy(JRAbstractObjectFactory factory) 676 { 677 return factory.getSubreport(this); 678 } 679 680 683 public void collectExpressions(JRExpressionCollector collector) 684 { 685 collector.collect(this); 686 } 687 688 691 public void writeXml(JRXmlWriter xmlWriter) throws IOException 692 { 693 xmlWriter.writeSubreport(this); 694 } 695 696 697 private JRFillSubreportReturnValue addReturnValue (JRSubreportReturnValue parentReturnValue, List returnValueList, JRFillObjectFactory factory) 698 { 699 JRFillSubreportReturnValue returnValue = factory.getSubreportReturnValue(parentReturnValue); 700 701 byte calculation = returnValue.getCalculation(); 702 switch (calculation) 703 { 704 case JRVariable.CALCULATION_AVERAGE: 705 case JRVariable.CALCULATION_VARIANCE: 706 { 707 JRSubreportReturnValue countVal = createHelperReturnValue(parentReturnValue, "_COUNT", JRVariable.CALCULATION_COUNT); 708 addReturnValue(countVal, returnValueList, factory); 709 710 JRSubreportReturnValue sumVal = createHelperReturnValue(parentReturnValue, "_SUM", JRVariable.CALCULATION_SUM); 711 addReturnValue(sumVal, returnValueList, factory); 712 713 filler.addVariableCalculationReq(returnValue.getToVariable(), calculation); 714 715 break; 716 } 717 case JRVariable.CALCULATION_STANDARD_DEVIATION: 718 { 719 JRSubreportReturnValue varianceVal = createHelperReturnValue(parentReturnValue, "_VARIANCE", JRVariable.CALCULATION_VARIANCE); 720 addReturnValue(varianceVal, returnValueList, factory); 721 722 filler.addVariableCalculationReq(returnValue.getToVariable(), calculation); 723 break; 724 } 725 case JRVariable.CALCULATION_DISTINCT_COUNT: 726 { 727 JRSubreportReturnValue countVal = createDistinctCountHelperReturnValue(parentReturnValue); 728 addReturnValue(countVal, returnValueList, factory); 729 730 filler.addVariableCalculationReq(returnValue.getToVariable(), calculation); 731 break; 732 } 733 } 734 735 returnValueList.add(returnValue); 736 return returnValue; 737 738 } 739 740 741 protected JRSubreportReturnValue createHelperReturnValue(JRSubreportReturnValue returnValue, String nameSuffix, byte calculation) 742 { 743 JRDesignSubreportReturnValue helper = new JRDesignSubreportReturnValue(); 744 helper.setToVariable(returnValue.getToVariable() + nameSuffix); 745 helper.setSubreportVariable(returnValue.getSubreportVariable()); 746 helper.setCalculation(calculation); 747 helper.setIncrementerFactoryClassName(helper.getIncrementerFactoryClassName()); 749 return helper; 750 } 751 752 753 protected JRSubreportReturnValue createDistinctCountHelperReturnValue(JRSubreportReturnValue returnValue) 754 { 755 JRDesignSubreportReturnValue helper = new JRDesignSubreportReturnValue(); 756 helper.setToVariable(returnValue.getToVariable() + "_DISTINCT_COUNT"); 757 helper.setSubreportVariable(returnValue.getSubreportVariable()); 758 helper.setCalculation(JRVariable.CALCULATION_NOTHING); 759 helper.setIncrementerFactoryClassName(helper.getIncrementerFactoryClassName()); 761 return helper; 762 } 763 764 765 public JRSubreportReturnValue[] getReturnValues() 766 { 767 return this.returnValues; 768 } 769 770 771 774 private void copyValues() 775 { 776 if (returnValues != null && returnValues.length > 0) 777 { 778 for (int i = 0; i < returnValues.length; i++) 779 { 780 try 781 { 782 JRFillVariable variable = filler.getVariable(returnValues[i].getToVariable()); 783 Object value = subreportFiller.getVariableValue(returnValues[i].getSubreportVariable()); 784 785 Object newValue = returnValues[i].getIncrementer().increment(variable, value, AbstractValueProvider.getCurrentValueProvider()); 786 variable.setOldValue(newValue); 787 variable.setValue(newValue); 788 } 789 catch (JRException e) 790 { 791 throw new JRRuntimeException(e); 792 } 793 } 794 } 795 } 796 797 798 803 private void checkReturnValues() throws JRException 804 { 805 if (returnValues != null && returnValues.length > 0 && !checkedReports.contains(jasperReport)) 806 { 807 for (int i = 0; i < returnValues.length; i++) 808 { 809 JRSubreportReturnValue returnValue = returnValues[i]; 810 String subreportVariableName = returnValue.getSubreportVariable(); 811 JRVariable subrepVariable = subreportFiller.getVariable(subreportVariableName); 812 if (subrepVariable == null) 813 { 814 throw new JRException("Subreport variable " + subreportVariableName + " not found."); 815 } 816 817 JRVariable variable = filler.getVariable(returnValue.getToVariable()); 818 if ( 819 returnValue.getCalculation() == JRVariable.CALCULATION_COUNT 820 || returnValue.getCalculation() == JRVariable.CALCULATION_DISTINCT_COUNT 821 ) 822 { 823 if (!Number .class.isAssignableFrom(variable.getValueClass())) 824 { 825 throw new JRException("Variable " + returnValue.getToVariable() + 826 " must have a numeric type."); 827 } 828 } 829 else if (!variable.getValueClass().isAssignableFrom(subrepVariable.getValueClass()) && 830 !(Number .class.isAssignableFrom(variable.getValueClass()) && Number .class.isAssignableFrom(subrepVariable.getValueClass()))) 831 { 832 throw new JRException("Variable " + returnValue.getToVariable() + 833 " is not assignable from subreport variable " + 834 subreportVariableName); 835 } 836 } 837 838 if (isUsingCache()) 839 checkedReports.add(jasperReport); 840 } 841 } 842 843 844 protected void resolveElement (JRPrintElement element, byte evaluation) 845 { 846 } 848 849 850 public Boolean isOwnUsingCache() 851 { 852 return ((JRSubreport)parent).isOwnUsingCache(); 853 } 854 855 856 public void setUsingCache(Boolean isUsingCache) 857 { 858 } 859 860 861 public JRCloneable createClone(JRFillCloneFactory factory) 862 { 863 return null; 865 } 866 867 protected static JRSubreportRunnerFactory getRunnerFactory() throws JRException 868 { 869 String factoryClassName = JRProperties.getProperty(JRProperties.SUBREPORT_RUNNER_FACTORY); 870 if (factoryClassName == null) 871 { 872 throw new JRException("Property \"" + JRProperties.SUBREPORT_RUNNER_FACTORY + "\" must be set"); 873 } 874 return (JRSubreportRunnerFactory) runnerFactoryCache.getCachedInstance(factoryClassName); 875 } 876 } 877 | Popular Tags |