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