Thanks. Much better now. I implemented a couple of small changes on top of it, please check out whether you agree (find the patch attached).
Eelco > > Matej Knopp wrote: > > Hi. > > > > There's a slight performace problem with JRResource, that it creates > > JasperReport in it's constructor. I've 10 resource links on one page so > > it means that 10 JasperReports will be initialized everytime page is > > created, even if none of them gets clicked. The performance penalty is > > not small - 400ms. > > So I think the JasperReport should be initialized lazyly, only when > > the resource is really used. > > I've atached "fixed" JRResource, it may not be the best solution, but > > it works for me. (Look in the constructor(s) to see how it works) > > > > -Matej > >
Index: src/java/wicket/contrib/jasperreports/JRResource.java =================================================================== RCS file: /cvsroot/wicket-stuff/wicket-contrib-jasperreports/src/java/wicket/contrib/jasperreports/JRResource.java,v retrieving revision 1.1 diff -u -r1.1 JRResource.java --- src/java/wicket/contrib/jasperreports/JRResource.java 20 Sep 2005 20:00:46 -0000 1.1 +++ src/java/wicket/contrib/jasperreports/JRResource.java 21 Nov 2005 18:36:46 -0000 @@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; +import java.io.Serializable; import java.net.URL; import java.sql.Connection; import java.util.Map; @@ -54,7 +55,7 @@ /** * Provides JDBC connection. */ - public static interface IDatabaseConnectionProvider + public static interface IDatabaseConnectionProvider extends Serializable { /** * Gets a JDBC connection to use when filling the report. @@ -70,8 +71,32 @@ void release(); } - /** the compiled report this resource references. */ - private JasperReport jasperReport; + /** + * Factory class for lazy initialization of the jasper report. + */ + private static interface JasperReportFactory extends Serializable + { + /** + * Create a jasper report instance. + * + * @return the new jasper report instance. + * @throws JRException + */ + JasperReport newJasperReport() throws JRException; + }; + + /** the connection provider if any for filling this report. */ + private IDatabaseConnectionProvider connectionProvider; + + /** factory for delayed report creation. */ + private JasperReportFactory jasperReportFactory; + + /** + * The compiled report this resource references. Made transient as we don't + * want our report to be serialized while we can recreate it at other + * servers at will using the factory. + */ + private transient JasperReport jasperReport; /** the report parameters. */ private Map reportParameters; @@ -79,9 +104,6 @@ /** the datasource if any for filling this report. */ private JRDataSource reportDataSource; - /** the connection provider if any for filling this report. */ - private IDatabaseConnectionProvider connectionProvider; - /** * When set, a header 'Content-Disposition: attachment; * filename="${fileName}"' will be added to the response, resulting in a @@ -106,18 +128,15 @@ * @param report * the report input stream */ - public JRResource(InputStream report) + public JRResource(final InputStream report) { - super(); - setCacheable(false); - try + this(new JasperReportFactory() { - jasperReport = (JasperReport) JRLoader.loadObject(report); - } - catch (JRException e) - { - throw new WicketRuntimeException(e); - } + public JasperReport newJasperReport() throws JRException + { + return (JasperReport) JRLoader.loadObject(report); + }; + }); } /** @@ -126,18 +145,15 @@ * @param report * the report input stream */ - public JRResource(URL report) + public JRResource(final URL report) { - super(); - setCacheable(false); - try - { - jasperReport = (JasperReport) JRLoader.loadObject(report); - } - catch (JRException e) + this(new JasperReportFactory() { - throw new WicketRuntimeException(e); - } + public JasperReport newJasperReport() throws JRException + { + return (JasperReport) JRLoader.loadObject(report); + }; + }); } /** @@ -146,27 +162,53 @@ * @param report * the report input stream */ - public JRResource(File report) + public JRResource(final File report) + { + this(new JasperReportFactory() + { + public JasperReport newJasperReport() throws JRException + { + return (JasperReport) JRLoader.loadObject(report); + }; + }); + } + + /** + * Construct. + * + * @param jasperReportFactory + * report factory for lazy initialization + */ + private JRResource(JasperReportFactory jasperReportFactory) { super(); setCacheable(false); - try - { - jasperReport = (JasperReport) JRLoader.loadObject(report); - } - catch (JRException e) - { - throw new WicketRuntimeException(e); - } + + this.jasperReportFactory = jasperReportFactory; } /** - * Gets jasperReport. + * Gets jasperReport. This implementation uses an internal factory to lazily + * create the report. After creation the report is cached (set as the + * jasperReport property). Override this method in case you want to provide + * some alternative creation/ caching scheme. * * @return jasperReport */ public JasperReport getJasperReport() { + // if the report has not yet been initialized and can be, initialize it + if (jasperReport == null && jasperReportFactory != null) + { + try + { + setJasperReport(jasperReportFactory.newJasperReport()); + } + catch (JRException e) + { + throw new WicketRuntimeException(e); + } + } return jasperReport; } @@ -282,6 +324,7 @@ /** * Called by getData to obtain an exporter instance. + * * @return an exporter instance */ protected abstract JRAbstractExporter newExporter(); @@ -337,6 +380,7 @@ protected JasperPrint newJasperPrint() throws JRException { final JasperPrint jasperPrint; + JasperReport jasperReport = getJasperReport(); Map reportParameters = getReportParameters(); JRDataSource reportDataSource = getReportDataSource(); @@ -385,4 +429,4 @@ } } -} +} \ No newline at end of file