=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java 2010-12-04 01:31:11 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java 2010-12-05 19:09:58 +0000 @@ -45,11 +45,12 @@ implements Serializable, Comparable { public static final String SEPARATOR = "."; - + + private static final String TYPE_VALUE = "value"; + private static final String TYPE_TOTAL = "total"; + private static final String SPACE = ""; - private static final String COLUMN_PREFIX = "de"; - private static final String COLUMN_SEPARATOR = "_"; // ------------------------------------------------------------------------- @@ -81,6 +82,8 @@ private List aggregationLevels = new ArrayList(); private int frequencyOrder; + + private String operandType; // ------------------------------------------------------------------------- // Constructors @@ -175,29 +178,12 @@ } /** - * Generates a DataElementOperand based on the given formula. The formula - * needs to be on the form "[,]". - * - * @param formula the formula. - * @return a DataElementOperand. - */ - public static DataElementOperand getOperand( String formula ) - { - formula = formula.replaceAll( "[\\[\\]]", "" ); //TODO fix - - final int dataElementId = Integer.parseInt( formula.substring( 0, formula.indexOf( SEPARATOR ) ) ); - final int categoryOptionComboId = Integer.parseInt( formula.substring( formula.indexOf( SEPARATOR ) + 1, - formula.length() ) ); - - return new DataElementOperand( dataElementId, categoryOptionComboId ); - } - - /** * Returns a name based on the DataElement and the * DataElementCategoryOptionCombo. * * @return the name. */ + //TODO remove? public String getPersistedName() { return dataElement.getName() + SPACE + categoryOptionCombo.getName(); @@ -214,11 +200,25 @@ return dataElement.getId() + SEPARATOR + categoryOptionCombo.getId(); } + /** + * Returns a database-friendly name. + * + * @return the name. + */ + //TODO rename public String getSimpleName() { return COLUMN_PREFIX + dataElementId + COLUMN_SEPARATOR + optionComboId; } + /** + * Returns a pretty-print name based on the given data element and category + * option combo. + * + * @param dataElement the data element. + * @param categoryOptionCombo the category option combo. + * @return the name. + */ public String getPrettyName( DataElement dataElement, DataElementCategoryOptionCombo categoryOptionCombo ) { if ( dataElement == null || categoryOptionCombo == null ) @@ -228,7 +228,22 @@ return categoryOptionCombo.isDefault() ? dataElement.getName() : dataElement.getName() + SPACE + categoryOptionCombo.getName(); } + + /** + * Indicators whether this operand represents a total value or not. + * + * @return true or false. + */ + public boolean isTotal() + { + return operandType != null && operandType.equals( TYPE_TOTAL ); + } + /** + * Updates all transient + * @param dataElement + * @param categoryOptionCombo + */ public void updateProperties( DataElement dataElement, DataElementCategoryOptionCombo categoryOptionCombo ) { this.dataElementId = dataElement.getId(); @@ -241,6 +256,44 @@ this.valueType = dataElement.getType(); } + /** + * Generates a DataElementOperand based on the given formula. The formula + * needs to be on the form "[,]". + * + * @param formula the formula. + * @return a DataElementOperand. + */ + public static DataElementOperand getOperand( String formula ) + throws NumberFormatException + { + formula = formula.replaceAll( "[\\[\\]]", "" ); + + int dataElementId = 0; + int categoryOptionComboId = 0; + String operandType = null; + + if ( formula.contains( SEPARATOR ) ) // Value + { + dataElementId = Integer.parseInt( formula.substring( 0, formula.indexOf( SEPARATOR ) ) ); + categoryOptionComboId = Integer.parseInt( formula.substring( formula.indexOf( SEPARATOR ) + 1, formula.length() ) ); + + operandType = TYPE_VALUE; + } + else // Total + { + dataElementId = Integer.parseInt( formula ); + + operandType = TYPE_TOTAL; + } + + DataElementOperand operand = new DataElementOperand(); + operand.setDataElementId( dataElementId ); + operand.setOptionComboId( categoryOptionComboId ); + operand.setOperandType( operandType ); + + return operand; + } + // ------------------------------------------------------------------------- // Getters & setters // ------------------------------------------------------------------------- @@ -355,6 +408,16 @@ this.frequencyOrder = frequencyOrder; } + public String getOperandType() + { + return operandType; + } + + public void setOperandType( String operandType ) + { + this.operandType = operandType; + } + // ------------------------------------------------------------------------- // hashCode, equals, toString, compareTo // ------------------------------------------------------------------------- === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java 2010-04-12 21:23:33 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java 2010-12-05 18:52:18 +0000 @@ -35,7 +35,16 @@ /** * An Expression is the expression of e.g. a validation rule. It consist of a * String representation of the rule as well as references to the data elements - * included in the expression. + * and category option combos included in the expression. + * + * The expression can contain numbers and mathematical operators and contain references + * to data elements and category option combos on the form: + * + * i) [1.2] where 1 refers to the data element identifier and 2 refers to the + * category option combo identifier. + * + * ii) [1] where 1 refers to the data element identifier, in this case the formula + * represents the total value for all category option combos for that data element. * * @author Margrethe Store * @version $Id: Expression.java 5011 2008-04-24 20:41:28Z larshelg $ === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java 2010-12-04 00:03:38 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java 2010-12-05 18:52:18 +0000 @@ -49,8 +49,7 @@ final String VALID = "valid"; final String EXPRESSION_IS_EMPTY = "expression_is_empty"; - final String DATAELEMENT_ID_NOT_NUMERIC = "dataelement_id_not_numeric"; - final String CATEGORYOPTIONCOMBO_ID_NOT_NUMERIC = "category_option_combo_id_not_numeric"; + final String ID_NOT_NUMERIC = "id_not_numeric"; final String DATAELEMENT_DOES_NOT_EXIST = "data_element_does_not_exist"; final String CATEGORYOPTIONCOMBO_DOES_NOT_EXIST = "category_option_combo_does_not_exist"; final String EXPRESSION_NOT_WELL_FORMED = "expression_not_well_formed"; === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java 2010-12-05 17:38:27 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java 2010-12-05 18:52:18 +0000 @@ -249,56 +249,39 @@ return EXPRESSION_IS_EMPTY; } - StringBuffer buffer = new StringBuffer(); + final StringBuffer buffer = new StringBuffer(); final Matcher matcher = FORMULA_PATTERN.matcher( formula ); - int dataElementId = -1; - int categoryOptionComboId = -1; - while ( matcher.find() ) { - String match = matcher.group(); - - match = match.replaceAll( "[\\[\\]]", "" ); - - final String dataElementIdString = match.substring( 0, match.indexOf( SEPARATOR ) ); - final String categoryOptionComboIdString = match.substring( match.indexOf( SEPARATOR ) + 1, match.length() ); - - try - { - dataElementId = Integer.parseInt( dataElementIdString ); - } - catch ( NumberFormatException ex ) - { - return DATAELEMENT_ID_NOT_NUMERIC; - } - - try - { - categoryOptionComboId = Integer.parseInt( categoryOptionComboIdString ); - } - catch ( NumberFormatException ex ) - { - return CATEGORYOPTIONCOMBO_ID_NOT_NUMERIC; - } - - if ( !dataElementService.dataElementExists( dataElementId ) ) + DataElementOperand operand = null; + + try + { + operand = DataElementOperand.getOperand( matcher.group() ); + } + catch ( NumberFormatException ex ) + { + return ID_NOT_NUMERIC; + } + + if ( !dataElementService.dataElementExists( operand.getDataElementId() ) ) { return DATAELEMENT_DOES_NOT_EXIST; } - if ( !dataElementService.dataElementCategoryOptionComboExists( categoryOptionComboId ) ) + if ( !operand.isTotal() && !dataElementService.dataElementCategoryOptionComboExists( operand.getOptionComboId() ) ) { return CATEGORYOPTIONCOMBO_DOES_NOT_EXIST; } // ----------------------------------------------------------------- - // Replacing the operand with 1 in order to later be able to verify + // Replacing the operand with 1.1 in order to later be able to verify // that the formula is mathematically valid // ----------------------------------------------------------------- - matcher.appendReplacement( buffer, "1.0" ); + matcher.appendReplacement( buffer, "1.1" ); } matcher.appendTail( buffer ); === modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java' --- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java 2010-08-31 08:14:32 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java 2010-12-05 18:52:18 +0000 @@ -216,11 +216,11 @@ expressionA = "[" + "foo" + SEPARATOR + categoryOptionComboId + "] + 12"; - assertEquals( ExpressionService.DATAELEMENT_ID_NOT_NUMERIC, expressionService.expressionIsValid( expressionA ) ); + assertEquals( ExpressionService.ID_NOT_NUMERIC, expressionService.expressionIsValid( expressionA ) ); expressionA = "[" + dataElementIdA + SEPARATOR + "foo" + "] + 12"; - assertEquals( ExpressionService.CATEGORYOPTIONCOMBO_ID_NOT_NUMERIC, expressionService.expressionIsValid( expressionA ) ); + assertEquals( ExpressionService.ID_NOT_NUMERIC, expressionService.expressionIsValid( expressionA ) ); expressionA = "[" + 999 + SEPARATOR + categoryOptionComboId + "] + 12"; === modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/resources/i18n_global.properties' --- dhis-2/dhis-web/dhis-web-commons/src/main/resources/i18n_global.properties 2010-12-05 17:38:27 +0000 +++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/i18n_global.properties 2010-12-05 19:09:58 +0000 @@ -435,6 +435,8 @@ denominator_formula = Denominator formula denominator_description = Denominator description denominator_aggregation_operator = Denominator aggregation operator +expression_is_empty = Expression is empty category_option_combo_does_not_exist = Category option combo does not exist data_element_does_not_exist = Data element does not exist - +id_not_numeric = Identifier is not numeric +expression_not_well_formed = Expression is not well-formed