001: /*
002: * Copyright (c) 2002-2005 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.webwork.views.jasperreports;
006:
007: import java.io.ByteArrayOutputStream;
008: import java.io.File;
009: import java.io.IOException;
010: import java.util.HashMap;
011: import java.util.Map;
012:
013: import javax.servlet.ServletContext;
014: import javax.servlet.ServletException;
015: import javax.servlet.ServletOutputStream;
016: import javax.servlet.http.HttpServletRequest;
017: import javax.servlet.http.HttpServletResponse;
018:
019: import net.sf.jasperreports.engine.*;
020: import net.sf.jasperreports.engine.export.JRCsvExporter;
021: import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
022: import net.sf.jasperreports.engine.export.JRHtmlExporter;
023: import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
024: import net.sf.jasperreports.engine.export.JRRtfExporter;
025: import net.sf.jasperreports.engine.export.JRXlsExporter;
026: import net.sf.jasperreports.engine.export.JRXmlExporter;
027: import net.sf.jasperreports.engine.util.JRLoader;
028:
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031:
032: import com.opensymphony.util.TextUtils;
033: import com.opensymphony.webwork.ServletActionContext;
034: import com.opensymphony.webwork.WebWorkException;
035: import com.opensymphony.webwork.dispatcher.WebWorkResultSupport;
036: import com.opensymphony.xwork.ActionInvocation;
037: import com.opensymphony.xwork.util.OgnlValueStack;
038:
039: /**
040: * <!-- START SNIPPET: description -->
041: *
042: * Generates a JasperReports report using the specified format or PDF if no
043: * format is specified.
044: *
045: * <!-- END SNIPPET: description -->
046: * <p />
047: * <b>This result type takes the following parameters:</b>
048: *
049: * <!-- START SNIPPET: params -->
050: *
051: * <ul>
052: *
053: * <li><b>location (default)</b> - the location where the compiled jasper report
054: * definition is (foo.jasper), relative from current URL.</li>
055: *
056: * <li><b>dataSource (required)</b> - the Ognl expression used to retrieve the
057: * datasource from the value stack (usually a List).</li>
058: *
059: * <li><b>parse</b> - true by default. If set to false, the location param will
060: * not be parsed for Ognl expressions.</li>
061: *
062: * <li><b>format</b> - the format in which the report should be generated. Valid
063: * values can be found in {@link JasperReportConstants}. If no format is
064: * specified, PDF will be used.</li>
065: *
066: * <li><b>contentDisposition</b> - disposition (defaults to "inline", values are
067: * typically <i>filename="document.pdf"</i>).</li>
068: *
069: * <li><b>documentName</b> - name of the document (will generate the http header
070: * <code>Content-disposition = X; filename=X.[format]</code>).</li>
071: *
072: * <li><b>delimiter</b> - the delimiter used when generating CSV reports. By
073: * default, the character used is ",".</li>
074: *
075: * <li><b>imageServletUrl</b> - name of the url that, when prefixed with the
076: * context page, can return report images.</li>
077: *
078: * </ul>
079: *
080: * <p>
081: * This result follows the same rules from {@link WebWorkResultSupport}.
082: * Specifically, all parameters will be parsed if the "parse" parameter is not
083: * set to false.
084: * </p>
085: * <!-- END SNIPPET: params -->
086: *
087: * <b>Example:</b>
088: *
089: * <pre><!-- START SNIPPET: example1 -->
090: * <result name="success" type="jasper">
091: * <param name="location">foo.jasper</param>
092: * <param name="dataSource">mySource</param>
093: * <param name="format">CSV</param>
094: * </result>
095: * <!-- END SNIPPET: example1 --></pre>
096: * or for pdf
097: * <pre><!-- START SNIPPET: example2 -->
098: * <result name="success" type="jasper">
099: * <param name="location">foo.jasper</param>
100: * <param name="dataSource">mySource</param>
101: * </result>
102: * <!-- END SNIPPET: example2 --></pre>
103: *
104: * @author Patrick Lightbody
105: * @author Rainer Hermanns
106: */
107: public class JasperReportsResult extends WebWorkResultSupport implements
108: JasperReportConstants {
109: private final static Log LOG = LogFactory
110: .getLog(JasperReportsResult.class);
111:
112: protected String dataSource;
113: protected String format;
114: protected String documentName;
115: protected String contentDisposition;
116: protected String delimiter;
117: protected String imageServletUrl = "/images/";
118:
119: public String getImageServletUrl() {
120: return imageServletUrl;
121: }
122:
123: public void setImageServletUrl(final String imageServletUrl) {
124: this .imageServletUrl = imageServletUrl;
125: }
126:
127: public void setDataSource(String dataSource) {
128: this .dataSource = dataSource;
129: }
130:
131: public void setFormat(String format) {
132: this .format = format;
133: }
134:
135: public void setDocumentName(String documentName) {
136: this .documentName = documentName;
137: }
138:
139: public void setContentDisposition(String contentDisposition) {
140: this .contentDisposition = contentDisposition;
141: }
142:
143: public void setDelimiter(String delimiter) {
144: this .delimiter = delimiter;
145: }
146:
147: protected void doExecute(String finalLocation,
148: ActionInvocation invocation) throws Exception {
149: if (this .format == null) {
150: this .format = FORMAT_PDF;
151: }
152:
153: if (dataSource == null) {
154: String message = "No dataSource specified...";
155: LOG.error(message);
156: throw new WebWorkException(message);
157: }
158:
159: if (LOG.isDebugEnabled()) {
160: LOG.debug("Creating JasperReport for dataSource = "
161: + dataSource + ", format = " + this .format);
162: }
163:
164: HttpServletRequest request = (HttpServletRequest) invocation
165: .getInvocationContext().get(
166: ServletActionContext.HTTP_REQUEST);
167: HttpServletResponse response = (HttpServletResponse) invocation
168: .getInvocationContext().get(
169: ServletActionContext.HTTP_RESPONSE);
170:
171: //construct the data source for the report
172: OgnlValueStack stack = invocation.getStack();
173: OgnlValueStackDataSource stackDataSource = new OgnlValueStackDataSource(
174: stack, dataSource);
175:
176: format = conditionalParse(format, invocation);
177: dataSource = conditionalParse(dataSource, invocation);
178:
179: if (contentDisposition != null) {
180: contentDisposition = conditionalParse(contentDisposition,
181: invocation);
182: }
183:
184: if (documentName != null) {
185: documentName = conditionalParse(documentName, invocation);
186: }
187:
188: // (Map) ActionContext.getContext().getSession().get("IMAGES_MAP");
189: if (!TextUtils.stringSet(format)) {
190: format = FORMAT_PDF;
191: }
192:
193: if (!"contype".equals(request.getHeader("User-Agent"))) {
194: // Determine the directory that the report file is in and set the reportDirectory parameter
195: // For WW 2.1.7:
196: // ServletContext servletContext = ((ServletConfig) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONFIG)).getServletContext();
197: ServletContext servletContext = (ServletContext) invocation
198: .getInvocationContext().get(
199: ServletActionContext.SERVLET_CONTEXT);
200: String systemId = servletContext.getRealPath(finalLocation);
201: Map parameters = new OgnlValueStackShadowMap(stack);
202: File directory = new File(systemId.substring(0, systemId
203: .lastIndexOf(File.separator)));
204: parameters.put("reportDirectory", directory);
205: parameters.put(JRParameter.REPORT_LOCALE, invocation
206: .getInvocationContext().getLocale());
207:
208: byte[] output;
209: JasperPrint jasperPrint;
210:
211: // Fill the report and produce a print object
212: try {
213: JasperReport jasperReport = (JasperReport) JRLoader
214: .loadObject(systemId);
215:
216: jasperPrint = JasperFillManager.fillReport(
217: jasperReport, parameters, stackDataSource);
218: } catch (JRException e) {
219: LOG.error("Error building report for uri " + systemId,
220: e);
221: throw new ServletException(e.getMessage(), e);
222: }
223:
224: // Export the print object to the desired output format
225: try {
226: if (contentDisposition != null || documentName != null) {
227: final StringBuffer tmp = new StringBuffer();
228: tmp.append((contentDisposition == null) ? "inline"
229: : contentDisposition);
230:
231: if (documentName != null) {
232: tmp.append("; filename=");
233: tmp.append(documentName);
234: tmp.append(".");
235: tmp.append(format.toLowerCase());
236: }
237:
238: response.setHeader("Content-disposition", tmp
239: .toString());
240: }
241:
242: if (format.equals(FORMAT_PDF)) {
243: response.setContentType("application/pdf");
244:
245: // response.setHeader("Content-disposition", "inline; filename=report.pdf");
246: output = JasperExportManager
247: .exportReportToPdf(jasperPrint);
248: } else {
249: JRExporter exporter;
250:
251: if (format.equals(FORMAT_CSV)) {
252: response.setContentType("text/plain");
253: exporter = new JRCsvExporter();
254: } else if (format.equals(FORMAT_HTML)) {
255: response.setContentType("text/html");
256:
257: // IMAGES_MAPS seems to be only supported as "backward compatible" from JasperReports 1.1.0
258:
259: Map imagesMap = new HashMap();
260:
261: request.getSession(true).setAttribute(
262: "IMAGES_MAP", imagesMap);
263: exporter = new JRHtmlExporter();
264: exporter.setParameter(
265: JRHtmlExporterParameter.IMAGES_MAP,
266: imagesMap);
267: exporter.setParameter(
268: JRHtmlExporterParameter.IMAGES_URI,
269: request.getContextPath()
270: + imageServletUrl);
271: // Needed to support chart images:
272: exporter.setParameter(
273: JRExporterParameter.JASPER_PRINT,
274: jasperPrint);
275: request
276: .getSession()
277: .setAttribute(
278: "net.sf.jasperreports.j2ee.jasper_print",
279: jasperPrint);
280:
281: } else if (format.equals(FORMAT_XLS)) {
282: response
283: .setContentType("application/vnd.ms-excel");
284: exporter = new JRXlsExporter();
285: } else if (format.equals(FORMAT_XML)) {
286: response.setContentType("text/xml");
287: exporter = new JRXmlExporter();
288: } else if (format.equals(FORMAT_RTF)) {
289: response.setContentType("application/rtf");
290: exporter = new JRRtfExporter();
291: } else {
292: throw new ServletException(
293: "Unknown report format: " + format);
294: }
295:
296: output = exportReportToBytes(jasperPrint, exporter);
297: }
298: } catch (JRException e) {
299: String message = "Error producing " + format
300: + " report for uri " + systemId;
301: LOG.error(message, e);
302: throw new ServletException(e.getMessage(), e);
303: }
304:
305: response.setContentLength(output.length);
306:
307: ServletOutputStream ouputStream;
308:
309: try {
310: ouputStream = response.getOutputStream();
311: ouputStream.write(output);
312: ouputStream.flush();
313: ouputStream.close();
314: } catch (IOException e) {
315: LOG.error("Error writing report output", e);
316: throw new ServletException(e.getMessage(), e);
317: }
318: } else {
319: // Code to handle "contype" request from IE
320: try {
321: ServletOutputStream outputStream;
322: response.setContentType("application/pdf");
323: response.setContentLength(0);
324: outputStream = response.getOutputStream();
325: outputStream.close();
326: } catch (IOException e) {
327: LOG.error("Error writing report output", e);
328: throw new ServletException(e.getMessage(), e);
329: }
330: }
331: }
332:
333: /**
334: * Run a Jasper report to CSV format and put the results in a byte array
335: *
336: * @param jasperPrint The Print object to render as CSV
337: * @param exporter The exporter to use to export the report
338: * @return A CSV formatted report
339: * @throws net.sf.jasperreports.engine.JRException
340: * If there is a problem running the report
341: */
342: private byte[] exportReportToBytes(JasperPrint jasperPrint,
343: JRExporter exporter) throws JRException {
344: byte[] output;
345: ByteArrayOutputStream baos = new ByteArrayOutputStream();
346:
347: exporter.setParameter(JRExporterParameter.JASPER_PRINT,
348: jasperPrint);
349: exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
350: if (delimiter != null) {
351: exporter.setParameter(
352: JRCsvExporterParameter.FIELD_DELIMITER, delimiter);
353: }
354:
355: exporter.exportReport();
356:
357: output = baos.toByteArray();
358:
359: return output;
360: }
361: }
|