org.openmrs.web.controller.report.RunReportController.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.web.controller.report.RunReportController.java

Source

/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.web.controller.report;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.openmrs.api.ReportService;
import org.openmrs.api.context.Context;
import org.openmrs.module.reportingcompatibility.ReportingCompatibilityConstants;
import org.openmrs.report.EvaluationContext;
import org.openmrs.report.Parameter;
import org.openmrs.report.RenderingMode;
import org.openmrs.report.ReportData;
import org.openmrs.report.ReportRenderer;
import org.openmrs.report.ReportSchema;
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.web.report.WebReportRenderer;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;

/**
 * This controller runs a report (which must be passed in with the reportId parameter) after
 * allowing the user to enter parameters (if any) and to choose a ReportRenderer. If the chosen
 * ReportRenderer is a WebReportRenderer, then the report data is placed in the session and this
 * page redirects to the WebReportRenderer's specified URL. Otherwise the renderer writes to this
 * form's response.
 */
public class RunReportController extends SimpleFormController implements Validator {

    public class CommandObject {

        private ReportSchema schema;

        private Map<String, String> userEnteredParams;

        private List<RenderingMode> renderingModes;

        private String selectedRenderer;

        public CommandObject() {
            userEnteredParams = new LinkedHashMap<String, String>();
        }

        public List<RenderingMode> getRenderingModes() {
            return renderingModes;
        }

        public void setRenderingModes(List<RenderingMode> rendereringModes) {
            this.renderingModes = rendereringModes;
        }

        public ReportSchema getSchema() {
            return schema;
        }

        public void setSchema(ReportSchema schema) {
            this.schema = schema;
        }

        public String getSelectedRenderer() {
            return selectedRenderer;
        }

        public void setSelectedRenderer(String selectedRenderer) {
            this.selectedRenderer = selectedRenderer;
        }

        public Map<String, String> getUserEnteredParams() {
            return userEnteredParams;
        }

        public void setUserEnteredParams(Map<String, String> userEnteredParams) {
            this.userEnteredParams = userEnteredParams;
        }
    }

    @SuppressWarnings("unchecked")
    public boolean supports(Class c) {
        return c == CommandObject.class;
    }

    public void validate(Object commandObject, Errors errors) {
        CommandObject command = (CommandObject) commandObject;
        ValidationUtils.rejectIfEmpty(errors, "schema", "Missing reportId, or report not found");
        if (command.getSchema() != null) {
            ReportSchema rs = command.getSchema();
            Set<String> requiredParams = new HashSet<String>();
            if (rs.getReportParameters() != null) {
                for (Parameter p : rs.getReportParameters()) {
                    if (p.isRequired())
                        requiredParams.add(p.getName());
                }
            }

            for (Map.Entry<String, String> e : command.getUserEnteredParams().entrySet()) {
                if (StringUtils.hasText(e.getValue()))
                    requiredParams.remove(e.getKey());
            }
            if (requiredParams.size() > 0) {
                errors.rejectValue("userEnteredParams", "Enter all parameter values");
            }

            if (rs.getDataSetDefinitions() == null || rs.getDataSetDefinitions().size() == 0)
                errors.rejectValue("schema", "ReportSchema must declare some data set definitions");
        }
        ValidationUtils.rejectIfEmpty(errors, "selectedRenderer", "Pick a renderer");
    }

    @Override
    protected Object formBackingObject(HttpServletRequest request) throws Exception {
        CommandObject ret = new CommandObject();
        if (Context.isAuthenticated()) {
            Integer id;
            String param = request.getParameter("reportId");
            try {
                id = Integer.valueOf(param);
            } catch (NumberFormatException e) {
                throw new ServletException(
                        "Unable to run a report with report id: '" + param + "'.  Please choose a valid id");
            }
            ReportService reportService = (ReportService) Context.getService(ReportService.class);
            ReportSchema schema = reportService.getReportSchema(id);
            if (schema == null)
                throw new ServletException("Unable to find a report with report id: '" + param
                        + "' in the database. Please choose a different id");
            ret.setSchema(schema);
            ret.setRenderingModes(reportService.getRenderingModes(schema));
        }
        return ret;
    }

    @Override
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object commandObject,
            BindException errors) throws Exception {
        CommandObject command = (CommandObject) commandObject;
        ReportSchema rs = command.getSchema();
        ReportService reportService = (ReportService) Context.getService(ReportService.class);

        EvaluationContext evalContext = new EvaluationContext();

        if (rs.getReportParameters() != null) {
            for (Parameter p : rs.getReportParameters()) {
                if (command.getUserEnteredParams() != null) {
                    String valString = command.getUserEnteredParams().get(p.getName());
                    Object value;
                    if (StringUtils.hasText(valString)) {
                        try {
                            value = OpenmrsUtil.parse(valString, p.getClazz());
                            evalContext.addParameterValue(p, value);
                        } catch (Exception ex) {
                            errors.rejectValue("userEnteredParams", p.getLabel() + ": " + ex.getMessage());
                        }
                    }
                }
            }
        }
        if (errors.hasErrors())
            return showForm(request, response, errors);

        ReportData data = reportService.evaluate(rs, null, evalContext);
        String renderClass = command.getSelectedRenderer();
        String renderArg = "";
        if (renderClass.indexOf("!") > 0) {
            int ind = renderClass.indexOf("!");
            renderArg = renderClass.substring(ind + 1);
            renderClass = renderClass.substring(0, ind);
        }

        ReportRenderer renderer = reportService.getReportRenderer(renderClass);

        // If we're supposed to use a web report renderer, then we just redirect to the appropriate URL 
        if (renderer instanceof WebReportRenderer) {
            WebReportRenderer webRenderer = (WebReportRenderer) renderer;
            if (webRenderer.getLinkUrl(rs) != null) {
                request.getSession().setAttribute(ReportingCompatibilityConstants.OPENMRS_REPORT_DATA, data);
                request.getSession().setAttribute(ReportingCompatibilityConstants.OPENMRS_REPORT_ARGUMENT,
                        renderArg);
                String url = webRenderer.getLinkUrl(rs);
                if (!url.startsWith("/"))
                    url = "/" + url;
                url = request.getContextPath() + url;
                return new ModelAndView(new RedirectView(url));
            }
        }

        // Otherwise, just render the report 
        // TODO it's possible that a web renderer will handle this -- is that ok?
        String filename = renderer.getFilename(rs, renderArg).replace(" ", "_");
        response.setContentType(renderer.getRenderedContentType(rs, renderArg));
        response.setHeader("Content-Disposition", "attachment; filename=" + filename);
        response.setHeader("Pragma", "no-cache");
        renderer.render(data, renderArg, response.getOutputStream());
        return null;

    }

}