package org.openmrs.module.reporting.web.cohorts; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.Cohort; 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.cohort.definition.service.CohortDefinitionService; import org.openmrs.module.reporting.common.ObjectUtil; import org.openmrs.module.reporting.common.ReflectionUtil; import org.openmrs.module.reporting.definition.DefinitionUtil; import org.openmrs.module.reporting.definition.configuration.Property; import org.openmrs.module.reporting.evaluation.EvaluationContext; import org.openmrs.module.reporting.evaluation.EvaluationException; import org.openmrs.module.reporting.evaluation.parameter.Parameter; import org.openmrs.module.reporting.validator.CohortDefinitionValidator; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class ManageCohortDefinitionsController { protected static Log log = LogFactory.getLog(ManageCohortDefinitionsController.class); @ModelAttribute("cohortDefinition") public CohortDefinition getCohortDefinition(@RequestParam(required = false, value = "uuid") String uuid, @RequestParam(required = false, value = "type") Class<? extends CohortDefinition> type) { return Context.getService(CohortDefinitionService.class).getDefinition(uuid, type); } /** * Basically acts as the formBackingObject() method for saving a CohortDefinition. */ @RequestMapping("/module/reporting/cohorts/editCohortDefinition") public String editCohortDefinition(ModelMap model, @ModelAttribute("cohortDefinition") CohortDefinition cohortDefinition) { addPropertiesToModel(model, cohortDefinition); return "/module/reporting/cohorts/cohortDefinitionEditor"; } /** * Saves a cohort definition. */ @RequestMapping("/module/reporting/cohorts/saveCohortDefinition") @SuppressWarnings("unchecked") public String saveCohortDefinition(@ModelAttribute("cohortDefinition") CohortDefinition cohortDefinition, BindingResult bindingResult, ModelMap model, HttpServletRequest request) { cohortDefinition.getParameters().clear(); for (Property p : DefinitionUtil.getConfigurationProperties(cohortDefinition)) { String fieldName = p.getField().getName(); String prefix = "parameter." + fieldName; String valParamName = prefix + ".value"; boolean isParameter = "t".equals(request.getParameter(prefix + ".allowAtEvaluation")); try { Object valToSet = WidgetUtil.getFromRequest(request, valParamName, p.getField()); Class<? extends Collection<?>> collectionType = null; Class<?> fieldType = p.getField().getType(); if (ReflectionUtil.isCollection(p.getField())) { collectionType = (Class<? extends Collection<?>>) p.getField().getType(); fieldType = (Class<?>) ReflectionUtil.getGenericTypes(p.getField())[0]; } if (isParameter) { //skip primitive types since they already have a default value if (!fieldType.isPrimitive()) { ReflectionUtil.setPropertyValue(cohortDefinition, p.getField(), null); } else { //use the wrapper class type equivalent so that the WidgetTag doesn't fail fieldType = ReflectionUtil.getWrapperMap().get(fieldType.getName()); } String paramLabel = ObjectUtil.nvlStr(request.getParameter(prefix + ".label"), fieldName); Properties widgetConfig = (Properties)WidgetUtil.getFromRequest(request, prefix+".widgetConfiguration", Properties.class, (Class)null); Parameter param = new Parameter(fieldName, paramLabel, fieldType, collectionType, valToSet, widgetConfig); cohortDefinition.addParameter(param); } else { ReflectionUtil.setPropertyValue(cohortDefinition, p.getField(), valToSet); } } catch (NumberFormatException e) { bindingResult.rejectValue(fieldName, "reporting.error.invalidNumber", "Only integers are allowed"); } } new CohortDefinitionValidator().validate(cohortDefinition, bindingResult); if (bindingResult.hasErrors()) { addPropertiesToModel(model, cohortDefinition); model.addAttribute("errors", bindingResult); return "/module/reporting/cohorts/cohortDefinitionEditor"; } if ("".equals(cohortDefinition.getUuid())) { cohortDefinition.setUuid(null); } log.warn("Saving: " + cohortDefinition); Context.getService(CohortDefinitionService.class).saveDefinition(cohortDefinition); return "redirect:/module/reporting/definition/manageDefinitions.form?type=" + CohortDefinition.class.getName(); } /** * Evaluates a cohort definition given a uuid. * * @param uuid * @param type * @param returnUrl * @param model * @return * @throws EvaluationException */ @RequestMapping("/module/reporting/cohorts/evaluateCohortDefinition") public String evaluateCohortDefinition(@RequestParam(required = false, value = "uuid") String uuid, @RequestParam(required = false, value = "type") Class<? extends CohortDefinition> type, ModelMap model) throws EvaluationException { CohortDefinitionService service = Context.getService(CohortDefinitionService.class); CohortDefinition cohortDefinition = service.getDefinition(uuid, type); // Evaluate the cohort definition EvaluationContext context = new EvaluationContext(); Cohort cohort = service.evaluate(cohortDefinition, context); // create the model and view to return model.addAttribute("cohort", cohort); model.addAttribute("cohortDefinition", cohortDefinition); return "/module/reporting/cohorts/cohortDefinitionEvaluator"; } private void addPropertiesToModel(ModelMap model, CohortDefinition cohortDefinition) { List<Property> properties = DefinitionUtil.getConfigurationProperties(cohortDefinition); model.addAttribute("configurationProperties", properties); Map<String, List<Property>> groups = new LinkedHashMap<String, List<Property>>(); for (Property p : properties) { List<Property> l = groups.get(p.getGroup()); if (l == null) { l = new ArrayList<Property>(); groups.put(p.getGroup(), l); } l.add(p); } model.addAttribute("groupedProperties", groups); } }