001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.web.servlet.view.jasperreports;
018:
019: import java.io.ByteArrayOutputStream;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.Map;
023:
024: import javax.servlet.ServletOutputStream;
025: import javax.servlet.http.HttpServletResponse;
026:
027: import net.sf.jasperreports.engine.JRExporter;
028: import net.sf.jasperreports.engine.JRExporterParameter;
029: import net.sf.jasperreports.engine.JasperPrint;
030:
031: import org.springframework.ui.jasperreports.JasperReportsUtils;
032: import org.springframework.util.CollectionUtils;
033: import org.springframework.web.util.WebUtils;
034:
035: /**
036: * Extends <code>AbstractJasperReportsView</code> to provide basic rendering logic
037: * for views that use a fixed format, e.g. always PDF or always HTML.
038: *
039: * <p>Subclasses need to implement two template methods: <code>createExporter</code>
040: * to create a JasperReports exporter for a specific output format, and
041: * <code>useWriter</code> to determine whether to write text or binary content.
042: *
043: * @author Rob Harrop
044: * @author Juergen Hoeller
045: * @since 1.1.5
046: * @see #createExporter()
047: * @see #useWriter()
048: */
049: public abstract class AbstractJasperReportsSingleFormatView extends
050: AbstractJasperReportsView {
051:
052: /**
053: * Initial size for the output array.
054: */
055: private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 4096;
056:
057: /**
058: * Perform rendering for a single Jasper Reports exporter, that is,
059: * for a pre-defined output format.
060: */
061: protected void renderReport(JasperPrint populatedReport, Map model,
062: HttpServletResponse response) throws Exception {
063:
064: // Prepare report for rendering.
065: JRExporter exporter = createExporter();
066:
067: // Set exporter parameters - overriding with values from the Model.
068: Map mergedExporterParameters = mergeExporterParameters(model);
069: if (!CollectionUtils.isEmpty(mergedExporterParameters)) {
070: exporter.setParameters(mergedExporterParameters);
071: }
072:
073: if (useWriter()) {
074: // We need to write text to the response Writer.
075:
076: // Copy the encoding configured for the report into the response.
077: String contentType = getContentType();
078: String encoding = (String) exporter
079: .getParameter(JRExporterParameter.CHARACTER_ENCODING);
080: if (encoding != null) {
081: // Only apply encoding if content type is specified but does not contain charset clause already.
082: if (contentType != null
083: && contentType.toLowerCase().indexOf(
084: WebUtils.CONTENT_TYPE_CHARSET_PREFIX) == -1) {
085: contentType = contentType
086: + WebUtils.CONTENT_TYPE_CHARSET_PREFIX
087: + encoding;
088: }
089: }
090: response.setContentType(contentType);
091:
092: // Render report into HttpServletResponse's Writer.
093: JasperReportsUtils.render(exporter, populatedReport,
094: response.getWriter());
095: }
096:
097: else {
098: // We need to write binary output to the response OutputStream.
099:
100: // Apply the content type as specified - we don't need an encoding here.
101: response.setContentType(getContentType());
102:
103: // Render report into local OutputStream.
104: // IE workaround: write into byte array first.
105: ByteArrayOutputStream baos = new ByteArrayOutputStream(
106: OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
107: JasperReportsUtils.render(exporter, populatedReport, baos);
108:
109: // Write content length (determined via byte array).
110: response.setContentLength(baos.size());
111:
112: // Flush byte array to servlet output stream.
113: ServletOutputStream out = response.getOutputStream();
114: baos.writeTo(out);
115: out.flush();
116: }
117: }
118:
119: /**
120: * Merges the configured JRExporterParameters with any specified in the supplied model data.
121: * JRExporterParameters in the model override those specified in the configuration.
122: * @see #setExporterParameters(java.util.Map)
123: */
124: protected Map mergeExporterParameters(Map model) {
125: Map mergedParameters = new HashMap();
126: Map convertedExporterParameters = getConvertedExporterParameters();
127: if (!CollectionUtils.isEmpty(convertedExporterParameters)) {
128: mergedParameters.putAll(convertedExporterParameters);
129: }
130: for (Iterator it = model.keySet().iterator(); it.hasNext();) {
131: Object key = it.next();
132: if (key instanceof JRExporterParameter) {
133: Object value = model.get(key);
134: if (value instanceof String) {
135: mergedParameters.put(key, value);
136: } else {
137: if (logger.isWarnEnabled()) {
138: logger.warn("Ignoring exporter parameter ["
139: + key + "]: value is not a String");
140: }
141: }
142: }
143: }
144: return mergedParameters;
145: }
146:
147: /**
148: * Create a JasperReports exporter for a specific output format,
149: * which will be used to render the report to the HTTP response.
150: * <p>The <code>useWriter</code> method determines whether the
151: * output will be written as text or as binary content.
152: * @see #useWriter()
153: */
154: protected abstract JRExporter createExporter();
155:
156: /**
157: * Return whether to use a <code>java.io.Writer</code> to write text content
158: * to the HTTP response. Else, a <code>java.io.OutputStream</code> will be used,
159: * to write binary content to the response.
160: * @see javax.servlet.ServletResponse#getWriter()
161: * @see javax.servlet.ServletResponse#getOutputStream()
162: */
163: protected abstract boolean useWriter();
164:
165: }
|