/** * 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.dataset.definition.evaluator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.Obs; import org.openmrs.annotation.Handler; import org.openmrs.module.reporting.common.BeanPropertyComparator; import org.openmrs.module.reporting.common.ObjectCounter; import org.openmrs.module.reporting.common.ObjectUtil; import org.openmrs.module.reporting.data.converter.ObsValueConverter; import org.openmrs.module.reporting.data.encounter.definition.ObsForEncounterDataDefinition; import org.openmrs.module.reporting.data.encounter.library.BuiltInEncounterDataLibrary; import org.openmrs.module.reporting.dataset.DataSet; import org.openmrs.module.reporting.dataset.DataSetColumn; import org.openmrs.module.reporting.dataset.DataSetRow; import org.openmrs.module.reporting.dataset.SimpleDataSet; import org.openmrs.module.reporting.dataset.definition.DataSetDefinition; import org.openmrs.module.reporting.dataset.definition.EncounterAndObsDataSetDefinition; import org.openmrs.module.reporting.evaluation.EvaluationContext; import org.openmrs.module.reporting.evaluation.EvaluationException; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * The logic that evaluates a {@link EncounterAndObsDataSetDefinition} and produces an {@link DataSet} * @see EncounterAndObsDataSetDefinition */ @Handler(supports = { EncounterAndObsDataSetDefinition.class }, order = 25) public class EncounterAndObsDataSetEvaluator extends EncounterDataSetEvaluator { protected static final Log log = LogFactory.getLog(EncounterAndObsDataSetEvaluator.class); @Autowired BuiltInEncounterDataLibrary encounterData; /** * @see DataSetEvaluator#evaluate(DataSetDefinition, EvaluationContext) * @should evaluate an EncounterAndObsDataSetDefinition */ public DataSet evaluate(DataSetDefinition dataSetDefinition, EvaluationContext context) throws EvaluationException { EncounterAndObsDataSetDefinition dsd = (EncounterAndObsDataSetDefinition) dataSetDefinition; // If no specific columns definitions are specified, use some defaults if (dsd.getColumnDefinitions().isEmpty()) { dsd.addColumn("ENCOUNTER_ID", encounterData.getEncounterId(), ""); dsd.addColumn("PATIENT_ID", encounterData.getPatientId(), ""); dsd.addColumn("ENCOUNTER_TYPE", encounterData.getEncounterTypeName(), ""); dsd.addColumn("ENCOUNTER_DATETIME", encounterData.getEncounterDatetime(), ""); dsd.addColumn("LOCATION", encounterData.getLocationName(), ""); } // Add all Obs for each encounter ObsForEncounterDataDefinition allObs = new ObsForEncounterDataDefinition(); allObs.setSingleObs(false); dsd.addColumn("OBS", allObs, ""); // Produce the core starting data set for encounter data SimpleDataSet data = (SimpleDataSet) super.evaluate(dsd, context); // Determine all necessary column headers and get necessary obs data to populate these Map<String, DataSetColumn> obsColumnMap = new HashMap<String, DataSetColumn>(); ObsValueConverter obsValueConverter = new ObsValueConverter(); // Get the maximum number of occurrences for each Obs column, to determine which need to have sequence numbers appended Map<String, Integer> maxNumForKey = new HashMap<String, Integer>(); for (DataSetRow row : data.getRows()) { List<Obs> obsList = (List<Obs>)row.getColumnValue("OBS"); if (obsList != null) { ObjectCounter<String> currentNumForKey = new ObjectCounter<String>(); for (Obs obs : obsList) { String key = getObsKey(obs); if (key != null) { currentNumForKey.increment(key); } } for (Map.Entry<String, Integer> e : currentNumForKey.getAllObjectCounts().entrySet()) { Integer existing = maxNumForKey.get(e.getKey()); if (existing == null || (existing < e.getValue())) { maxNumForKey.put(e.getKey(), e.getValue()); } } } } // Add the Obs values to each dataset row for (DataSetRow row : data.getRows()) { List<Obs> obsList = (List<Obs>)row.getColumnValue("OBS"); if (obsList != null) { ObjectCounter<String> currentNumForKey = new ObjectCounter<String>(); for (Obs obs : obsList) { String key = getObsKey(obs); if (key != null) { int num = currentNumForKey.increment(key); String columnName = ObjectUtil.format(obs.getConcept()).replaceAll("\\s", "_").replaceAll("-", "_").toUpperCase(); if (maxNumForKey.get(key) > 1) { columnName = columnName + "_" + num; } DataSetColumn obsColumn = obsColumnMap.get(columnName); if (obsColumn == null) { obsColumn = new DataSetColumn(columnName, columnName, Object.class); obsColumnMap.put(columnName, obsColumn); } row.addColumnValue(obsColumn, obsValueConverter.convert(obs)); } } } row.removeColumn("OBS"); } data.getMetaData().removeColumn("OBS"); // Sort the obs columns by name, and add to metadata List<DataSetColumn> obsColumns = new ArrayList<DataSetColumn>(obsColumnMap.values()); Collections.sort(obsColumns, new BeanPropertyComparator("name")); data.getMetaData().getColumns().addAll(obsColumns); return data; } protected String getObsKey(Obs obs) { if (obs.isObsGrouping()) { return null; } StringBuilder key = new StringBuilder(obs.getConcept().getConceptId().toString()); for (Obs toCheck = obs.getObsGroup(); toCheck != null; toCheck = toCheck.getObsGroup() ) { key.append("_").append(toCheck.getConcept().getConceptId()); } return key.toString(); } }