1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts2.views.jasperreports;
22
23 import java.io.ByteArrayOutputStream;
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import javax.servlet.ServletContext;
30 import javax.servlet.ServletException;
31 import javax.servlet.ServletOutputStream;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34
35 import net.sf.jasperreports.engine.*;
36 import net.sf.jasperreports.engine.export.JRCsvExporter;
37 import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
38 import net.sf.jasperreports.engine.export.JRHtmlExporter;
39 import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
40 import net.sf.jasperreports.engine.export.JRXlsExporter;
41 import net.sf.jasperreports.engine.export.JRXmlExporter;
42 import net.sf.jasperreports.engine.util.JRLoader;
43
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46
47 import com.opensymphony.xwork2.util.TextUtils;
48 import org.apache.struts2.ServletActionContext;
49 import org.apache.struts2.dispatcher.StrutsResultSupport;
50 import com.opensymphony.xwork2.ActionInvocation;
51 import com.opensymphony.xwork2.util.ValueStack;
52
53 /***
54 * <!-- START SNIPPET: description -->
55 *
56 * Generates a JasperReports report using the specified format or PDF if no
57 * format is specified.
58 *
59 * <!-- END SNIPPET: description -->
60 * <p />
61 * <b>This result type takes the following parameters:</b>
62 *
63 * <!-- START SNIPPET: params -->
64 *
65 * <ul>
66 *
67 * <li><b>location (default)</b> - the location where the compiled jasper report
68 * definition is (foo.jasper), relative from current URL.</li>
69 *
70 * <li><b>dataSource (required)</b> - the EL expression used to retrieve the
71 * datasource from the value stack (usually a List).</li>
72 *
73 * <li><b>parse</b> - true by default. If set to false, the location param will
74 * not be parsed for EL expressions.</li>
75 *
76 * <li><b>format</b> - the format in which the report should be generated. Valid
77 * values can be found in {@link JasperReportConstants}. If no format is
78 * specified, PDF will be used.</li>
79 *
80 * <li><b>contentDisposition</b> - disposition (defaults to "inline", values are
81 * typically <i>filename="document.pdf"</i>).</li>
82 *
83 * <li><b>documentName</b> - name of the document (will generate the http header
84 * <code>Content-disposition = X; filename=X.[format]</code>).</li>
85 *
86 * <li><b>delimiter</b> - the delimiter used when generating CSV reports. By
87 * default, the character used is ",".</li>
88 *
89 * <li><b>imageServletUrl</b> - name of the url that, when prefixed with the
90 * context page, can return report images.</li>
91 *
92 * </ul>
93 *
94 * <p>
95 * This result follows the same rules from {@link StrutsResultSupport}.
96 * Specifically, all parameters will be parsed if the "parse" parameter is not
97 * set to false.
98 * </p>
99 * <!-- END SNIPPET: params -->
100 *
101 * <b>Example:</b>
102 *
103 * <pre><!-- START SNIPPET: example1 -->
104 * <result name="success" type="jasper">
105 * <param name="location">foo.jasper</param>
106 * <param name="dataSource">mySource</param>
107 * <param name="format">CSV</param>
108 * </result>
109 * <!-- END SNIPPET: example1 --></pre>
110 * or for pdf
111 * <pre><!-- START SNIPPET: example2 -->
112 * <result name="success" type="jasper">
113 * <param name="location">foo.jasper</param>
114 * <param name="dataSource">mySource</param>
115 * </result>
116 * <!-- END SNIPPET: example2 --></pre>
117 *
118 */
119 public class JasperReportsResult extends StrutsResultSupport implements JasperReportConstants {
120
121 private static final long serialVersionUID = -2523174799621182907L;
122
123
124 private final static Log LOG = LogFactory.getLog(JasperReportsResult.class);
125
126
127 protected String dataSource;
128 protected String format;
129 protected String documentName;
130 protected String contentDisposition;
131 protected String delimiter;
132 protected String imageServletUrl = "/images/";
133
134 public JasperReportsResult() {
135 super();
136 }
137
138 public JasperReportsResult(String location) {
139 super(location);
140 }
141
142 public String getImageServletUrl() {
143 return imageServletUrl;
144 }
145
146 public JasperReportsResult setImageServletUrl(final String imageServletUrl) {
147 this.imageServletUrl = imageServletUrl;
148 return this;
149 }
150
151 public JasperReportsResult setDataSource(String dataSource) {
152 this.dataSource = dataSource;
153 return this;
154 }
155
156 public JasperReportsResult setFormat(String format) {
157 this.format = format;
158 return this;
159 }
160
161 public JasperReportsResult setDocumentName(String documentName) {
162 this.documentName = documentName;
163 return this;
164 }
165
166 public JasperReportsResult setContentDisposition(String contentDisposition) {
167 this.contentDisposition = contentDisposition;
168 return this;
169 }
170
171 public JasperReportsResult setDelimiter(String delimiter) {
172 this.delimiter = delimiter;
173 return this;
174 }
175
176 protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
177 if (this.format == null) {
178 this.format = FORMAT_PDF;
179 }
180
181 if (dataSource == null) {
182 String message = "No dataSource specified...";
183 LOG.error(message);
184 throw new RuntimeException(message);
185 }
186
187 if (LOG.isDebugEnabled()) {
188 LOG.debug("Creating JasperReport for dataSource = " + dataSource + ", format = " + this.format);
189 }
190
191 HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().get(ServletActionContext.HTTP_REQUEST);
192 HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().get(ServletActionContext.HTTP_RESPONSE);
193
194
195 ValueStack stack = invocation.getStack();
196 ValueStackDataSource stackDataSource = new ValueStackDataSource(stack, dataSource);
197
198 format = conditionalParse(format, invocation);
199 dataSource = conditionalParse(dataSource, invocation);
200
201 if (contentDisposition != null) {
202 contentDisposition = conditionalParse(contentDisposition, invocation);
203 }
204
205 if (documentName != null) {
206 documentName = conditionalParse(documentName, invocation);
207 }
208
209
210 if (!TextUtils.stringSet(format)) {
211 format = FORMAT_PDF;
212 }
213
214 if (!"contype".equals(request.getHeader("User-Agent"))) {
215
216
217
218 ServletContext servletContext = (ServletContext) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONTEXT);
219 String systemId = servletContext.getRealPath(finalLocation);
220 Map parameters = new ValueStackShadowMap(stack);
221 File directory = new File(systemId.substring(0, systemId.lastIndexOf(File.separator)));
222 parameters.put("reportDirectory", directory);
223 parameters.put(JRParameter.REPORT_LOCALE, invocation.getInvocationContext().getLocale());
224
225 byte[] output;
226 JasperPrint jasperPrint;
227
228
229 try {
230 JasperReport jasperReport = (JasperReport) JRLoader.loadObject(systemId);
231
232 jasperPrint =
233 JasperFillManager.fillReport(jasperReport,
234 parameters,
235 stackDataSource);
236 } catch (JRException e) {
237 LOG.error("Error building report for uri " + systemId, e);
238 throw new ServletException(e.getMessage(), e);
239 }
240
241
242 try {
243 if (contentDisposition != null || documentName != null) {
244 final StringBuffer tmp = new StringBuffer();
245 tmp.append((contentDisposition == null) ? "inline" : contentDisposition);
246
247 if (documentName != null) {
248 tmp.append("; filename=");
249 tmp.append(documentName);
250 tmp.append(".");
251 tmp.append(format.toLowerCase());
252 }
253
254 response.setHeader("Content-disposition", tmp.toString());
255 }
256
257 if (format.equals(FORMAT_PDF)) {
258 response.setContentType("application/pdf");
259
260
261 output = JasperExportManager.exportReportToPdf(jasperPrint);
262 } else {
263 JRExporter exporter;
264
265 if (format.equals(FORMAT_CSV)) {
266 response.setContentType("text/plain");
267 exporter = new JRCsvExporter();
268 } else if (format.equals(FORMAT_HTML)) {
269 response.setContentType("text/html");
270
271
272
273 Map imagesMap = new HashMap();
274
275 request.getSession(true).setAttribute("IMAGES_MAP", imagesMap);
276 exporter = new JRHtmlExporter();
277 exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
278 exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + imageServletUrl);
279
280 exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
281 request.getSession().setAttribute("net.sf.jasperreports.j2ee.jasper_print", jasperPrint);
282
283 } else if (format.equals(FORMAT_XLS)) {
284 response.setContentType("application/vnd.ms-excel");
285 exporter = new JRXlsExporter();
286 } else if (format.equals(FORMAT_XML)) {
287 response.setContentType("text/xml");
288 exporter = new JRXmlExporter();
289 } else {
290 throw new ServletException("Unknown report format: " + format);
291 }
292
293 output = exportReportToBytes(jasperPrint, exporter);
294 }
295 } catch (JRException e) {
296 String message = "Error producing " + format + " report for uri " + systemId;
297 LOG.error(message, e);
298 throw new ServletException(e.getMessage(), e);
299 }
300
301 response.setContentLength(output.length);
302
303 ServletOutputStream ouputStream;
304
305 try {
306 ouputStream = response.getOutputStream();
307 ouputStream.write(output);
308 ouputStream.flush();
309 ouputStream.close();
310 } catch (IOException e) {
311 LOG.error("Error writing report output", e);
312 throw new ServletException(e.getMessage(), e);
313 }
314 } else {
315
316 try {
317 ServletOutputStream outputStream;
318 response.setContentType("application/pdf");
319 response.setContentLength(0);
320 outputStream = response.getOutputStream();
321 outputStream.close();
322 } catch (IOException e) {
323 LOG.error("Error writing report output", e);
324 throw new ServletException(e.getMessage(), e);
325 }
326 }
327 }
328
329 /***
330 * Run a Jasper report to CSV format and put the results in a byte array
331 *
332 * @param jasperPrint The Print object to render as CSV
333 * @param exporter The exporter to use to export the report
334 * @return A CSV formatted report
335 * @throws net.sf.jasperreports.engine.JRException
336 * If there is a problem running the report
337 */
338 private byte[] exportReportToBytes(JasperPrint jasperPrint, JRExporter exporter) throws JRException {
339 byte[] output;
340 ByteArrayOutputStream baos = new ByteArrayOutputStream();
341
342 exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
343 exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
344 if (delimiter != null) {
345 exporter.setParameter(JRCsvExporterParameter.FIELD_DELIMITER, delimiter);
346 }
347
348 exporter.exportReport();
349
350 output = baos.toByteArray();
351
352 return output;
353 }
354 }