← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 4036: Implemented support for constants in expressions, data mart and aggregation engine. Constants are...

 

------------------------------------------------------------
revno: 4036
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2011-06-29 17:25:19 +0200
message:
  Implemented support for constants in expressions, data mart and aggregation engine. Constants are useful when creating indicators with values which might appear in multiple expressions.
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/constant/ConstantService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java
  dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/indicator/IndicatorAggregation.java
  dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/constant/DefaultConstantService.java
  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/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java
  dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java
  dhis-2/dhis-services/dhis-service-datamart-default/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/dbms/HibernateDbmsManager.java
  dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/ehcache.xml
  dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/constant/ConstantService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/constant/ConstantService.java	2011-06-29 08:51:25 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/constant/ConstantService.java	2011-06-29 15:25:19 +0000
@@ -28,6 +28,7 @@
  */
 
 import java.util.Collection;
+import java.util.Map;
 
 /**
  * @author Dang Duy Hieu
@@ -53,6 +54,8 @@
 
     Collection<Constant> getAllConstants();
     
+    Map<Integer, Double> getConstantMap();
+    
     // -------------------------------------------------------------------------
     // Constant expanding
     // -------------------------------------------------------------------------

=== 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	2011-06-03 13:11:34 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2011-06-29 15:25:19 +0000
@@ -54,13 +54,17 @@
     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";
-
+    final String CONSTANT_DOES_NOT_EXIST = "constant_does_not_exist";
+
+
+    final String DAYS_DESCRIPTION = "[Number of days]";
     final String NULL_REPLACEMENT = "0";
     final String SPACE = " ";
 
     final String FORMULA_EXPRESSION = "\\[.+?\\]";
     final String OPERAND_EXPRESSION = "\\[\\d+?.*?\\]";
     final String DAYS_EXPRESSION = "[days]";
+    final String CONSTANT_EXPRESSION = "\\[C(\\d+?)\\]";
     
     /**
      * Adds a new Expression to the database.
@@ -212,5 +216,5 @@
      * @param valueMap The map containing data element identifiers and aggregated value.
      * @param days The number to be substituted with the days expression in the formula.
      */
-    String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Integer days );
+    String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Map<Integer, Double> constantMap, Integer days );
 }

=== modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/indicator/IndicatorAggregation.java'
--- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/indicator/IndicatorAggregation.java	2011-06-11 07:06:18 +0000
+++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/indicator/IndicatorAggregation.java	2011-06-29 15:25:19 +0000
@@ -27,9 +27,9 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import static org.hisp.dhis.system.util.DateUtils.daysBetween;
 import static org.hisp.dhis.system.util.MathUtils.INVALID;
 import static org.hisp.dhis.system.util.MathUtils.calculateExpression;
-import static org.hisp.dhis.system.util.DateUtils.daysBetween;
 
 import java.util.Date;
 import java.util.HashMap;
@@ -37,6 +37,7 @@
 import java.util.Set;
 
 import org.hisp.dhis.aggregation.impl.cache.AggregationCache;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
@@ -84,7 +85,14 @@
     {
         this.categoryService = categoryService;
     }
-    
+
+    private ConstantService constantService;
+
+    public void setConstantService( ConstantService constantService )
+    {
+        this.constantService = constantService;
+    }
+
     // -------------------------------------------------------------------------
     // Indicator aggregation
     // -------------------------------------------------------------------------
@@ -139,6 +147,8 @@
     
     private String generateExpression( String expression, Date startDate, Date endDate, OrganisationUnit organisationUnit, int days )
     {
+        Map<Integer, Double> constantMap = constantService.getConstantMap();
+        
         Set<DataElementOperand> operands = expressionService.getOperandsInExpression( expression );
         
         Map<DataElementOperand, Double> valueMap = new HashMap<DataElementOperand, Double>();
@@ -151,6 +161,6 @@
             valueMap.put( operand, aggregationCache.getAggregatedDataValue( dataElement, optionCombo, startDate, endDate, organisationUnit ) );            
         }
         
-        return expressionService.generateExpression( expression, valueMap, null );
+        return expressionService.generateExpression( expression, valueMap, constantMap, null );
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/resources/META-INF/dhis/beans.xml	2011-06-23 14:44:17 +0000
+++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/resources/META-INF/dhis/beans.xml	2011-06-29 15:25:19 +0000
@@ -57,6 +57,7 @@
     <property name="categoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
     <property name="expressionService" ref="org.hisp.dhis.expression.ExpressionService" />
     <property name="aggregationCache" ref="org.hisp.dhis.aggregation.impl.cache.AggregationCache" />
+	<property name="constantService" ref="org.hisp.dhis.constant.ConstantService" />
   </bean>
 
 </beans>

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/constant/DefaultConstantService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/constant/DefaultConstantService.java	2011-06-29 08:51:25 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/constant/DefaultConstantService.java	2011-06-29 15:25:19 +0000
@@ -27,6 +27,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.hisp.dhis.common.GenericIdentifiableObjectStore;
 import org.springframework.transaction.annotation.Transactional;
@@ -83,6 +85,18 @@
     {
         return constantStore.getAll();
     }
+    
+    public Map<Integer, Double> getConstantMap()
+    {
+        Map<Integer, Double> map = new HashMap<Integer, Double>();
+        
+        for ( Constant constant : getAllConstants() )
+        {
+            map.put( constant.getId(), constant.getValue() );
+        }
+        
+        return map;
+    }
 
     // -------------------------------------------------------------------------
     // Constant expanding

=== 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	2011-06-22 19:04:55 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java	2011-06-29 15:25:19 +0000
@@ -29,9 +29,9 @@
 
 import static org.hisp.dhis.expression.Expression.EXP_CLOSE;
 import static org.hisp.dhis.expression.Expression.EXP_OPEN;
+import static org.hisp.dhis.expression.Expression.PAR_CLOSE;
+import static org.hisp.dhis.expression.Expression.PAR_OPEN;
 import static org.hisp.dhis.expression.Expression.SEPARATOR;
-import static org.hisp.dhis.expression.Expression.PAR_OPEN;
-import static org.hisp.dhis.expression.Expression.PAR_CLOSE;
 import static org.hisp.dhis.system.util.MathUtils.calculateExpression;
 
 import java.util.Collection;
@@ -45,6 +45,8 @@
 import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.aggregation.AggregatedDataValueService;
 import org.hisp.dhis.common.GenericStore;
+import org.hisp.dhis.constant.Constant;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementCategoryCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
@@ -75,11 +77,8 @@
     private static final Log log = LogFactory.getLog( DefaultExpressionService.class );
 
     private final Pattern FORMULA_PATTERN = Pattern.compile( FORMULA_EXPRESSION );
-
     private final Pattern OPERAND_PATTERN = Pattern.compile( OPERAND_EXPRESSION );
 
-    private final String DAYS_DESCRIPTION = "[Number of days]";
-
     // -------------------------------------------------------------------------
     // Dependencies
     // -------------------------------------------------------------------------
@@ -97,6 +96,13 @@
     {
         this.dataElementService = dataElementService;
     }
+    
+    private ConstantService constantService;
+
+    public void setConstantService( ConstantService constantService )
+    {
+        this.constantService = constantService;
+    }
 
     private DataValueService dataValueService;
 
@@ -214,6 +220,8 @@
     public String convertExpression( String expression, Map<Object, Integer> dataElementMapping,
         Map<Object, Integer> categoryOptionComboMapping )
     {
+        //TODO constants
+        
         final StringBuffer convertedFormula = new StringBuffer();
 
         if ( expression != null )
@@ -231,13 +239,13 @@
 
                 if ( mappedDataElementId == null )
                 {
-                    log.info( "Data element identifier refers to non-existing object: " + operand.getDataElementId() );
+                    log.warn( "Data element identifier refers to non-existing object: " + operand.getDataElementId() );
 
                     match = NULL_REPLACEMENT;
                 }
                 else if ( !operand.isTotal() && mappedCategoryOptionComboId == null )
                 {
-                    log.info( "Category option combo identifer refers to non-existing object: "
+                    log.warn( "Category option combo identifer refers to non-existing object: "
                         + operand.getOptionComboId() );
 
                     match = NULL_REPLACEMENT;
@@ -292,7 +300,29 @@
 
             final String match = matcher.group();
 
-            if ( !DAYS_EXPRESSION.equals( match ) )
+            if ( DAYS_EXPRESSION.equals( match ) )
+            {
+                // Ignore
+            }
+            else if ( match.matches( CONSTANT_EXPRESSION ) )
+            {
+                Integer id = null;
+                
+                try
+                {
+                    id = Integer.parseInt( stripConstantExpression( match ) );
+                }
+                catch ( NumberFormatException ex )
+                {
+                    return ID_NOT_NUMERIC;
+                }
+                
+                if ( constantService.getConstant( id ) == null )
+                {
+                    return CONSTANT_DOES_NOT_EXIST;
+                }                    
+            }
+            else
             {
                 try
                 {
@@ -350,6 +380,19 @@
                 {
                     match = DAYS_DESCRIPTION;
                 }
+                else if ( match.matches( CONSTANT_EXPRESSION ) )
+                {
+                    final Integer id = Integer.parseInt( stripConstantExpression( match ) );
+                    
+                    final Constant constant = constantService.getConstant( id );
+                    
+                    if ( constant == null )
+                    {
+                        throw new IllegalArgumentException( "Identifier does not reference a constant: " + id );
+                    }
+                    
+                    match = constant.getName();
+                }
                 else
                 {
                     final DataElementOperand operand = DataElementOperand.getOperand( match );
@@ -436,11 +479,17 @@
             while ( matcher.find() )
             {
                 String match = matcher.group();
-
+                
                 if ( DAYS_EXPRESSION.equals( match ) ) // Days
                 {
                     match = days != null ? String.valueOf( days ) : NULL_REPLACEMENT;
                 }
+                else if ( match.matches( CONSTANT_EXPRESSION ) ) // Constant
+                {
+                    final Constant constant = constantService.getConstant( Integer.parseInt( stripConstantExpression( match ) ) );
+                    
+                    match = constant != null ? String.valueOf( constant.getValue() ) : NULL_REPLACEMENT; 
+                }
                 else // Operand
                 {
                     final DataElementOperand operand = DataElementOperand.getOperand( match );
@@ -465,7 +514,7 @@
                         return null;
                     }
 
-                    match = (value == null) ? NULL_REPLACEMENT : value;
+                    match = value != null ? value : NULL_REPLACEMENT;
                 }
 
                 matcher.appendReplacement( buffer, match );
@@ -477,7 +526,7 @@
         return buffer != null ? buffer.toString() : null;
     }
 
-    public String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Integer days )
+    public String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Map<Integer, Double> constantMap, Integer days )
     {
         StringBuffer buffer = null;
 
@@ -495,13 +544,19 @@
                 {
                     match = days != null ? String.valueOf( days ) : NULL_REPLACEMENT;
                 }
+                else if ( match.matches( CONSTANT_EXPRESSION ) ) // Constant
+                {
+                    final Double constant = constantMap.get( Integer.parseInt( stripConstantExpression( match ) ) );
+                    
+                    match = constant != null ? String.valueOf( constant ) : NULL_REPLACEMENT;
+                }
                 else // Operand
                 {
                     final DataElementOperand operand = DataElementOperand.getOperand( match );
 
                     final Double aggregatedValue = valueMap.get( operand );
 
-                    match = (aggregatedValue == null) ? NULL_REPLACEMENT : String.valueOf( aggregatedValue );
+                    match = aggregatedValue != null ? String.valueOf( aggregatedValue ) : NULL_REPLACEMENT;
                 }
 
                 matcher.appendReplacement( buffer, match );
@@ -512,4 +567,9 @@
 
         return buffer != null ? buffer.toString() : null;
     }
+    
+    private static final String stripConstantExpression( String match )
+    {
+        return match != null ? match.replaceAll( "[\\[C\\]]", "" ) : null;
+    }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2011-06-29 08:51:25 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2011-06-29 15:25:19 +0000
@@ -301,6 +301,7 @@
   <bean id="org.hisp.dhis.expression.ExpressionService" class="org.hisp.dhis.expression.DefaultExpressionService">
     <property name="expressionStore" ref="org.hisp.dhis.expression.ExpressionStore" />
     <property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />
+	<property name="constantService" ref="org.hisp.dhis.constant.ConstantService" />
     <property name="dataValueService" ref="org.hisp.dhis.datavalue.DataValueService" />
     <property name="aggregatedDataValueService" ref="org.hisp.dhis.aggregation.AggregatedDataValueService" />
     <property name="categoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />

=== 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	2011-06-03 13:11:34 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java	2011-06-29 15:25:19 +0000
@@ -41,6 +41,8 @@
 import java.util.Set;
 
 import org.hisp.dhis.DhisTest;
+import org.hisp.dhis.constant.Constant;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementCategory;
 import org.hisp.dhis.dataelement.DataElementCategoryCombo;
@@ -104,6 +106,8 @@
 
     private int categoryOptionComboId;
 
+    private int constantIdA;
+
     private String expressionA;
 
     private String expressionB;
@@ -111,11 +115,13 @@
     private String expressionC;
 
     private String expressionD;
+    
+    private String expressionE;
 
     private String descriptionA;
 
     private String descriptionB;
-
+    
     private Set<DataElement> dataElements = new HashSet<DataElement>();
 
     private Set<DataElementCategoryOptionCombo> optionCombos = new HashSet<DataElementCategoryOptionCombo>();
@@ -134,6 +140,8 @@
 
         categoryService = (DataElementCategoryService) getBean( DataElementCategoryService.ID );
 
+        constantService = (ConstantService) getBean( ConstantService.ID );
+        
         dataValueService = (DataValueService) getBean( DataValueService.ID );
 
         organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
@@ -188,12 +196,15 @@
 
         organisationUnitService.addOrganisationUnit( source );
 
+        constantIdA = constantService.saveConstant( new Constant( "ConstantA", 2.0 ) );
+        
         expressionA = "[" + dataElementIdA + SEPARATOR + categoryOptionComboId + "]+[" + dataElementIdB + SEPARATOR
             + categoryOptionComboId + "]";
         expressionB = "[" + dataElementIdC + SEPARATOR + categoryOptionComboId + "]-[" + dataElementIdD + SEPARATOR
             + categoryOptionComboId + "]";
         expressionC = "[" + dataElementIdA + SEPARATOR + categoryOptionComboId + "]+[" + dataElementIdE + "]-10";
         expressionD = "[" + dataElementIdA + SEPARATOR + categoryOptionComboId + "]+" + DAYS_EXPRESSION;
+        expressionE = "[" + dataElementIdA + SEPARATOR + categoryOptionComboId + "]*[C" + constantIdA + "]";
 
         descriptionA = "Expression A";
         descriptionB = "Expression B";
@@ -249,13 +260,25 @@
 
         Double value = expressionService.getExpressionValue( expression, period, source, false, false, null );
 
-        assertEquals( value, 15.0 );
+        assertEquals( value, 15.0, 0.1 );
 
         expression = new Expression( expressionB, descriptionB, dataElements, optionCombos );
 
         value = expressionService.getExpressionValue( expression, period, source, false, false, null );
 
-        assertEquals( 0.0, value );
+        assertEquals( 0.0, value, 0.1 );
+
+        expression = new Expression( expressionD, descriptionB, dataElements, optionCombos );
+
+        value = expressionService.getExpressionValue( expression, period, source, false, false, 5 );
+
+        assertEquals( 15.0, value, 0.1 );
+
+        expression = new Expression( expressionE, descriptionB, dataElements, optionCombos );
+
+        value = expressionService.getExpressionValue( expression, period, source, false, false, null );
+
+        assertEquals( 20.0, value, 0.1 );
     }
 
     @Test
@@ -306,6 +329,9 @@
     {
         assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionA ) );
         assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionB ) );
+        assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionC ) );
+        assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionD ) );
+        assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionE ) );
 
         expressionA = "[" + dataElementIdA + SEPARATOR + "foo" + "] + 12";
 
@@ -327,6 +353,14 @@
         expressionA = "12 x 4";
 
         assertEquals( ExpressionService.EXPRESSION_NOT_WELL_FORMED, expressionService.expressionIsValid( expressionA ) );
+        
+        expressionA = "12 + [Cfoo]";
+
+        assertEquals( ExpressionService.ID_NOT_NUMERIC, expressionService.expressionIsValid( expressionA ) );
+
+        expressionA = "12 + [C999999]";
+
+        assertEquals( ExpressionService.CONSTANT_DOES_NOT_EXIST, expressionService.expressionIsValid( expressionA ) );
     }
 
     @Test
@@ -335,6 +369,14 @@
         String description = expressionService.getExpressionDescription( expressionA );
 
         assertEquals( "DataElementA+DataElementB", description );
+        
+        description = expressionService.getExpressionDescription( expressionD );
+        
+        assertEquals( description, "DataElementA+" + ExpressionService.DAYS_DESCRIPTION );
+
+        description = expressionService.getExpressionDescription( expressionE );
+        
+        assertEquals( description, "DataElementA*ConstantA" );
     }
 
     @Test
@@ -343,6 +385,7 @@
         assertEquals( "10+5", expressionService.generateExpression( expressionA, period, source, false, false, null ) );
         assertEquals( "0-0", expressionService.generateExpression( expressionB, period, source, false, false, null ) );
         assertEquals( "10+7", expressionService.generateExpression( expressionD, period, source, false, false, 7 ) );
+        assertEquals( "10*2.0", expressionService.generateExpression( expressionE, period, source, false, false, null ) );
     }
 
     @Test
@@ -351,9 +394,13 @@
         Map<DataElementOperand, Double> valueMap = new HashMap<DataElementOperand, Double>();
         valueMap.put( new DataElementOperand( dataElementIdA, categoryOptionComboId ), new Double( 12 ) );
         valueMap.put( new DataElementOperand( dataElementIdB, categoryOptionComboId ), new Double( 34 ) );
+        
+        Map<Integer, Double> constantMap = new HashMap<Integer, Double>();
+        constantMap.put( constantIdA, 2.0 );
 
-        assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, null ) );
-        assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, 5 ) );
+        assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, constantMap, null ) );
+        assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, constantMap, 5 ) );
+        assertEquals( "12.0*2.0", expressionService.generateExpression( expressionE, valueMap, constantMap, null ) );
     }
 
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java'
--- dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java	2011-06-12 08:23:05 +0000
+++ dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java	2011-06-29 15:25:19 +0000
@@ -41,6 +41,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.aggregation.AggregatedIndicatorValue;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.datamart.aggregation.cache.AggregationCache;
 import org.hisp.dhis.datamart.crosstab.CrossTabService;
@@ -97,6 +98,13 @@
     {
         this.crossTabService = crossTabService;
     }
+    
+    private ConstantService constantService;
+
+    public void setConstantService( ConstantService constantService )
+    {
+        this.constantService = constantService;
+    }
 
     private BatchHandlerFactory batchHandlerFactory;
 
@@ -120,6 +128,8 @@
         
         final AggregatedIndicatorValue indicatorValue = new AggregatedIndicatorValue();
         
+        final Map<Integer, Double> constantMap = constantService.getConstantMap();
+        
         for ( final Period period : periods )
         {
             int days = daysBetween( period.getStartDate(), period.getEndDate() );
@@ -136,11 +146,11 @@
                 {                
                     for ( final Indicator indicator : indicators )
                     {
-                        final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, days ) );
+                        final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, constantMap, days ) );
 
                         if ( !isEqual( denominatorValue, 0d ) )
                         {
-                            final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, days ) );
+                            final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, constantMap, days ) );
                          
                             if ( !( omitZeroNumerator && isEqual( numeratorValue, 0d ) ) )
                             {

=== modified file 'dhis-2/dhis-services/dhis-service-datamart-default/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-datamart-default/src/main/resources/META-INF/dhis/beans.xml	2011-06-23 14:44:17 +0000
+++ dhis-2/dhis-services/dhis-service-datamart-default/src/main/resources/META-INF/dhis/beans.xml	2011-06-29 15:25:19 +0000
@@ -110,6 +110,7 @@
     <property name="aggregationCache" ref="org.hisp.dhis.datamart.aggregation.cache.AggregationCache" />
     <property name="systemSettingManager" ref="org.hisp.dhis.options.SystemSettingManager" />
     <property name="crossTabService" ref="org.hisp.dhis.datamart.crosstab.CrossTabService" />
+	<property name="constantService" ref="org.hisp.dhis.constant.ConstantService" />
     <property name="batchHandlerFactory" ref="batchHandlerFactory" />
   </bean>
     

=== modified file 'dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/dbms/HibernateDbmsManager.java'
--- dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/dbms/HibernateDbmsManager.java	2011-06-03 13:11:34 +0000
+++ dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/dbms/HibernateDbmsManager.java	2011-06-29 15:25:19 +0000
@@ -77,6 +77,7 @@
         emptyTable( "translation" );
         emptyTable( "importobject" );
         emptyTable( "importdatavalue" );
+        emptyTable( "constant" );
 
         emptyTable( "datavalue_audit" );
         emptyTable( "datavalue" );

=== modified file 'dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/ehcache.xml'
--- dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/ehcache.xml	2011-06-29 08:51:25 +0000
+++ dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/ehcache.xml	2011-06-29 15:25:19 +0000
@@ -124,7 +124,7 @@
     maxElementsInMemory="1000"/>
 	
   <cache name="org.hisp.dhis.constant.Constant"
-    maxElementsInMemory="1000"/>
+    maxElementsInMemory="200"/>
   
   <!-- Hibernate Associations -->
   

=== modified file 'dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java'
--- dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java	2011-06-07 16:12:23 +0000
+++ dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java	2011-06-29 15:25:19 +0000
@@ -39,6 +39,7 @@
 import org.hisp.dhis.aggregation.AggregatedDataValueService;
 import org.hisp.dhis.chart.Chart;
 import org.hisp.dhis.concept.Concept;
+import org.hisp.dhis.constant.ConstantService;
 import org.hisp.dhis.datadictionary.DataDictionary;
 import org.hisp.dhis.datadictionary.DataDictionaryService;
 import org.hisp.dhis.dataelement.DataElement;
@@ -134,6 +135,8 @@
 
     protected PeriodService periodService;
 
+    protected ConstantService constantService;
+    
     protected ValidationRuleService validationRuleService;
 
     protected ValidationCriteriaService validationCriteriaService;