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