org.jasig.ssp.web.api.reports.ReportBaseController.java Source code

Java tutorial

Introduction

Here is the source code for org.jasig.ssp.web.api.reports.ReportBaseController.java

Source

/**
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jasig.ssp.web.api.reports;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRXlsAbstractExporterParameter;

import org.apache.commons.lang.StringUtils;
import org.jasig.ssp.service.EarlyAlertResponseService;
import org.jasig.ssp.transferobject.reports.BaseStudentReportTO;
import org.jasig.ssp.transferobject.reports.EarlyAlertResponseCounts;
import org.jasig.ssp.transferobject.reports.EarlyAlertStudentReportTO;
import org.jasig.ssp.util.csvwriter.AbstractCsvWriterHelper;
import org.jasig.ssp.util.sort.PagingWrapper;
import org.jasig.ssp.web.api.AbstractBaseController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

abstract class ReportBaseController<R> extends AbstractBaseController {

    public static final String REPORT_TYPE_PDF = "pdf";
    public static final String REPORT_TYPE_CSV = "csv";
    public static final String DEFAULT_REPORT_TYPE = REPORT_TYPE_PDF;

    public static final String DEFAULT_DATE_FORMAT = "MM/dd/yyyy";

    private static final Logger LOGGER = LoggerFactory.getLogger(ReportBaseController.class);
    private static final String DEFAULT_REPORT_NAME = "report"; // no 'ssp' prefix b/c that's branding

    @Autowired
    private ServletContext servletContext;

    @Override
    protected Logger getLogger() {
        return LOGGER;
    }

    protected void renderReport(HttpServletResponse response, Map<String, Object> reportParameters,
            Collection<R> reportResults, String reportViewUrl, String reportType, String reportName)
            throws IOException {
        reportName = normalizeReportName(reportName);
        // TODO this should really all be shunted off to Spring's View mechanism
        if (REPORT_TYPE_PDF.equals(reportType)) {
            renderPdfReport(response, reportParameters, reportResults, reportViewUrl, reportType, reportName);
        } else if (REPORT_TYPE_CSV.equals(reportType)) {
            renderCsvReport(response, reportParameters, reportResults, reportViewUrl, reportType, reportName);
        } else {
            throw new IllegalArgumentException("Unrecognized report type");
        }
    }

    protected String normalizeReportName(String reportName) {
        if (StringUtils.isBlank(reportName)) {
            return DEFAULT_REPORT_NAME;
        }
        return reportName.replaceAll("\\s", "_");
    }

    protected void renderPdfReport(HttpServletResponse response, Map<String, Object> reportParameters,
            Collection<R> reportResults, String reportViewUrl, String reportType, String reportName)
            throws IOException {
        try {
            renderJasperReport(response, reportParameters, reportResults, reportViewUrl, reportType, reportName);
        } catch (JRException e) {
            throw new RuntimeException(e);
        }
    }

    protected void renderCsvReport(HttpServletResponse response, Map<String, Object> reportParameters,
            Collection<R> reportResults, String reportViewUrl, String reportType, String reportName)
            throws IOException {
        if (overridesCsvRendering()) {
            renderCsvReportWithFromattingOverrides(response, reportParameters, reportResults, reportViewUrl,
                    reportType, reportName);
        } else {
            try {
                renderJasperReport(response, reportParameters, reportResults, reportViewUrl, reportType,
                        reportName);
            } catch (JRException e) {
                throw new RuntimeException(e);
            }
        }
    }

    protected void renderJasperReport(HttpServletResponse response, Map<String, Object> reportParameters,
            Collection<R> reportResults, String reportViewUrl, String reportType, String reportName)
            throws JRException, IOException {

        SearchParameters.addReportDateToMap(reportParameters);
        final InputStream is = getClass().getResourceAsStream(reportViewUrl);
        final ByteArrayOutputStream os = new ByteArrayOutputStream();

        JRDataSource beanDS;
        if (reportResults == null || reportResults.size() <= 0) {
            beanDS = new JREmptyDataSource();
        } else {
            beanDS = new JRBeanCollectionDataSource(reportResults);
        }

        if (REPORT_TYPE_PDF.equals(reportType)) {
            DefaultJasperReportsContext context = DefaultJasperReportsContext.getInstance();
            JRPropertiesUtil.getInstance(context).setProperty("net.sf.jasperreports.awt.ignore.missing.font",
                    "true");
            JRPropertiesUtil.getInstance(context).setProperty("net.sf.jasperreports.default.font.name",
                    "DejaVu Sans");
            JRPropertiesUtil.getInstance(context).setProperty("net.sf.jasperreports.default.pdf.embedded", "true");
            JRPropertiesUtil.getInstance(context).setProperty("net.sf.jasperreports.default.pdf.font.name",
                    "DejaVu Sans");

            if (!(reportParameters.containsKey("realPath"))) {
                reportParameters.put("realPath", servletContext.getRealPath("/"));
            }
        }

        JasperFillManager.fillReportToStream(is, os, reportParameters, beanDS);
        final InputStream decodedInput = new ByteArrayInputStream(os.toByteArray());

        if (REPORT_TYPE_PDF.equals(reportType)) {
            response.setHeader("Content-disposition", "attachment; filename=" + reportName + "." + REPORT_TYPE_PDF);
            JasperExportManager.exportReportToPdfStream(decodedInput, response.getOutputStream());
        } else if ("csv".equals(reportType)) {
            writeCsvHttpResponseHeaders(response, reportName);

            final JRCsvExporter exporter = new JRCsvExporter();
            exporter.setParameter(JRExporterParameter.INPUT_STREAM, decodedInput);
            exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, response.getOutputStream());
            exporter.setParameter(JRXlsAbstractExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE);

            exporter.exportReport();
        }

        response.flushBuffer();
        is.close();
        os.close();
    }

    /**
     * If {@code true}, subclasses will have the opportunity to participate in more fine-grained, i.e. non-Jasper CSV
     * report rendering. In particular, CSV rendering will rely on
     * {@link #csvBodyRow(Object, java.util.Map, java.util.Collection, String, String, String, org.jasig.ssp.util.csvwriter.AbstractCsvWriterHelper)}
     * and
     * {@link #csvBodyRow(Object, java.util.Map, java.util.Collection, String, String, String, org.jasig.ssp.util.csvwriter.AbstractCsvWriterHelper)}
     * via {@link #renderCsvReportWithFromattingOverrides(javax.servlet.http.HttpServletResponse, java.util.Map, java.util.Collection, String, String, String)}.
     * This is designed with a flag method rather than a mixin interface b/c Spring will not map {@code Controllers} that
     * mix in interfaces unless we change our proxying mode (See <a href="http://stackoverflow.com/a/16970812">this SO
     * answer</a>)
     */
    protected boolean overridesCsvRendering() {
        return false;
    }

    protected void renderCsvReportWithFromattingOverrides(final HttpServletResponse response,
            final Map<String, Object> reportParameters, final Collection<R> reportResults,
            final String reportViewUrl, final String reportType, final String reportName) throws IOException {
        writeCsvHttpResponseHeaders(response, reportName);
        AbstractCsvWriterHelper<R> csvWriter = new AbstractCsvWriterHelper<R>(response.getWriter()) {
            @Override
            protected String[] csvHeaderRow() {
                return ReportBaseController.this.csvHeaderRow(reportParameters, reportResults, reportViewUrl,
                        reportType, reportName, this);
            }

            @Override
            protected List<String[]> csvBodyRows(R model) {
                return ReportBaseController.this.csvBodyRows(model, reportParameters, reportResults, reportViewUrl,
                        reportType, reportName, this);
            }
        };
        csvWriter.write((Collection<R>) reportResults, -1L);
    }

    /** Defaults to an angry no-op. See {@link #overridesCsvRendering()}. Should not be called unless that op returns
     * true */
    protected String[] csvHeaderRow(Map<String, Object> reportParameters, Collection<R> reportResults,
            String reportViewUrl, String reportType, String reportName, AbstractCsvWriterHelper csvHelper) {
        throw new UnsupportedOperationException();
    }

    /** Defaults to an angry no-op. See {@link #overridesCsvRendering()}. Should not be called unless that op returns
     * true */
    protected List<String[]> csvBodyRows(R reportResultElement, Map<String, Object> reportParameters,
            Collection<R> reportResults, String reportViewUrl, String reportType, String reportName,
            AbstractCsvWriterHelper csvHelper) {
        throw new UnsupportedOperationException();
    }

    protected void writeCsvHttpResponseHeaders(HttpServletResponse response, String reportName) {
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment; filename=" + reportName + "." + REPORT_TYPE_CSV);
    }

    <T extends BaseStudentReportTO> List<T> processStudentReportTOs(PagingWrapper<T> people) {
        if (people == null || people.getRows().size() <= 0)
            return new ArrayList<T>();
        return processStudentReportTOs(new ArrayList<T>(people.getRows()));
    }

    <T extends BaseStudentReportTO> List<T> processStudentReportTOs(Collection<T> reports) {
        ArrayList<T> compressedReports = new ArrayList<T>();
        if (reports == null || reports.size() <= 0)
            return compressedReports;

        for (T reportTO : reports) {
            Integer index = compressedReports.indexOf(reportTO);
            if (index != null && index >= 0) {
                T compressedReportTo = compressedReports.get(index);
                compressedReportTo.processDuplicate(reportTO);
            } else {
                reportTO.normalize();
                compressedReports.add(reportTO);
            }
        }
        return compressedReports;
    }

    protected List<EarlyAlertStudentReportTO> processReports(PagingWrapper<EarlyAlertStudentReportTO> reports,
            EarlyAlertResponseService earlyAlertResponseService) {

        ArrayList<EarlyAlertStudentReportTO> compressedReports = new ArrayList<EarlyAlertStudentReportTO>();
        if (reports == null || reports.getRows().size() <= 0)
            return compressedReports;

        for (EarlyAlertStudentReportTO reportTO : reports) {
            Integer index = compressedReports.indexOf(reportTO);
            if (index != null && index >= 0) {
                BaseStudentReportTO compressedReportTo = compressedReports.get(index);
                compressedReportTo.processDuplicate(reportTO);
            } else {
                reportTO.normalize();
                compressedReports.add(reportTO);
            }
        }

        for (EarlyAlertStudentReportTO reportTO : compressedReports) {
            EarlyAlertResponseCounts countOfResponses = earlyAlertResponseService
                    .getCountEarlyAlertRespondedToForEarlyAlerts(reportTO.getEarlyAlertIds());
            reportTO.setPending(countOfResponses.getTotalEARespondedToNotClosed());
        }
        return compressedReports;
    }

}