org.openmrs.module.bom.web.controller.BomRunReportFormController.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.bom.web.controller.BomRunReportFormController.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.module.bom.web.controller;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.context.Context;
import org.openmrs.module.htmlwidgets.web.WidgetUtil;
import org.openmrs.module.reporting.cohort.definition.CohortDefinition;
import org.openmrs.module.reporting.common.ObjectUtil;
import org.openmrs.module.reporting.evaluation.EvaluationContext;
import org.openmrs.module.reporting.evaluation.EvaluationUtil;
import org.openmrs.module.reporting.evaluation.parameter.Mapped;
import org.openmrs.module.reporting.evaluation.parameter.Parameter;
import org.openmrs.module.reporting.propertyeditor.MappedEditor;
import org.openmrs.module.reporting.report.ReportRequest;
import org.openmrs.module.reporting.report.ReportRequest.Priority;
import org.openmrs.module.reporting.report.definition.ReportDefinition;
import org.openmrs.module.reporting.report.definition.service.ReportDefinitionService;
import org.openmrs.module.reporting.report.renderer.RenderingMode;
import org.openmrs.module.reporting.report.renderer.ReportRenderer;
import org.openmrs.module.reporting.report.service.ReportService;
import org.openmrs.util.OpenmrsUtil;
import org.quartz.CronExpression;
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.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.BaseCommandController;
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 BomRunReportFormController extends SimpleFormController implements Validator {

    private transient Log log = LogFactory.getLog(this.getClass());

    /**
     * @see BaseCommandController#initBinder(HttpServletRequest, ServletRequestDataBinder)
     */
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
        super.initBinder(request, binder);
        binder.registerCustomEditor(Mapped.class, new MappedEditor());
    }

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

    @Override
    public void validate(Object commandObject, Errors errors) {
        CommandObject command = (CommandObject) commandObject;
        ValidationUtils.rejectIfEmpty(errors, "reportDefinition", "reporting.Report.run.error.missingReportID");
        if (command.getReportDefinition() != null) {
            ReportDefinition reportDefinition = command.getReportDefinition();
            Set<String> requiredParams = new HashSet<String>();
            if (reportDefinition.getParameters() != null) {
                for (Parameter parameter : reportDefinition.getParameters()) {
                    if (parameter.isRequired()) {
                        requiredParams.add(parameter.getName());
                    }
                }
            }

            for (Map.Entry<String, Object> e : command.getUserEnteredParams().entrySet()) {
                if (e.getValue() instanceof Iterable || e.getValue() instanceof Object[]) {
                    Object iterable = e.getValue();
                    if (e.getValue() instanceof Object[]) {
                        iterable = Arrays.asList((Object[]) e.getValue());
                    }

                    boolean hasNull = true;

                    for (Object value : (Iterable<Object>) iterable) {
                        hasNull = !ObjectUtil.notNull(value);
                    }

                    if (!hasNull) {
                        requiredParams.remove(e.getKey());
                    }
                } else if (ObjectUtil.notNull(e.getValue())) {
                    requiredParams.remove(e.getKey());
                }
            }
            if (requiredParams.size() > 0) {
                for (Iterator<String> iterator = requiredParams.iterator(); iterator.hasNext();) {
                    String parameterName = (String) iterator.next();
                    if (StringUtils.hasText(command.getExpressions().get(parameterName))) {
                        String expression = command.getExpressions().get(parameterName);
                        if (!EvaluationUtil.isExpression(expression)) {
                            errors.rejectValue("expressions[" + parameterName + "]",
                                    "reporting.Report.run.error.invalidParamExpression");
                        }
                    } else {
                        errors.rejectValue("userEnteredParams[" + parameterName + "]", "error.required",
                                new Object[] { "This parameter" }, "{0} is required");
                    }
                }
            }

            if (reportDefinition.getDataSetDefinitions() == null
                    || reportDefinition.getDataSetDefinitions().size() == 0) {
                errors.reject("reporting.Report.run.error.definitionNotDeclared");
            }

            if (ObjectUtil.notNull(command.getSchedule())) {
                if (!CronExpression.isValidExpression(command.getSchedule())) {
                    errors.rejectValue("schedule", "reporting.Report.run.error.invalidCronExpression");
                }
            }
        }
        ValidationUtils.rejectIfEmpty(errors, "selectedRenderer", "reporting.Report.run.error.noRendererSelected");
    }

    @Override
    protected Object formBackingObject(HttpServletRequest request) throws Exception {
        CommandObject command = new CommandObject();
        if (Context.isAuthenticated()) {
            ReportDefinitionService rds = Context.getService(ReportDefinitionService.class);
            ReportService reportService = Context.getService(ReportService.class);
            if (StringUtils.hasText(request.getParameter("copyRequest"))) {
                ReportRequest req = reportService.getReportRequestByUuid(request.getParameter("copyRequest"));
                // avoid lazy init exceptions
                command.setReportDefinition(
                        rds.getDefinitionByUuid(req.getReportDefinition().getParameterizable().getUuid()));
                for (Map.Entry<String, Object> param : req.getReportDefinition().getParameterMappings()
                        .entrySet()) {
                    Object value = param.getValue();
                    if (value != null && EvaluationUtil.isExpression(value.toString())) {
                        command.getExpressions().put(param.getKey(), (String) value);
                        value = "";
                    }
                    command.getUserEnteredParams().put(param.getKey(), value);
                }
                command.setSelectedRenderer(req.getRenderingMode().getDescriptor());
            } else if (StringUtils.hasText(request.getParameter("requestUuid"))) {
                String reqUuid = request.getParameter("requestUuid");
                ReportRequest rr = reportService.getReportRequestByUuid(reqUuid);
                command.setExistingRequestUuid(reqUuid);
                command.setReportDefinition(rr.getReportDefinition().getParameterizable());
                command.setUserEnteredParams(rr.getReportDefinition().getParameterMappings());
                command.setBaseCohort(rr.getBaseCohort());
                command.setSelectedRenderer(rr.getRenderingMode().getDescriptor());
                command.setSchedule(rr.getSchedule());
            } else {
                String uuid = request.getParameter("reportId");
                ReportDefinition reportDefinition = rds.getDefinitionByUuid(uuid);
                command.setReportDefinition(reportDefinition);
            }
            command.setRenderingModes(reportService.getRenderingModes(command.getReportDefinition()));
        }
        return command;
    }

    @Override
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object commandObject,
            BindException errors) throws Exception {
        CommandObject command = (CommandObject) commandObject;
        ReportDefinition reportDefinition = command.getReportDefinition();

        ReportService rs = Context.getService(ReportService.class);

        // Parse the input parameters into appropriate objects and fail validation if any are invalid
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        if (reportDefinition.getParameters() != null
                && (command.getUserEnteredParams() != null || command.getExpressions() != null)) {
            for (Parameter parameter : reportDefinition.getParameters()) {
                Object value = null;
                String expression = null;
                if (command.getExpressions() != null
                        && ObjectUtil.notNull(command.getExpressions().get(parameter.getName()))) {
                    expression = command.getExpressions().get(parameter.getName());
                } else {
                    value = command.getUserEnteredParams().get(parameter.getName());
                }
                if (ObjectUtil.notNull(value) || ObjectUtil.notNull(expression)) {
                    try {
                        if (StringUtils.hasText(expression))
                            value = expression;
                        else
                            value = WidgetUtil.parseInput(value, parameter.getType(),
                                    parameter.getCollectionType());

                        params.put(parameter.getName(), value);
                    } catch (Exception ex) {
                        errors.rejectValue("userEnteredParams[" + parameter.getName() + "]", ex.getMessage());
                    }
                }
            }
        }

        // Ensure that the chosen renderer is valid for this report
        RenderingMode renderingMode = command.getSelectedMode();
        if (!renderingMode.getRenderer().canRender(reportDefinition)) {
            errors.rejectValue("selectedRenderer", "reporting.Report.run.error.invalidRenderer");
        }

        if (errors.hasErrors()) {
            return showForm(request, response, errors);
        }

        ReportRequest rr = null;
        if (command.getExistingRequestUuid() != null) {
            rr = rs.getReportRequestByUuid(command.getExistingRequestUuid());
        } else {
            rr = new ReportRequest();
        }
        rr.setReportDefinition(new Mapped<ReportDefinition>(reportDefinition, params));
        rr.setBaseCohort(command.getBaseCohort());
        rr.setRenderingMode(command.getSelectedMode());
        rr.setPriority(Priority.NORMAL);
        rr.setSchedule(command.getSchedule());

        // TODO: We might want to check here if this exact same report request is already queued and just re-direct if so

        rr = rs.queueReport(rr);
        rs.processNextQueuedReports();

        return new ModelAndView(new RedirectView("../bom/bomReportHistoryOpen.form?uuid=" + rr.getUuid()));
    }

    /**
     * @see org.springframework.web.servlet.mvc.SimpleFormController#referenceData(javax.servlet.http.HttpServletRequest)
     */
    @Override
    protected Map<String, Object> referenceData(HttpServletRequest request, Object commandObject, Errors errors)
            throws Exception {
        CommandObject command = (CommandObject) commandObject;
        Map<String, Object> map = new HashMap<String, Object>();
        EvaluationContext ec = new EvaluationContext();
        Set<String> expSupportedTypes = new HashSet<String>();
        Set<String> inputsToToggle = new HashSet<String>();
        for (Object value : ec.getContextValues().values()) {
            expSupportedTypes.add(value.getClass().getName());
        }
        map.put("expSupportedTypes", expSupportedTypes);

        for (Map.Entry<String, Object> e : command.getUserEnteredParams().entrySet()) {
            if (StringUtils.hasText(command.getExpressions().get(e.getKey()))) {
                inputsToToggle.add(e.getKey());
            }
        }
        map.put("inputsToToggle", inputsToToggle);
        return map;
    }

    public class CommandObject {

        private String existingRequestUuid;
        private ReportDefinition reportDefinition;
        private Mapped<CohortDefinition> baseCohort;
        private Map<String, Object> userEnteredParams;
        private String selectedRenderer; // as RendererClass!Arg
        private String schedule;
        private Map<String, String> expressions;

        private List<RenderingMode> renderingModes;

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

        @SuppressWarnings("unchecked")
        public RenderingMode getSelectedMode() {
            if (selectedRenderer != null) {
                try {
                    String[] temp = selectedRenderer.split("!");
                    Class<? extends ReportRenderer> rc = (Class<? extends ReportRenderer>) Context
                            .loadClass(temp[0]);
                    String arg = (temp.length > 1 && StringUtils.hasText(temp[1])) ? temp[1] : null;
                    for (RenderingMode mode : renderingModes) {
                        if (mode.getRenderer().getClass().equals(rc)
                                && OpenmrsUtil.nullSafeEquals(mode.getArgument(), arg)) {
                            return mode;
                        }
                    }
                    log.warn("Could not find requested rendering mode: " + selectedRenderer);
                } catch (Exception e) {
                    log.warn("Could not load requested renderer", e);
                }
            }
            return null;
        }

        public String getExistingRequestUuid() {
            return existingRequestUuid;
        }

        public void setExistingRequestUuid(String existingRequestUuid) {
            this.existingRequestUuid = existingRequestUuid;
        }

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

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

        public ReportDefinition getReportDefinition() {
            return reportDefinition;
        }

        public void setReportDefinition(ReportDefinition reportDefinition) {
            this.reportDefinition = reportDefinition;
        }

        public Mapped<CohortDefinition> getBaseCohort() {
            return baseCohort;
        }

        public void setBaseCohort(Mapped<CohortDefinition> baseCohort) {
            this.baseCohort = baseCohort;
        }

        public String getSelectedRenderer() {
            return selectedRenderer;
        }

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

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

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

        public String getSchedule() {
            return schedule;
        }

        public void setSchedule(String schedule) {
            this.schedule = schedule;
        }

        /**
         * @return the expressions
         */
        public Map<String, String> getExpressions() {
            return expressions;
        }

        /**
         * @param expressions the expressions to set
         */
        public void setExpressions(Map<String, String> expressions) {
            this.expressions = expressions;
        }
    }

}