Save This Page
Home » struts-2.1.8.1-src » org.apache » struts2 » views » jasperreports » [javadoc | source]
    1   /*
    2    * $Id: JasperReportsResult.java 767507 2009-04-22 13:09:32Z hermanns $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
   10    * with the License.  You may obtain a copy of the License at
   11    *
   12    *  http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing,
   15    * software distributed under the License is distributed on an
   16    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   17    * KIND, either express or implied.  See the License for the
   18    * specific language governing permissions and limitations
   19    * under the License.
   20    */
   21   
   22   package org.apache.struts2.views.jasperreports;
   23   
   24   import java.io.ByteArrayOutputStream;
   25   import java.io.File;
   26   import java.io.IOException;
   27   import java.util.HashMap;
   28   import java.util.Map;
   29   import java.util.TimeZone;
   30   import java.sql.Connection;
   31   
   32   import javax.servlet.ServletContext;
   33   import javax.servlet.ServletException;
   34   import javax.servlet.ServletOutputStream;
   35   import javax.servlet.http.HttpServletRequest;
   36   import javax.servlet.http.HttpServletResponse;
   37   
   38   import net.sf.jasperreports.engine.JRException;
   39   import net.sf.jasperreports.engine.JRExporter;
   40   import net.sf.jasperreports.engine.JRExporterParameter;
   41   import net.sf.jasperreports.engine.JRParameter;
   42   import net.sf.jasperreports.engine.JasperFillManager;
   43   import net.sf.jasperreports.engine.JasperPrint;
   44   import net.sf.jasperreports.engine.JasperReport;
   45   import net.sf.jasperreports.engine.export.JRCsvExporter;
   46   import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
   47   import net.sf.jasperreports.engine.export.JRHtmlExporter;
   48   import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
   49   import net.sf.jasperreports.engine.export.JRPdfExporter;
   50   import net.sf.jasperreports.engine.export.JRRtfExporter;
   51   import net.sf.jasperreports.engine.export.JRXlsExporter;
   52   import net.sf.jasperreports.engine.export.JRXmlExporter;
   53   import net.sf.jasperreports.engine.util.JRLoader;
   54   
   55   import org.apache.struts2.ServletActionContext;
   56   import org.apache.struts2.dispatcher.StrutsResultSupport;
   57   import org.apache.commons.lang.xwork.StringUtils;
   58   
   59   import com.opensymphony.xwork2.ActionInvocation;
   60   import com.opensymphony.xwork2.util.ValueStack;
   61   import com.opensymphony.xwork2.util.logging.Logger;
   62   import com.opensymphony.xwork2.util.logging.LoggerFactory;
   63   
   64   /**
   65    * <!-- START SNIPPET: description -->
   66    * <p/>
   67    * Generates a JasperReports report using the specified format or PDF if no
   68    * format is specified.
   69    * <p/>
   70    * <!-- END SNIPPET: description -->
   71    * <p />
   72    * <b>This result type takes the following parameters:</b>
   73    * <p/>
   74    * <!-- START SNIPPET: params -->
   75    * <p/>
   76    * <ul>
   77    * <p/>
   78    * <li><b>location (default)</b> - the location where the compiled jasper report
   79    * definition is (foo.jasper), relative from current URL.</li>
   80    * <p/>
   81    * <li><b>dataSource (required)</b> - the EL expression used to retrieve the
   82    * datasource from the value stack (usually a List).</li>
   83    * <p/>
   84    * <li><b>parse</b> - true by default. If set to false, the location param will
   85    * not be parsed for EL expressions.</li>
   86    * <p/>
   87    * <li><b>format</b> - the format in which the report should be generated. Valid
   88    * values can be found in {@link JasperReportConstants}. If no format is
   89    * specified, PDF will be used.</li>
   90    * <p/>
   91    * <li><b>contentDisposition</b> - disposition (defaults to "inline", values are
   92    * typically <i>filename="document.pdf"</i>).</li>
   93    * <p/>
   94    * <li><b>documentName</b> - name of the document (will generate the http header
   95    * <code>Content-disposition = X; filename=X.[format]</code>).</li>
   96    * <p/>
   97    * <li><b>delimiter</b> - the delimiter used when generating CSV reports. By
   98    * default, the character used is ",".</li>
   99    * <p/>
  100    * <li><b>imageServletUrl</b> - name of the url that, when prefixed with the
  101    * context page, can return report images.</li>
  102    * <p/>
  103    * <li>
  104    * <b>reportParameters</b> - (2.1.2+) OGNL expression used to retrieve a map of
  105    * report parameters from the value stack. The parameters may be accessed
  106    * in the report via the usual JR mechanism and might include data not
  107    * part of the dataSource, such as the user name of the report creator, etc.
  108    * </li>
  109    * <p/>
  110    * <li>
  111    * <b>exportParameters</b> - (2.1.2+) OGNL expression used to retrieve a map of
  112    * JR exporter parameters from the value stack. The export parameters are
  113    * used to customize the JR export. For example, a PDF export might enable
  114    * encryption and set the user password to a string known to the report creator.
  115    * </li>
  116    * <p/>
  117    * <li>
  118    * <b>connection</b> - (2.1.7+) JDBC Connection which can be passed to the
  119    * report instead of dataSource
  120    * </li>
  121    * <p/>
  122    * </ul>
  123    * <p/>
  124    * <p>
  125    * This result follows the same rules from {@link StrutsResultSupport}.
  126    * Specifically, all parameters will be parsed if the "parse" parameter
  127    * is not set to false.
  128    * </p>
  129    * <!-- END SNIPPET: params -->
  130    * <p/>
  131    * <b>Example:</b>
  132    * <p/>
  133    * <pre><!-- START SNIPPET: example1 -->
  134    * &lt;result name="success" type="jasper"&gt;
  135    *   &lt;param name="location"&gt;foo.jasper&lt;/param&gt;
  136    *   &lt;param name="dataSource"&gt;mySource&lt;/param&gt;
  137    *   &lt;param name="format"&gt;CSV&lt;/param&gt;
  138    * &lt;/result&gt;
  139    * <!-- END SNIPPET: example1 --></pre>
  140    * or for pdf
  141    * <pre><!-- START SNIPPET: example2 -->
  142    * &lt;result name="success" type="jasper"&gt;
  143    *   &lt;param name="location"&gt;foo.jasper&lt;/param&gt;
  144    *   &lt;param name="dataSource"&gt;mySource&lt;/param&gt;
  145    * &lt;/result&gt;
  146    * <!-- END SNIPPET: example2 --></pre>
  147    */
  148   public class JasperReportsResult extends StrutsResultSupport implements JasperReportConstants {
  149   
  150       private static final long serialVersionUID = -2523174799621182907L;
  151   
  152       private final static Logger LOG = LoggerFactory.getLogger(JasperReportsResult.class);
  153   
  154       protected String dataSource;
  155       protected String format;
  156       protected String documentName;
  157       protected String contentDisposition;
  158       protected String delimiter;
  159       protected String imageServletUrl = "/images/";
  160       protected String timeZone;
  161   
  162       /**
  163        * Connection which can be passed to the report
  164        * instead od dataSource.
  165        */
  166       protected String connection;
  167   
  168       /**
  169        * Names a report parameters map stack value, allowing
  170        * additional report parameters from the action.
  171        */
  172       protected String reportParameters;
  173   
  174       /**
  175        * Names an exporter parameters map stack value,
  176        * allowing the use of custom export parameters.
  177        */
  178       protected String exportParameters;
  179   
  180       /**
  181        * Default ctor.
  182        */
  183       public JasperReportsResult() {
  184           super();
  185       }
  186   
  187       /**
  188        * Default ctor with location.
  189        *
  190        * @param location Result location.
  191        */
  192       public JasperReportsResult(String location) {
  193           super(location);
  194       }
  195   
  196       public String getImageServletUrl() {
  197           return imageServletUrl;
  198       }
  199   
  200       public void setImageServletUrl(final String imageServletUrl) {
  201           this.imageServletUrl = imageServletUrl;
  202       }
  203   
  204       public void setDataSource(String dataSource) {
  205           this.dataSource = dataSource;
  206       }
  207   
  208       public void setFormat(String format) {
  209           this.format = format;
  210       }
  211   
  212       public void setDocumentName(String documentName) {
  213           this.documentName = documentName;
  214       }
  215   
  216       public void setContentDisposition(String contentDisposition) {
  217           this.contentDisposition = contentDisposition;
  218       }
  219   
  220       public void setDelimiter(String delimiter) {
  221           this.delimiter = delimiter;
  222       }
  223   
  224       /**
  225        * set time zone id
  226        *
  227        * @param timeZone
  228        */
  229       public void setTimeZone(final String timeZone) {
  230           this.timeZone = timeZone;
  231       }
  232   
  233       public String getReportParameters() {
  234           return reportParameters;
  235       }
  236   
  237       public void setReportParameters(String reportParameters) {
  238           this.reportParameters = reportParameters;
  239       }
  240   
  241       public String getExportParameters() {
  242           return exportParameters;
  243       }
  244   
  245       public void setExportParameters(String exportParameters) {
  246           this.exportParameters = exportParameters;
  247       }
  248   
  249       public String getConnection() {
  250           return connection;
  251       }
  252   
  253       public void setConnection(String connection) {
  254           this.connection = connection;
  255       }
  256   
  257       protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
  258           // Will throw a runtime exception if no "datasource" property. TODO Best place for that is...?
  259           initializeProperties(invocation);
  260   
  261           if (LOG.isDebugEnabled()) {
  262               LOG.debug("Creating JasperReport for dataSource = " + dataSource + ", format = " + format);
  263           }
  264   
  265           HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().get(ServletActionContext.HTTP_REQUEST);
  266           HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().get(ServletActionContext.HTTP_RESPONSE);
  267   
  268           // Handle IE special case: it sends a "contype" request first.
  269           // TODO Set content type to config settings?
  270           if ("contype".equals(request.getHeader("User-Agent"))) {
  271               try {
  272                   response.setContentType("application/pdf");
  273                   response.setContentLength(0);
  274   
  275                   ServletOutputStream outputStream = response.getOutputStream();
  276                   outputStream.close();
  277               } catch (IOException e) {
  278                   LOG.error("Error writing report output", e);
  279                   throw new ServletException(e.getMessage(), e);
  280               }
  281               return;
  282           }
  283   
  284           // Construct the data source for the report.
  285           ValueStack stack = invocation.getStack();
  286           ValueStackDataSource stackDataSource = null;
  287   
  288           Connection conn = (Connection) stack.findValue(connection);
  289           if (conn == null)
  290               stackDataSource = new ValueStackDataSource(stack, dataSource);
  291   
  292           // Determine the directory that the report file is in and set the reportDirectory parameter
  293           // For WW 2.1.7:
  294           //  ServletContext servletContext = ((ServletConfig) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONFIG)).getServletContext();
  295           ServletContext servletContext = (ServletContext) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONTEXT);
  296           String systemId = servletContext.getRealPath(finalLocation);
  297           Map parameters = new ValueStackShadowMap(stack);
  298           File directory = new File(systemId.substring(0, systemId.lastIndexOf(File.separator)));
  299           parameters.put("reportDirectory", directory);
  300           parameters.put(JRParameter.REPORT_LOCALE, invocation.getInvocationContext().getLocale());
  301   
  302           // put timezone in jasper report parameter
  303           if (timeZone != null) {
  304               timeZone = conditionalParse(timeZone, invocation);
  305               final TimeZone tz = TimeZone.getTimeZone(timeZone);
  306               if (tz != null) {
  307                   // put the report time zone
  308                   parameters.put(JRParameter.REPORT_TIME_ZONE, tz);
  309               }
  310           }
  311   
  312           // Add any report parameters from action to param map.
  313           Map reportParams = (Map) stack.findValue(reportParameters);
  314           if (reportParams != null) {
  315               LOG.debug("Found report parameters; adding to parameters...");
  316               parameters.putAll(reportParams);
  317           }
  318   
  319           byte[] output;
  320           JasperPrint jasperPrint;
  321   
  322           // Fill the report and produce a print object
  323           try {
  324               JasperReport jasperReport = (JasperReport) JRLoader.loadObject(systemId);
  325               if (conn == null)
  326                   jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, stackDataSource);
  327               else
  328                   jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
  329           } catch (JRException e) {
  330               LOG.error("Error building report for uri " + systemId, e);
  331               throw new ServletException(e.getMessage(), e);
  332           }
  333   
  334           // Export the print object to the desired output format
  335           try {
  336               if (contentDisposition != null || documentName != null) {
  337                   final StringBuffer tmp = new StringBuffer();
  338                   tmp.append((contentDisposition == null) ? "inline" : contentDisposition);
  339   
  340                   if (documentName != null) {
  341                       tmp.append("; filename=");
  342                       tmp.append(documentName);
  343                       tmp.append(".");
  344                       tmp.append(format.toLowerCase());
  345                   }
  346   
  347                   response.setHeader("Content-disposition", tmp.toString());
  348               }
  349   
  350               JRExporter exporter;
  351   
  352               if (format.equals(FORMAT_PDF)) {
  353                   response.setContentType("application/pdf");
  354                   exporter = new JRPdfExporter();
  355               } else if (format.equals(FORMAT_CSV)) {
  356                   response.setContentType("text/plain");
  357                   exporter = new JRCsvExporter();
  358               } else if (format.equals(FORMAT_HTML)) {
  359                   response.setContentType("text/html");
  360   
  361                   // IMAGES_MAPS seems to be only supported as "backward compatible" from JasperReports 1.1.0
  362   
  363                   Map imagesMap = new HashMap();
  364                   request.getSession(true).setAttribute("IMAGES_MAP", imagesMap);
  365   
  366                   exporter = new JRHtmlExporter();
  367                   exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
  368                   exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + imageServletUrl);
  369   
  370                   // Needed to support chart images:
  371                   exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
  372                   request.getSession().setAttribute("net.sf.jasperreports.j2ee.jasper_print", jasperPrint);
  373               } else if (format.equals(FORMAT_XLS)) {
  374                   response.setContentType("application/vnd.ms-excel");
  375                   exporter = new JRXlsExporter();
  376               } else if (format.equals(FORMAT_XML)) {
  377                   response.setContentType("text/xml");
  378                   exporter = new JRXmlExporter();
  379               } else if (format.equals(FORMAT_RTF)) {
  380                   response.setContentType("application/rtf");
  381                   exporter = new JRRtfExporter();
  382               } else {
  383                   throw new ServletException("Unknown report format: " + format);
  384               }
  385   
  386               Map exportParams = (Map) stack.findValue(exportParameters);
  387               if (exportParams != null) {
  388                   LOG.debug("Found export parameters; adding to exporter parameters...");
  389                   exporter.getParameters().putAll(exportParams);
  390               }
  391   
  392               output = exportReportToBytes(jasperPrint, exporter);
  393           } catch (JRException e) {
  394               String message = "Error producing " + format + " report for uri " + systemId;
  395               LOG.error(message, e);
  396               throw new ServletException(e.getMessage(), e);
  397           }
  398   
  399           response.setContentLength(output.length);
  400   
  401           // Will throw ServletException on IOException.
  402           writeReport(response, output);
  403       }
  404   
  405       /**
  406        * Writes report bytes to response output stream.
  407        *
  408        * @param response Current response.
  409        * @param output   Report bytes to write.
  410        * @throws ServletException on stream IOException.
  411        */
  412       private void writeReport(HttpServletResponse response, byte[] output) throws ServletException {
  413           ServletOutputStream outputStream = null;
  414           try {
  415               outputStream = response.getOutputStream();
  416               outputStream.write(output);
  417               outputStream.flush();
  418           } catch (IOException e) {
  419               LOG.error("Error writing report output", e);
  420               throw new ServletException(e.getMessage(), e);
  421           } finally {
  422               try {
  423                   if (outputStream != null) {
  424                       outputStream.close();
  425                   }
  426               } catch (IOException e) {
  427                   LOG.error("Error closing report output stream", e);
  428                   throw new ServletException(e.getMessage(), e);
  429               }
  430           }
  431       }
  432   
  433       /**
  434        * Sets up result properties, parsing etc.
  435        *
  436        * @param invocation Current invocation.
  437        * @throws Exception on initialization error.
  438        */
  439       private void initializeProperties(ActionInvocation invocation) throws Exception {
  440           if (dataSource == null && connection == null) {
  441               String message = "No dataSource specified...";
  442               LOG.error(message);
  443               throw new RuntimeException(message);
  444           }
  445           if (dataSource != null)
  446               dataSource = conditionalParse(dataSource, invocation);
  447   
  448           format = conditionalParse(format, invocation);
  449           if (StringUtils.isEmpty(format)) {
  450               format = FORMAT_PDF;
  451           }
  452   
  453           if (contentDisposition != null) {
  454               contentDisposition = conditionalParse(contentDisposition, invocation);
  455           }
  456   
  457           if (documentName != null) {
  458               documentName = conditionalParse(documentName, invocation);
  459           }
  460   
  461           reportParameters = conditionalParse(reportParameters, invocation);
  462           exportParameters = conditionalParse(exportParameters, invocation);
  463       }
  464   
  465       /**
  466        * Run a Jasper report to CSV format and put the results in a byte array
  467        *
  468        * @param jasperPrint The Print object to render as CSV
  469        * @param exporter    The exporter to use to export the report
  470        * @return A CSV formatted report
  471        * @throws net.sf.jasperreports.engine.JRException
  472        *          If there is a problem running the report
  473        */
  474       private byte[] exportReportToBytes(JasperPrint jasperPrint, JRExporter exporter) throws JRException {
  475           byte[] output;
  476           ByteArrayOutputStream baos = new ByteArrayOutputStream();
  477   
  478           exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
  479           exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
  480           if (delimiter != null) {
  481               exporter.setParameter(JRCsvExporterParameter.FIELD_DELIMITER, delimiter);
  482           }
  483   
  484           exporter.exportReport();
  485   
  486           output = baos.toByteArray();
  487   
  488           return output;
  489       }
  490   
  491   }

Save This Page
Home » struts-2.1.8.1-src » org.apache » struts2 » views » jasperreports » [javadoc | source]