| Method from org.springframework.web.servlet.view.jasperreports.AbstractJasperReportsView Detail: |
protected final void convertExporterParameters() {
if (!CollectionUtils.isEmpty(this.exporterParameters)) {
this.convertedExporterParameters = new HashMap(this.exporterParameters.size());
for (Iterator it = this.exporterParameters.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
JRExporterParameter exporterParameter = getExporterParameter(entry.getKey());
this.convertedExporterParameters.put(
exporterParameter, convertParameterValue(exporterParameter, entry.getValue()));
}
}
}
Converts the exporter parameters passed in by the user which may be keyed
by Strings corresponding to the fully qualified name of the
JRExporterParameter into parameters which are keyed by
JRExporterParameter. |
protected Object convertParameterValue(JRExporterParameter parameter,
Object value) {
if (value instanceof String) {
String str = (String) value;
if ("true".equals(str)) {
return Boolean.TRUE;
}
else if ("false".equals(str)) {
return Boolean.FALSE;
}
else if (str.length() > 0 && Character.isDigit(str.charAt(0))) {
// Looks like a number... let's try.
try {
return new Integer(str);
}
catch (NumberFormatException ex) {
// OK, then let's keep it as a String value.
return str;
}
}
}
return value;
}
Convert the supplied parameter value into the actual type required by the
corresponding JRExporterParameter .
The default implementation simply converts the String values "true" and
"false" into corresponding Boolean objects, and tries to convert
String values that start with a digit into Integer objects
(simply keeping them as String if number conversion fails). |
protected JRDataSource convertReportData(Object value) throws IllegalArgumentException {
if (value instanceof JRDataSourceProvider) {
return createReport((JRDataSourceProvider) value);
}
else {
return JasperReportsUtils.convertReportData(value);
}
}
Convert the given report data value to a JRDataSource.
The default implementation delegates to JasperReportUtils unless
the report data value is an instance of JRDataSourceProvider.
A JRDataSource, JRDataSourceProvider,
java.util.Collection or object array is detected.
JRDataSources are returned as is, whilst JRDataSourceProviders
are used to create an instance of JRDataSource which is then returned.
The latter two are converted to JRBeanCollectionDataSource or
JRBeanArrayDataSource, respectively. |
protected JRExporterParameter convertToExporterParameter(String fqFieldName) {
int index = fqFieldName.lastIndexOf('.");
if (index == -1 || index == fqFieldName.length()) {
throw new IllegalArgumentException(
"Parameter name [" + fqFieldName + "] is not a valid static field. " +
"The parameter name must map to a static field such as " +
"[net.sf.jasperreports.engine.export.JRHtmlExporterParameter.IMAGES_URI]");
}
String className = fqFieldName.substring(0, index);
String fieldName = fqFieldName.substring(index + 1);
try {
Class cls = ClassUtils.forName(className);
Field field = cls.getField(fieldName);
if (JRExporterParameter.class.isAssignableFrom(field.getType())) {
try {
return (JRExporterParameter) field.get(null);
}
catch (IllegalAccessException ex) {
throw new IllegalArgumentException(
"Unable to access field [" + fieldName + "] of class [" + className + "]. " +
"Check that it is static and accessible.");
}
}
else {
throw new IllegalArgumentException("Field [" + fieldName + "] on class [" + className +
"] is not assignable from JRExporterParameter - check the type of this field.");
}
}
catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(
"Class [" + className + "] in key [" + fqFieldName + "] could not be found.");
}
catch (NoSuchFieldException ex) {
throw new IllegalArgumentException("Field [" + fieldName + "] in key [" + fqFieldName +
"] could not be found on class [" + className + "].");
}
}
Convert the given fully qualified field name to a corresponding
JRExporterParameter instance. |
protected JRDataSource createReport(JRDataSourceProvider provider) {
try {
JasperReport report = getReport();
if (report == null) {
throw new IllegalStateException("No main report defined for JRDataSourceProvider - " +
"specify a 'url' on this view or override 'getReport()'");
}
return provider.create(report);
}
catch (JRException ex) {
IllegalArgumentException iaex = new IllegalArgumentException("Supplied JRDataSourceProvider is invalid");
iaex.initCause(ex);
throw iaex;
}
}
Create a report using the given provider. |
protected void exposeLocalizationContext(Map model,
HttpServletRequest request) {
RequestContext rc = new RequestContext(request, getServletContext());
model.put(JRParameter.REPORT_LOCALE, rc.getLocale());
JasperReport report = getReport();
if (report == null || report.getResourceBundle() == null) {
model.put(JRParameter.REPORT_RESOURCE_BUNDLE,
new MessageSourceResourceBundle(rc.getMessageSource(), rc.getLocale()));
}
}
Expose current Spring-managed Locale and MessageSource to JasperReports i18n
($R expressions etc). The MessageSource should only be exposed as JasperReports
resource bundle if no such bundle is defined in the report itself.
Default implementation exposes the Spring RequestContext Locale and a
MessageSourceResourceBundle adapter for the Spring ApplicationContext,
analogous to the JstlUtils.exposeLocalizationContext method. |
protected JasperPrint fillReport(Map model) throws Exception {
// Determine main report.
JasperReport report = getReport();
if (report == null) {
throw new IllegalStateException("No main report defined for 'fillReport' - " +
"specify a 'url' on this view or override 'getReport()' or 'fillReport(Map)'");
}
JRDataSource jrDataSource = null;
DataSource jdbcDataSourceToUse = null;
// Try model attribute with specified name.
if (this.reportDataKey != null) {
Object reportDataValue = model.get(this.reportDataKey);
if (reportDataValue instanceof DataSource) {
jdbcDataSourceToUse = (DataSource) reportDataValue;
}
else {
jrDataSource = convertReportData(reportDataValue);
}
}
else {
Collection values = model.values();
jrDataSource = (JRDataSource) CollectionUtils.findValueOfType(values, JRDataSource.class);
if (jrDataSource == null) {
JRDataSourceProvider provider =
(JRDataSourceProvider) CollectionUtils.findValueOfType(values, JRDataSourceProvider.class);
if (provider != null) {
jrDataSource = createReport(provider);
}
else {
jdbcDataSourceToUse = (DataSource) CollectionUtils.findValueOfType(values, DataSource.class);
if (jdbcDataSourceToUse == null) {
jdbcDataSourceToUse = this.jdbcDataSource;
}
}
}
}
if (jdbcDataSourceToUse != null) {
return doFillReport(report, model, jdbcDataSourceToUse);
}
else {
// Determine JRDataSource for main report.
if (jrDataSource == null) {
jrDataSource = getReportData(model);
}
if (jrDataSource != null) {
// Use the JasperReports JRDataSource.
if (logger.isDebugEnabled()) {
logger.debug("Filling report with JRDataSource [" + jrDataSource + "]");
}
return JasperFillManager.fillReport(report, model, jrDataSource);
}
else {
// Assume that the model contains parameters that identify
// the source for report data (e.g. Hibernate or JPA queries).
logger.debug("Filling report with plain model");
return JasperFillManager.fillReport(report, model);
}
}
}
Create a populated JasperPrint instance from the configured
JasperReport instance.
By default, thois method will use any JRDataSource instance
(or wrappable Object) that can be located using #getReportData .
If no JRDataSource can be found, this method will use a JDBC
Connection obtained from the configured javax.sql.DataSource
(or a DataSource attribute in the model). If no JDBC DataSource can be found
either, the JasperReports engine will be invoked with plain model Map,
assuming that the model contains parameters that identify the source
for report data (e.g. Hibernate or JPA queries). |
protected Map getConvertedExporterParameters() {
return this.convertedExporterParameters;
}
Allows subclasses to retrieve the converted exporter parameters. |
protected JRExporterParameter getExporterParameter(Object parameter) {
if (parameter instanceof JRExporterParameter) {
return (JRExporterParameter) parameter;
}
if (parameter instanceof String) {
return convertToExporterParameter((String) parameter);
}
throw new IllegalArgumentException(
"Parameter [" + parameter + "] is invalid type. Should be either String or JRExporterParameter.");
}
Return a JRExporterParameter for the given parameter object,
converting it from a String if necessary. |
public Map getExporterParameters() {
return this.exporterParameters;
}
Return the exporter parameters that this view uses, if any. |
protected DataSource getJdbcDataSource() {
return this.jdbcDataSource;
}
Return the javax.sql.DataSource that this view uses, if any. |
protected JasperReport getReport() {
return this.report;
}
Determine the JasperReport to fill.
Called by #fillReport .
The default implementation returns the report as statically configured
through the 'url' property (and loaded by #loadReport() ).
Can be overridden in subclasses in order to dynamically obtain a
JasperReport instance. As an alternative, consider
overriding the #fillReport template method itself. |
protected JRCompiler getReportCompiler() {
return this.reportCompiler;
}
Return the JRCompiler instance to use for compiling ".jrxml" report files. |
protected JRDataSource getReportData(Map model) {
// Try to find matching attribute, of given prioritized types.
Object value = CollectionUtils.findValueOfType(model.values(), getReportDataTypes());
return (value != null ? convertReportData(value) : null);
}
Find an instance of JRDataSource in the given model map or create an
appropriate JRDataSource for passed-in report data.
The default implementation checks for a model object under the
specified "reportDataKey" first, then falls back to looking for a value
of type JRDataSource, java.util.Collection,
object array (in that order). |
protected Class[] getReportDataTypes() {
return new Class[] {Collection.class, Object[].class};
}
|
protected final void initApplicationContext() throws ApplicationContextException {
this.report = loadReport();
// Load sub reports if required, and check data source parameters.
if (this.subReportUrls != null) {
if (this.subReportDataKeys != null && this.subReportDataKeys.length > 0 && this.reportDataKey == null) {
throw new ApplicationContextException(
"'reportDataKey' for main report is required when specifying a value for 'subReportDataKeys'");
}
this.subReports = new HashMap(this.subReportUrls.size());
for (Enumeration urls = this.subReportUrls.propertyNames(); urls.hasMoreElements();) {
String key = (String) urls.nextElement();
String path = this.subReportUrls.getProperty(key);
Resource resource = getApplicationContext().getResource(path);
this.subReports.put(key, loadReport(resource));
}
}
// Convert user-supplied exporterParameters.
convertExporterParameters();
if (this.headers == null) {
this.headers = new Properties();
}
if (!this.headers.containsKey(HEADER_CONTENT_DISPOSITION)) {
this.headers.setProperty(HEADER_CONTENT_DISPOSITION, CONTENT_DISPOSITION_INLINE);
}
onInit();
}
|
protected boolean isUrlRequired() {
return false;
}
JasperReports views do not strictly required a 'url' value.
Alternatively, the #getReport() template method may be overridden. |
protected JasperReport loadReport() {
String url = getUrl();
if (url == null) {
return null;
}
Resource mainReport = getApplicationContext().getResource(url);
return loadReport(mainReport);
}
Load the main JasperReport from the specified Resource.
If the Resource points to an uncompiled report design file then the
report file is compiled dynamically and loaded into memory. |
protected final JasperReport loadReport(Resource resource) {
try {
String fileName = resource.getFilename();
if (fileName.endsWith(".jasper")) {
// Load pre-compiled report.
if (logger.isInfoEnabled()) {
logger.info("Loading pre-compiled Jasper Report from " + resource);
}
return (JasperReport) JRLoader.loadObject(resource.getInputStream());
}
else if (fileName.endsWith(".jrxml")) {
// Compile report on-the-fly.
if (logger.isInfoEnabled()) {
logger.info("Compiling Jasper Report loaded from " + resource);
}
JasperDesign design = JRXmlLoader.load(resource.getInputStream());
return getReportCompiler().compileReport(design);
}
else {
throw new IllegalArgumentException(
"Report filename [" + fileName + "] must end in either .jasper or .jrxml");
}
}
catch (IOException ex) {
throw new ApplicationContextException(
"Could not load JasperReports report from " + resource, ex);
}
catch (JRException ex) {
throw new ApplicationContextException(
"Could not parse JasperReports report from " + resource, ex);
}
}
Loads a JasperReport from the specified Resource.
If the Resource points to an uncompiled report design file then
the report file is compiled dynamically and loaded into memory. |
protected void onInit() {
}
Subclasses can override this to add some custom initialization logic. Called
by #initApplicationContext() as soon as all standard initialization logic
has finished executing. |
protected void postProcessReport(JasperPrint populatedReport,
Map model) throws Exception {
}
|
protected void renderMergedOutputModel(Map model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (this.subReports != null) {
// Expose sub-reports as model attributes.
model.putAll(this.subReports);
// Transform any collections etc into JRDataSources for sub reports.
if (this.subReportDataKeys != null) {
for (int i = 0; i < this.subReportDataKeys.length; i++) {
String key = this.subReportDataKeys[i];
model.put(key, convertReportData(model.get(key)));
}
}
}
// Expose Spring-managed Locale and MessageSource.
exposeLocalizationContext(model, request);
// Fill the report.
JasperPrint filledReport = fillReport(model);
postProcessReport(filledReport, model);
// Prepare response and render report.
populateHeaders(response);
renderReport(filledReport, model, response);
}
Finds the report data to use for rendering the report and then invokes the
renderReport method that should be implemented by the subclass. |
abstract protected void renderReport(JasperPrint populatedReport,
Map model,
HttpServletResponse response) throws Exception
Subclasses should implement this method to perform the actual rendering process.
Note that the content type has not been set yet: Implementors should build
a content type String and set it via response.setContentType.
If necessary, this can include a charset clause for a specific encoding.
The latter will only be necessary for textual output onto a Writer, and only
in case of the encoding being specified in the JasperReports exporter parameters.
WARNING: Implementors should not use response.setCharacterEncoding
unless they are willing to depend on Servlet API 2.4 or higher. Prefer a
concatenated content type String with a charset clause instead. |
public void setExporterParameters(Map parameters) {
// NOTE: Removed conversion from here since configuration of parameters
// can also happen through access to the underlying Map using
// getExporterParameters(). Conversion now happens in initApplicationContext,
// and subclasses use getConvertedExporterParameters() to access the converted
// parameter Map - robh.
this.exporterParameters = parameters;
}
Set the exporter parameters that should be used when rendering a view. |
public void setHeaders(Properties headers) {
this.headers = headers;
}
Specify the set of headers that are included in each of response. |
public void setJdbcDataSource(DataSource jdbcDataSource) {
this.jdbcDataSource = jdbcDataSource;
}
Specify the javax.sql.DataSource to use for reports with
embedded SQL statements. |
public void setReportCompiler(JRCompiler reportCompiler) {
this.reportCompiler = (reportCompiler != null ? reportCompiler : JRDefaultCompiler.getInstance());
}
Specify the JRCompiler implementation to use for compiling a ".jrxml"
report file on-the-fly into a report class.
By default, a JRDefaultCompiler will be used, delegating to the
Eclipse JDT compiler or the Sun JDK compiler underneath. |
public void setReportDataKey(String reportDataKey) {
this.reportDataKey = reportDataKey;
}
Set the name of the model attribute that represents the report data.
If not specified, the model map will be searched for a matching value type.
A JRDataSource will be taken as-is. For other types, conversion
will apply: By default, a java.util.Collection will be converted
to JRBeanCollectionDataSource, and an object array to
JRBeanArrayDataSource.
Note: If you pass in a Collection or object array in the model map
for use as plain report parameter, rather than as report data to extract fields
from, you need to specify the key for the actual report data to use, to avoid
mis-detection of report data by type. |
public void setSubReportDataKeys(String[] subReportDataKeys) {
this.subReportDataKeys = subReportDataKeys;
}
Set the list of names corresponding to the model parameters that will contain
data source objects for use in sub-reports. Spring will convert these objects
to instances of JRDataSource where applicable and will then
include the resulting JRDataSource in the parameters passed into
the JasperReports engine.
The name specified in the list should correspond to an attribute in the
model Map, and to a sub-report data source parameter in your report file.
If you pass in JRDataSource objects as model attributes,
specifing this list of keys is not required.
If you specify a list of sub-report data keys, it is required to also
specify a reportDataKey for the main report, to avoid confusion
between the data source objects for the various reports involved. |
public void setSubReportUrls(Properties subReports) {
this.subReportUrls = subReports;
}
Specify resource paths which must be loaded as instances of
JasperReport and passed to the JasperReports engine for
rendering as sub-reports, under the same keys as in this mapping. |