DisplayReportAction.java

/*
 * This software was designed and created by Jason Carroll.
 * Copyright (c) 2002, 2003, 2004 Jason Carroll.
 * The author can be reached at jcarroll@cowsultants.com
 * ITracker website: http://www.cowsultants.com
 * ITracker forums: http://www.cowsultants.com/phpBB/index.php
 *
 * This program is free software; you can redistribute it and/or modify
 * it only under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

package org.itracker.web.actions.report;

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.*;
import org.itracker.ReportException;
import org.itracker.core.resources.ITrackerResourceBundle;
import org.itracker.core.resources.ITrackerResources;
import org.itracker.model.*;
import org.itracker.model.util.ReportUtilities;
import org.itracker.services.ConfigurationService;
import org.itracker.services.IssueService;
import org.itracker.services.ReportService;
import org.itracker.web.actions.base.ItrackerBaseAction;
import org.itracker.web.util.*;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;


public class DisplayReportAction extends ItrackerBaseAction {
    private static final Logger log = Logger.getLogger(DisplayReportAction.class);

    public DisplayReportAction() {
    }

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ActionMessages errors = new ActionMessages();

        try {
            HttpSession session = request.getSession(false);
            Locale userLocale = LoginUtilities.getCurrentLocale(request);

            List<Issue> reportingIssues = new ArrayList<Issue>();
            String reportType = (String) PropertyUtils.getSimpleProperty(form, "type");
            log.info("execute: report type was " + reportType);

            final Integer[] projectIds = (Integer[]) PropertyUtils.getSimpleProperty(form, "projectIds");
            final IssueService issueService = ServletContextUtils.getItrackerServices().getIssueService();
            final ConfigurationService configurationService = ServletContextUtils.getItrackerServices().getConfigurationService();
            final ReportService reportService = ServletContextUtils.getItrackerServices().getReportService();

            if ("all".equalsIgnoreCase(reportType)) {
                // Export all of the issues in the system
                User currUser = (User) session.getAttribute(Constants.USER_KEY);
                if (!currUser.isSuperUser()) {
                    errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.unauthorized"));
                    throw new ReportException();
                }
                reportingIssues = issueService.getAllIssues();
                Collections.sort(reportingIssues, Issue.ID_COMPARATOR);
            } else if ("project".equalsIgnoreCase(reportType)) {
                if (projectIds != null && projectIds.length > 0) {
                    // This wasn't a regular search.  So instead, take all the selected projects and find all the
                    // issues for them, check which ones the user can see, and then create a new array of issues
                    List<Issue> reportDataList = new ArrayList<>();

                    List<Issue> issues;
                   for (Integer projectId : projectIds) {
                      issues = issueService.getIssuesByProjectId(projectId);
                      for (Issue issue: issues) {
                         if (LoginUtilities.canViewIssue(issue))
                             reportDataList.add(issue);

                      }
                   }
                    reportingIssues = reportDataList;
                    Collections.sort(reportingIssues, Issue.ID_COMPARATOR);

                } else {
                    throw new ReportException("", "itracker.web.error.projectrequired");
                }
            } else {
                // This must be a regular search, look for a search query result.
                // must be loaded with current session (lazy loading)
                IssueSearchQuery isqm = (IssueSearchQuery) session.getAttribute(Constants.SEARCH_QUERY_KEY);
                for (Issue issue : isqm.getResults()) {
                    reportingIssues.add(issueService.getIssue(issue.getId()));
                }
            }

            log.debug("Report data contains " + reportingIssues.size() + " elements.");

            if (reportingIssues.isEmpty()) {
                errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.noreportdata"));
                throw new ReportException();
            }

            Integer reportId = (Integer) PropertyUtils.getSimpleProperty(form, "reportId");
            String reportOutput = (String) PropertyUtils.getSimpleProperty(form, "reportOutput");
            if (null == reportId) {
                log.debug("Invalid report id: " + reportId + " requested.");
                errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.invalidreport"));
            } else if (ReportUtilities.REPORT_EXPORT_XML == reportId.intValue()) {
                log.debug("Issue export requested.");

                SystemConfiguration config = configurationService.getSystemConfiguration(ImportExportTags.EXPORT_LOCALE);

                if (!ImportExportUtilities.exportIssues(reportingIssues, config, request, response)) {
                    errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.system"));
                } else {
                   return null;
                }
            } else if (reportId.intValue() > 0) {
                log.debug("Defined report (" + reportId + ") requested.");

                Report reportModel = reportService.getReportDAO().findByPrimaryKey(reportId);

                log.debug("Report " + reportModel + " found.");

                Project project = null;
                log.debug("Processing report.");
                outputReport(reportingIssues, project, reportModel, userLocale, reportOutput, response);
                return null;

            }
        } catch (ReportException re) {
            log.debug("Error for report", re);
            if (!StringUtils.isEmpty(re.getErrorKey())) {
                errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(re.getErrorKey()));
            } else {
                errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.details", re.getMessage()));
            }

        } catch (Exception e) {
            log.warn("Error in report processing: " + e.getMessage(), e);
            errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.system"));
            errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.details", e.getMessage()));
        }

        if (!errors.isEmpty()) {
            saveErrors(request, errors);
        }

        return mapping.findForward("error");
    }





    private static JasperPrint generateReport(Report report,
                                       Map<String, Object> parameters, JRDataSource datasource)
    throws ReportException{
        try {

            JasperReport jasperReport = JasperCompileManager.compileReport(new ByteArrayInputStream(report.getFileData()));
            JasperPrint jasperPrint = JasperFillManager.fillReport(
                    jasperReport,
                    parameters,
                    datasource);


            return jasperPrint;
        } catch (JRException e) {
            throw new ReportException(e);
        }

    }

    /**
     *
     */
    public static void outputReport(List<Issue> reportDataArray, Project project, Report report,
                          Locale userLocale, String reportOutput,
                          HttpServletResponse response) throws ReportException {

        try {
            // hack, we have to find a more structured way to support
            // various types of queries
            final JRBeanCollectionDataSource beanCollectionDataSource = new JRBeanCollectionDataSource(
                    reportDataArray);

            final Map<String, Object> parameters = new HashMap<String, Object>();
            String reportTitle = report.getName();
            if (project != null) {
                reportTitle += " - " + project.getName();
                if (report.getNameKey() != null) {
                    reportTitle = ITrackerResources.getString(report.getNameKey(), project.getName());
                }
            } else if (report.getNameKey() != null) {
                reportTitle = ITrackerResources.getString(report.getNameKey());
            }
            parameters.put("ReportTitle", reportTitle);
            parameters.put("BaseDir", new File("."));
            parameters.put("REPORT_LOCALE", userLocale);
            parameters.put("REPORT_RESOURCE_BUNDLE", ITrackerResourceBundle.getBundle(userLocale));

            final JasperPrint jasperPrint = generateReport(report, parameters,
                    beanCollectionDataSource);


            final ServletOutputStream out = response.getOutputStream();
            final JRExporter x;
            if (ReportUtilities.REPORT_OUTPUT_PDF.equals(reportOutput)) {

                response.setHeader("Content-Type", "application/pdf");
                response.setHeader("Content-Disposition", "attachment; filename=\"" + report.getName()
                        + new SimpleDateFormat("-yyyy-MM-dd").format(new Date())
                        + ".pdf\"");
                x = new JRPdfExporter();

            } else if (ReportUtilities.REPORT_OUTPUT_XLS.equals(reportOutput)) {
                response.setHeader("Content-Type", "application/xls");
                response.setHeader("Content-Disposition", "attachment; filename=\"" + report.getName()
                           + new SimpleDateFormat("-yyyy-MM-dd").format(new Date())
                           + ".xls\"");
                x = new JRXlsExporter();

            } else if (ReportUtilities.REPORT_OUTPUT_CSV.equals(reportOutput)) {

                response.setHeader("Content-Type", "text/csv");
                response.setHeader("Content-Disposition", "attachment; filename=\"" + report.getName()
                        + new SimpleDateFormat("-yyyy-MM-dd").format(new Date())
                        + ".csv\"");
                x = new JRCsvExporter();

            } else if (ReportUtilities.REPORT_OUTPUT_HTML.equals(reportOutput)) {
                response.setHeader("Content-Type", "text/html");
                response.setHeader("Content-Disposition", "attachment; filename=\"" + report.getName()
                        + new SimpleDateFormat("-yyyy-MM-dd").format(new Date())
                        + ".html\"");
                x = new JRHtmlExporter();

            } else {
                log.error("Invalid report output format: " + reportOutput);
                throw new ReportException("Invalid report type.", "itracker.web.error.invalidreportoutput");
            }
            x.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
            x.setParameter(JRExporterParameter.OUTPUT_STREAM, out);

            x.exportReport();

            out.flush();
            out.close();
        } catch (JRException e) {
            throw new ReportException(e);
        } catch (IOException e) {
            throw new ReportException(e);
        }

    }

}