/**
* 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.reporting.web.reports;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Cohort;
import org.openmrs.Patient;
import org.openmrs.api.APIException;
import org.openmrs.api.context.Context;
import org.openmrs.module.htmlwidgets.web.WidgetUtil;
import org.openmrs.module.reporting.common.ObjectUtil;
import org.openmrs.module.reporting.evaluation.EvaluationContext;
import org.openmrs.module.reporting.evaluation.parameter.Mapped;
import org.openmrs.module.reporting.evaluation.parameter.Parameter;
import org.openmrs.module.reporting.report.ReportData;
import org.openmrs.module.reporting.report.ReportDesign;
import org.openmrs.module.reporting.report.ReportDesignResource;
import org.openmrs.module.reporting.report.ReportProcessorConfiguration;
import org.openmrs.module.reporting.report.ReportRequest;
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.module.reporting.web.controller.mapping.renderers.RendererMappingHandler;
import org.openmrs.util.HandlerUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Controller
public class ManageReportsController {
protected static Log log = LogFactory.getLog(ManageReportsController.class);
/**
* Default Constructor
*/
public ManageReportsController() { }
/**
* Provide all reports, optionally including those that are retired, to a page
* that lists them and provides options for working with these reports.
*/
@RequestMapping("/module/reporting/reports/manageReports")
public ModelMap manageReports(ModelMap model,
@RequestParam(required=false, value="includeRetired") Boolean includeRetired) {
// Get list of existing reports
boolean includeRet = (includeRetired == Boolean.TRUE);
List<ReportDefinition> reportDefinitions = Context.getService(ReportDefinitionService.class).getAllDefinitions(includeRet);
model.addAttribute("reportDefinitions", reportDefinitions);
// Get possible new reports to create
Map<String, String> types = new LinkedHashMap<String, String>();
types.put("Period Indicator Report", "periodIndicatorReport.form");
types.put("Row-Per-Patient Report", "logicReport.form");
types.put("Custom Report (Advanced)", "reportEditor.form?type=" + ReportDefinition.class.getName());
model.addAttribute("createLinks", types);
return model;
}
/**
* Provide all reports designs, optionally including those that are retired, to a page
* that lists them and provides options for working with them.
*/
@RequestMapping("/module/reporting/reports/manageReportDesigns")
public ModelMap manageReportDesigns(ModelMap model,
@RequestParam(required=false, value="includeRetired") Boolean includeRetired) {
// Get list of existing reports
boolean includeRet = (includeRetired == Boolean.TRUE);
List<ReportDesign> reportDesigns = Context.getService(ReportService.class).getAllReportDesigns(includeRet);
ReportDesign reportDesign = new ReportDesign();
model.addAttribute("reportDesigns", reportDesigns);
model.addAttribute("reportDesign", reportDesign);
return model;
}
/**
*
* to edit a reportDefinition based on its rendererType.
*/
@RequestMapping("/module/reporting/reports/renderers/editReportDesign")
public String editReportDesign(ModelMap model,
@RequestParam(required=true, value="type") Class<? extends ReportRenderer> type,
@RequestParam(required=false, value="reportDesignUuid") String reportDesignUuid,
@RequestParam(required=false, value="reportDefinitionUuid") String reportDefinitionUuid,
@RequestParam(required=false, value="returnUrl") String returnUrl) {
if ( !ObjectUtil.isNull(type) ) {
try {
RendererMappingHandler handler = HandlerUtil.getPreferredHandler(RendererMappingHandler.class, type);
String redirectParameters = ObjectUtil.isNull(reportDefinitionUuid) ? "" : "&reportDefinitionUuid=" + reportDefinitionUuid;
redirectParameters += ObjectUtil.isNull(returnUrl) ? "" : "&successUrl=" + returnUrl;
if (ObjectUtil.isNull(reportDesignUuid)) {
return "redirect:" + handler.getCreateUrl( type ) + redirectParameters;
}
else {
ReportService rs = Context.getService(ReportService.class);
ReportDesign design = rs.getReportDesignByUuid(reportDesignUuid);
return "redirect:" + handler.getEditUrl( design ) + redirectParameters;
}
} catch ( APIException e ) {
log.error( "No handler found" );
}
}
StringBuilder url = new StringBuilder("/module/reporting/reports/renderers/defaultReportDesignEditor.form?type=" + type.getName());
if (ObjectUtil.notNull(reportDesignUuid)) {
url.append("&reportDesignUuid=" + reportDesignUuid);
}
if (ObjectUtil.notNull(reportDefinitionUuid)) {
url.append("&reportDefinitionUuid=" + reportDefinitionUuid);
}
if (ObjectUtil.notNull(returnUrl)) {
url.append("&returnUrl=" + returnUrl);
}
return "redirect:"+url.toString();
}
/**
*
* Edit page for a report design that does not have a custom editor
*/
@RequestMapping("/module/reporting/reports/renderers/defaultReportDesignEditor")
public void defaultReportDesignRenderer(ModelMap model,
@RequestParam(required=true, value="type") Class<? extends ReportRenderer> type,
@RequestParam(required=false, value="reportDesignUuid") String reportDesignUuid,
@RequestParam(required=false, value="reportDefinitionUuid") String reportDefinitionUuid,
@RequestParam(required=false, value="returnUrl") String returnUrl) {
StringBuilder parameters = new StringBuilder();
parameters.append("type="+type.getName());
if (ObjectUtil.notNull(reportDesignUuid)) {
parameters.append("|reportDesignUuid=" + reportDesignUuid);
}
if (ObjectUtil.notNull(reportDefinitionUuid)) {
parameters.append("|reportDefinitionUuid=" + reportDefinitionUuid);
}
if (ObjectUtil.notNull(returnUrl)) {
parameters.append("|returnUrl=" + returnUrl);
}
model.addAttribute("parameters", parameters);
}
/**
* Provide all reports processor configurations, to a page that lists them and provides options for working with them.
*/
@RequestMapping("/module/reporting/reports/manageReportProcessors")
public void manageReportProcessors(ModelMap model) {
List<ReportProcessorConfiguration> configs = Context.getService(ReportService.class).getAllReportProcessorConfigurations(false);
model.addAttribute("reportProcessorConfigurations", configs);
}
/**
* Provide all reports designs, optionally including those that are retired, to a page
* that lists them and provides options for working with them.
*/
@RequestMapping("/module/reporting/reports/viewReportDesignResource")
public void viewDesignContent(ModelMap model,
HttpServletResponse response,
@RequestParam(required=true, value="designUuid") String designUuid,
@RequestParam(required=true, value="resourceUuid") String resourceUuid) {
ReportDesign d = Context.getService(ReportService.class).getReportDesignByUuid(designUuid);
ReportDesignResource r = d.getResourceByUuid(resourceUuid);
response.setHeader("Pragma", "No-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Content-Disposition", "attachment; filename=" + r.getResourceFilename());
try {
response.getOutputStream().write(r.getContents());
}
catch (Exception e) {
throw new RuntimeException("Unable to render contents of file", e);
}
}
@RequestMapping("/module/reporting/reports/purgeReport")
public String purgeReportDefinition(@RequestParam(required=false, value="uuid") String uuid) {
ReportDefinitionService rds = Context.getService(ReportDefinitionService.class);
rds.purgeDefinition(rds.getDefinitionByUuid(uuid));
return "redirect:/module/reporting/reports/manageReports.form";
}
/**
* Renders a report to the response output stream, given a report definition, rendering mode, and optional patient id
* @param patientIdOrUuid the id or uuid of patient whose summary you wish to view
*/
@RequestMapping("/module/reporting/reports/renderReport")
public void renderReport(ModelMap model, HttpServletRequest request, HttpServletResponse response,
@RequestParam("reportDefinition") String reportDefinitionUuid,
@RequestParam("renderingMode") String renderingModeDescriptor,
@RequestParam(value="patient", required=false) String patientIdOrUuid,
@RequestParam(value="download", required=false) boolean download) throws IOException {
try {
ReportDefinition rd = getReportDefinitionService().getDefinitionByUuid(reportDefinitionUuid);
if (rd == null) {
throw new IllegalArgumentException("Unable to find report with passed uuid = " + reportDefinitionUuid);
}
RenderingMode renderingMode = new RenderingMode(renderingModeDescriptor);
if (!renderingMode.getRenderer().canRender(rd)) {
throw new IllegalArgumentException("Rendering mode chosen cannot render passed report definition");
}
EvaluationContext context = new EvaluationContext();
if (StringUtils.isNotBlank(patientIdOrUuid)) {
Cohort c = new Cohort();
Patient p = Context.getPatientService().getPatientByUuid(patientIdOrUuid);
if (p != null) {
c.addMember(p.getPatientId());
}
else {
c.addMember(Integer.parseInt(patientIdOrUuid));
}
context.setBaseCohort(c);
}
// If the report takes in additional parameters, try to retrieve these from the request
for (Parameter p : rd.getParameters()) {
String[] parameterValues = request.getParameterValues(p.getName());
if (parameterValues != null && parameterValues.length > 0) {
Object value = null;
if (parameterValues.length == 1) {
value = WidgetUtil.parseInput(parameterValues[0], p.getType(), p.getCollectionType());
}
else {
List l = new ArrayList();
for (String v : parameterValues) {
l.add(WidgetUtil.parseInput(parameterValues[0], p.getType()));
}
value = l;
}
context.addParameterValue(p.getName(), value);
}
}
ReportData reportData = getReportDefinitionService().evaluate(rd, context);
ReportRequest reportRequest = new ReportRequest();
reportRequest.setReportDefinition(new Mapped<ReportDefinition>(rd, context.getParameterValues()));
reportRequest.setRenderingMode(renderingMode);
String contentType = renderingMode.getRenderer().getRenderedContentType(reportRequest);
String fileName = renderingMode.getRenderer().getFilename(reportRequest);
response.setHeader("Content-Type", contentType);
if (download) {
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
}
renderingMode.getRenderer().render(reportData, renderingMode.getArgument(), response.getOutputStream());
}
catch (Exception e) {
e.printStackTrace(response.getWriter());
}
}
private ReportDefinitionService getReportDefinitionService() {
return Context.getService(ReportDefinitionService.class);
}
}