← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 16553: Expression, replaced boolean nullIfBlank with enum MissingValueStrategy, with options SKIP_IF_ANY...

 

------------------------------------------------------------
revno: 16553
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2014-08-28 14:01:44 +0200
message:
  Expression, replaced boolean nullIfBlank with enum MissingValueStrategy, with options SKIP_IF_ANY_VALUE_MISSING, SKIP_IF_ALL_VALUES_MISSING, NEVER_SKIP. Using this in validation rules. Useful to separate between situations where you want the validation rule to be skipped if there are no values present at all, and where you want the validation rule to be skipped if there are one or more values missing.
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/MissingValueStrategy.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/MissingValueStrategyUserType.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.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/java/org/hisp/dhis/startup/TableAlteror.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/expression/hibernate/Expression.hbm.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-dxf2/src/main/java/org/hisp/dhis/dxf2/csv/DefaultCsvImportService.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm
  dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/AddValidationRuleAction.java
  dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/UpdateValidationRuleAction.java
  dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties
  dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/addValidationRuleForm.vm
  dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/expressionBuilderForm.vm
  dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expression.js
  dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expressionBuilder.js
  dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/updateValidationRuleForm.vm


--
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/expression/Expression.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java	2014-08-27 09:20:22 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java	2014-08-28 12:01:44 +0000
@@ -96,10 +96,10 @@
     private String description;
 
     /**
-     * Indicates whether the expression should evaluate to null if there are
-     * missing data values in the expression.
+     * Indicates whether the expression should evaluate to null if all or any
+     * data values are missing in the expression.
      */
-    private boolean nullIfBlank;
+    private MissingValueStrategy missingValueStrategy;
 
     /**
      * A reference to the DataElements in the Expression.
@@ -267,7 +267,7 @@
     }
 
     @JsonProperty
-    @JsonView( { DetailedView.class, ExportView.class } )
+    @JsonView({ DetailedView.class, ExportView.class })
     @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
     public String getDescription()
     {
@@ -282,15 +282,15 @@
     @JsonProperty
     @JsonView({ DetailedView.class, ExportView.class })
     @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0)
-    public boolean isNullIfBlank()
+    public MissingValueStrategy getMissingValueStrategy()
     {
-        return nullIfBlank;
+        return missingValueStrategy;
     }
 
-    public void setNullIfBlank( boolean nullIfBlank )
+    public void setMissingValueStrategy( MissingValueStrategy missingValueStrategy )
     {
-        this.nullIfBlank = nullIfBlank;
-    }
+        this.missingValueStrategy = missingValueStrategy;
+    }    
 
     @JsonIgnore
     public String getExplodedExpression()
@@ -309,7 +309,7 @@
 
         expression = other.getExpression() == null ? expression : other.getExpression();
         description = other.getDescription() == null ? description : other.getDescription();
-        nullIfBlank = other.isNullIfBlank();
+        missingValueStrategy = other.getMissingValueStrategy() == null ? missingValueStrategy : other.getMissingValueStrategy();
 
         dataElementsInExpression = other.getDataElementsInExpression() == null ?
             dataElementsInExpression : new HashSet<>( other.getDataElementsInExpression() );

=== 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	2014-08-05 22:30:52 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2014-08-28 12:01:44 +0000
@@ -350,10 +350,13 @@
      * @param constantMap the mapping between the constant uid and value to use
      *        in the calculation.
      * @param orgUnitCountMap the mapping between organisation unit group uid and
-     *        count of org units to use in the calculation.
+     *        count of organisation units to use in the calculation.
      * @param days the number of days to use in the calculation.
+     * @param missingValueStrategy the strategy to use when data values are missing
+     *        when calculating the expression. Strategy defaults to NEVER_SKIP if null.
      */
-    String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, boolean nullIfNoValues );
+    String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, 
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, MissingValueStrategy missingValueStrategy );
     
     /**
      * Returns all Operands included in the formulas for the given collection of

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/MissingValueStrategy.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/MissingValueStrategy.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/MissingValueStrategy.java	2014-08-28 12:01:44 +0000
@@ -0,0 +1,61 @@
+package org.hisp.dhis.expression;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @author Lars Helge Overland
+ */
+public enum MissingValueStrategy
+{
+    SKIP_IF_ANY_VALUE_MISSING( "skip_if_any_value_missing" ),
+    SKIP_IF_ALL_VALUES_MISSING( "skip_if_all_values_missing" ),
+    NEVER_SKIP( "never_skip" );    
+
+    private final String value;
+
+    private MissingValueStrategy( String value )
+    {
+        this.value = value;
+    }
+
+    public String getValue()
+    {
+        return value;
+    }
+    
+    public static MissingValueStrategy safeValueOf( String value )
+    {
+        return value != null ? MissingValueStrategy.valueOf( value ) : null;
+    }
+
+    public static MissingValueStrategy safeValueOf( String value, MissingValueStrategy defaultValue )
+    {
+        return value != null ? MissingValueStrategy.valueOf( value ) : defaultValue;
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java	2014-08-25 11:42:12 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java	2014-08-28 12:01:44 +0000
@@ -97,7 +97,9 @@
     
     public void update( Integer lastYears, TaskId taskId )
     {
-        Clock clock = new Clock().startClock().logTime( "Starting update, no of processes: " + getProcessNo() );
+        int processNo = getProcessNo();
+        
+        Clock clock = new Clock().startClock().logTime( "Starting update, no of processes: " + processNo );
         
         String validState = tableManager.validState();
         
@@ -111,7 +113,7 @@
         
         clock.logTime( "Partition tables: " + tables + ", last years: " + lastYears );
         
-        notifier.notify( taskId, "Creating analytics tables" );
+        notifier.notify( taskId, "Creating analytics tables, last years: " + lastYears + ", processes: " + processNo );
         
         createTables( tables );
         

=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/MissingValueStrategyUserType.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/MissingValueStrategyUserType.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/MissingValueStrategyUserType.java	2014-08-28 12:01:44 +0000
@@ -0,0 +1,44 @@
+package org.hisp.dhis.common;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.expression.MissingValueStrategy;
+import org.hisp.dhis.hibernate.EnumUserType;
+
+/**
+ * @author Lars Helge Overland
+ */
+public class MissingValueStrategyUserType
+    extends EnumUserType<MissingValueStrategy>
+{
+    public MissingValueStrategyUserType()
+    {
+        super( MissingValueStrategy.class );
+    }
+}

=== 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	2014-08-15 07:40:20 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java	2014-08-28 12:01:44 +0000
@@ -35,6 +35,7 @@
 import static org.hisp.dhis.expression.Expression.SEPARATOR;
 import static org.hisp.dhis.system.util.MathUtils.calculateExpression;
 import static org.hisp.dhis.system.util.MathUtils.isEqual;
+import static org.hisp.dhis.expression.MissingValueStrategy.*;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -164,7 +165,8 @@
             return null;
         }
         
-        final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), valueMap, constantMap, orgUnitCountMap, days, false );
+        final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), 
+            valueMap, constantMap, orgUnitCountMap, days, NEVER_SKIP );
         
         if ( denominatorExpression == null )
         {
@@ -175,7 +177,8 @@
         
         if ( !isEqual( denominatorValue, 0d ) )
         {
-            final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), valueMap, constantMap, orgUnitCountMap, days, false );
+            final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), 
+                valueMap, constantMap, orgUnitCountMap, days, NEVER_SKIP );
             
             if ( numeratorExpression == null )
             {
@@ -197,21 +200,14 @@
     public Double getExpressionValue( Expression expression, Map<DataElementOperand, Double> valueMap,
         Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days )
     {
-        final String expressionString = generateExpression( expression.getExplodedExpressionFallback(), valueMap, constantMap, 
-            orgUnitCountMap, days, expression.isNullIfBlank() );
-
-        Double result = expressionString != null ? calculateExpression( expressionString ) : null;
-
-        log.debug( "Expression: " + expression.getExplodedExpressionFallback() + ", generated: " + expressionString + ", result: " + result );
-        
-        return result;
+        return getExpressionValue( expression, valueMap, constantMap, orgUnitCountMap, days, null );
     }
 
     public Double getExpressionValue( Expression expression, Map<DataElementOperand, Double> valueMap,
         Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, Set<DataElementOperand> incompleteValues )
     {
-        final String expressionString = generateExpression( expression.getExplodedExpressionFallback(), valueMap, constantMap, orgUnitCountMap, days,
-            expression.isNullIfBlank(), incompleteValues );
+        String expressionString = generateExpression( expression.getExplodedExpressionFallback(), valueMap, constantMap, 
+            orgUnitCountMap, days, expression.getMissingValueStrategy(), incompleteValues );
 
         Double result = expressionString != null ? calculateExpression( expressionString ) : null;
         
@@ -823,19 +819,21 @@
 
     @Transactional
     public String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, boolean nullIfNoValues )
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, MissingValueStrategy missingValueStrategy )
     {
-    	return generateExpression( expression, valueMap, constantMap, orgUnitCountMap, days, nullIfNoValues, null );
+    	return generateExpression( expression, valueMap, constantMap, orgUnitCountMap, days, missingValueStrategy, null );
     }
 
     private String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, boolean nullIfNoValues, Set<DataElementOperand> incompleteValues )
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, MissingValueStrategy missingValueStrategy, Set<DataElementOperand> incompleteValues )
     {
         if ( expression == null || expression.isEmpty() )
         {
             return null;
         }
         
+        missingValueStrategy = missingValueStrategy == null ? NEVER_SKIP : missingValueStrategy;
+        
         // ---------------------------------------------------------------------
         // Operands
         // ---------------------------------------------------------------------
@@ -843,22 +841,39 @@
         StringBuffer sb = new StringBuffer();
         Matcher matcher = OPERAND_PATTERN.matcher( expression );
         
+        int matchCount = 0;
+        int valueCount = 0;
+                
         while ( matcher.find() )
         {
+            matchCount++;
+            
             DataElementOperand operand = DataElementOperand.getOperand( matcher.group() );
 
             final Double value = valueMap.get( operand );
             
-            if ( nullIfNoValues && ( value == null || ( incompleteValues != null && incompleteValues.contains( operand ) ) ) )
+            boolean missingValue = value == null || ( incompleteValues != null && incompleteValues.contains( operand ) );
+            
+            if ( missingValue && SKIP_IF_ANY_VALUE_MISSING.equals( missingValueStrategy ) )
             {
                 return null;
             }
+            
+            if ( !missingValue )
+            {
+                valueCount++;
+            }
 
             String replacement = value != null ? String.valueOf( value ) : NULL_REPLACEMENT;
             
             matcher.appendReplacement( sb, replacement );
         }
         
+        if ( SKIP_IF_ALL_VALUES_MISSING.equals( missingValueStrategy ) && matchCount > 0 && valueCount == 0 )
+        {
+            return null;
+        }
+        
         expression = appendTail( matcher, sb );
         
         // ---------------------------------------------------------------------

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java	2014-08-26 10:51:19 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java	2014-08-28 12:01:44 +0000
@@ -722,6 +722,10 @@
 
         // validation rule group, new column alertbyorgunits
         executeSql( "UPDATE validationrulegroup SET alertbyorgunits=false WHERE alertbyorgunits IS NULL" );
+        
+        executeSql( "update expression set missingvaluestrategy = 'SKIP_IF_ANY_VALUE_MISSING' where nullifblank = true or nullifblank is null" );
+        executeSql( "update expression set missingvaluestrategy = 'NEVER_SKIP' where nullifblank = false" );
+        executeSql( "alter table expression alter column missingvaluestrategy set not null" );
 
         upgradeDataValuesWithAttributeOptionCombo();
         upgradeCompleteDataSetRegistrationsWithAttributeOptionCombo();

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/expression/hibernate/Expression.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/expression/hibernate/Expression.hbm.xml	2014-08-26 10:51:19 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/expression/hibernate/Expression.hbm.xml	2014-08-28 12:01:44 +0000
@@ -16,7 +16,7 @@
 
     <property name="expression" type="text" />
 
-	<property name="nullIfBlank" />
+    <property name="missingValueStrategy" column="missingvaluestrategy" type="org.hisp.dhis.common.MissingValueStrategyUserType" />
 
     <set name="dataElementsInExpression" table="expressiondataelement">
       <cache usage="read-write" />      

=== 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	2014-08-26 10:51:19 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java	2014-08-28 12:01:44 +0000
@@ -358,10 +358,10 @@
         Map<String, Integer> orgUnitCountMap = new HashMap<>();
         orgUnitCountMap.put( groupA.getUid(), groupA.getMembers().size() );
 
-        assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, false ) );
-        assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, false ) );
-        assertEquals( "12.0*2.0", expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, false ) );
-        assertEquals( "12.0*3", expressionService.generateExpression( expressionH, valueMap, constantMap, orgUnitCountMap, null, false ) );
+        assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, null ) );
+        assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, null ) );
+        assertEquals( "12.0*2.0", expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, null ) );
+        assertEquals( "12.0*3", expressionService.generateExpression( expressionH, valueMap, constantMap, orgUnitCountMap, null, null ) );
     }
 
     @Test
@@ -371,9 +371,9 @@
         
         Map<String, Double> constantMap = new HashMap<>();
 
-        assertNull( expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, true ) );
-        assertNull( expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, true ) );
-        assertNotNull( expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, false ) );
+        assertNull( expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, MissingValueStrategy.SKIP_IF_ANY_VALUE_MISSING ) );
+        assertNull( expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, MissingValueStrategy.SKIP_IF_ANY_VALUE_MISSING ) );
+        assertNotNull( expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, MissingValueStrategy.NEVER_SKIP ) );
     }
     
     @Test

=== 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	2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java	2014-08-28 12:01:44 +0000
@@ -164,11 +164,11 @@
                     {                
                         for ( final Indicator indicator : indicators )
                         {
-                            final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, constantMap, null, days, false ) );
+                            final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, constantMap, null, days, null ) );
     
                             if ( !isEqual( denominatorValue, 0d ) )
                             {
-                                final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, constantMap, null, days, false ) );
+                                final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, constantMap, null, days, null ) );
                              
                                 if ( !( omitZeroNumerator && isEqual( numeratorValue, 0d ) ) )
                                 {

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/csv/DefaultCsvImportService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/csv/DefaultCsvImportService.java	2014-08-26 10:51:19 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/csv/DefaultCsvImportService.java	2014-08-28 12:01:44 +0000
@@ -50,6 +50,7 @@
 import org.hisp.dhis.dxf2.metadata.MetaData;
 import org.hisp.dhis.expression.Expression;
 import org.hisp.dhis.expression.ExpressionService;
+import org.hisp.dhis.expression.MissingValueStrategy;
 import org.hisp.dhis.expression.Operator;
 import org.hisp.dhis.option.Option;
 import org.hisp.dhis.option.OptionSet;
@@ -259,15 +260,13 @@
                 
                 leftSide.setExpression( getSafe( values, 9, null, 255 ) );
                 leftSide.setDescription( getSafe( values, 10, null, 255 ) );
-                leftSide.setNullIfBlank( Boolean.valueOf( getSafe( values, 11, Boolean.FALSE.toString(), 5 ) ) );
+                leftSide.setMissingValueStrategy( MissingValueStrategy.safeValueOf( getSafe( values, 11, MissingValueStrategy.NEVER_SKIP.toString(), 50 ) ) );
                 leftSide.setDataElementsInExpression( expressionService.getDataElementsInExpression( leftSide.getExpression() ) );
-                leftSide.setNullIfBlank( true );
                 
                 rightSide.setExpression( getSafe( values, 12, null, 255 ) );
                 rightSide.setDescription( getSafe( values, 13, null, 255 ) );
-                rightSide.setNullIfBlank( Boolean.valueOf( getSafe( values, 14, Boolean.FALSE.toString(), 5 ) ) );
+                rightSide.setMissingValueStrategy( MissingValueStrategy.safeValueOf( getSafe( values, 14,  MissingValueStrategy.NEVER_SKIP.toString(), 50 ) ) );
                 rightSide.setDataElementsInExpression( expressionService.getDataElementsInExpression( rightSide.getExpression() ) );
-                rightSide.setNullIfBlank( true );
                 
                 object.setLeftSide( leftSide );
                 object.setRightSide( rightSide );

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm	2014-07-26 18:27:49 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm	2014-08-28 12:01:44 +0000
@@ -37,15 +37,15 @@
         <th>$i18n.getString( "organisation_unit_counts" )</th>
 	</tr>
 	<tr>
-		<td>
+		<td valign="top">
 			<input type="text" id="description" name="description" class="{validate:{required:true}}" style="width:100%"/>
 			<div class="tipText" style="margin-top: 4px">$i18n.getString( "tip" ): $i18n.getString( "use" ) abs(x) sin(x) cos(x) tan(x) ln(x) log(x) sqrt(x) mod(x,y)</div>
 		</td>
 		<td></td>
-		<td>
+		<td valign="top">
 			<select id="constantId" name="constantId" size="3" style="width:100%" ondblclick="insertText( 'expression', this.value )"></select>
 		</td>
-        <td>
+        <td valign="top">
             <select id="orgUnitGroupId" name="orgUnitGroupId" size="3" style="width:100%" ondblclick="insertText( 'expression', this.value )"></select>
         </td>
 	</tr>

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/AddValidationRuleAction.java'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/AddValidationRuleAction.java	2014-08-26 10:51:19 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/AddValidationRuleAction.java	2014-08-28 12:01:44 +0000
@@ -28,6 +28,9 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import static org.hisp.dhis.expression.MissingValueStrategy.SKIP_IF_ANY_VALUE_MISSING;
+import static org.hisp.dhis.expression.MissingValueStrategy.safeValueOf;
+
 import org.hisp.dhis.expression.Expression;
 import org.hisp.dhis.expression.ExpressionService;
 import org.hisp.dhis.expression.Operator;
@@ -133,11 +136,11 @@
         this.leftSideDescription = leftSideDescription;
     }
 
-    private boolean leftSideNullIfBlank;
+    private String leftSideMissingValueStrategy;
     
-    public void setLeftSideNullIfBlank( boolean leftSideNullIfBlank )
+    public void setLeftSideMissingValueStrategy( String leftSideMissingValueStrategy )
     {
-        this.leftSideNullIfBlank = leftSideNullIfBlank;
+        this.leftSideMissingValueStrategy = leftSideMissingValueStrategy;
     }
 
     private String rightSideExpression;
@@ -154,11 +157,11 @@
         this.rightSideDescription = rightSideDescription;
     }
     
-    private boolean rightSideNullIfBlank;
+    private String rightSideMissingValueStrategy;
 
-    public void setRightSideNullIfBlank( boolean rightSideNullIfBlank )
+    public void setRightSideMissingValueStrategy( String rightSideMissingValueStrategy )
     {
-        this.rightSideNullIfBlank = rightSideNullIfBlank;
+        this.rightSideMissingValueStrategy = rightSideMissingValueStrategy;
     }
 
     private Integer organisationUnitLevel;
@@ -213,14 +216,14 @@
         
         leftSide.setExpression( leftSideExpression );
         leftSide.setDescription( leftSideDescription );
-        leftSide.setNullIfBlank( leftSideNullIfBlank );
+        leftSide.setMissingValueStrategy( safeValueOf( leftSideMissingValueStrategy, SKIP_IF_ANY_VALUE_MISSING ) );
         leftSide.setDataElementsInExpression( expressionService.getDataElementsInExpression( leftSideExpression ) );
         
         Expression rightSide = new Expression();
         
         rightSide.setExpression( rightSideExpression );
         rightSide.setDescription( rightSideDescription );
-        rightSide.setNullIfBlank( rightSideNullIfBlank );
+        rightSide.setMissingValueStrategy( safeValueOf( rightSideMissingValueStrategy, SKIP_IF_ANY_VALUE_MISSING ) );
         rightSide.setDataElementsInExpression( expressionService.getDataElementsInExpression( rightSideExpression ) );
         
         ValidationRule validationRule = new ValidationRule();

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/UpdateValidationRuleAction.java'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/UpdateValidationRuleAction.java	2014-08-26 10:51:19 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/UpdateValidationRuleAction.java	2014-08-28 12:01:44 +0000
@@ -28,6 +28,9 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import static org.hisp.dhis.expression.MissingValueStrategy.SKIP_IF_ANY_VALUE_MISSING;
+import static org.hisp.dhis.expression.MissingValueStrategy.safeValueOf;
+
 import org.hisp.dhis.expression.ExpressionService;
 import org.hisp.dhis.expression.Operator;
 import org.hisp.dhis.period.PeriodService;
@@ -40,8 +43,6 @@
 /**
  * @author Margrethe Store
  * @author Lars Helge Overland
- * @version $Id: UpdateValidationRuleAction.java 3868 2007-11-08 15:11:12Z
- *          larshelg $
  */
 public class UpdateValidationRuleAction
     implements Action
@@ -138,11 +139,11 @@
         this.leftSideDescription = leftSideDescription;
     }
 
-    private boolean leftSideNullIfBlank;
+    private String leftSideMissingValueStrategy;
     
-    public void setLeftSideNullIfBlank( boolean leftSideNullIfBlank )
+    public void setLeftSideMissingValueStrategy( String leftSideMissingValueStrategy )
     {
-        this.leftSideNullIfBlank = leftSideNullIfBlank;
+        this.leftSideMissingValueStrategy = leftSideMissingValueStrategy;
     }
 
     private String rightSideExpression;
@@ -159,11 +160,11 @@
         this.rightSideDescription = rightSideDescription;
     }
 
-    private boolean rightSideNullIfBlank;
+    private String rightSideMissingValueStrategy;
 
-    public void setRightSideNullIfBlank( boolean rightSideNullIfBlank )
+    public void setRightSideMissingValueStrategy( String rightSideMissingValueStrategy )
     {
-        this.rightSideNullIfBlank = rightSideNullIfBlank;
+        this.rightSideMissingValueStrategy = rightSideMissingValueStrategy;
     }
 
     private Integer organisationUnitLevel;
@@ -225,12 +226,12 @@
 
         validationRule.getLeftSide().setExpression( leftSideExpression );
         validationRule.getLeftSide().setDescription( leftSideDescription );
-        validationRule.getLeftSide().setNullIfBlank( leftSideNullIfBlank );
+        validationRule.getLeftSide().setMissingValueStrategy( safeValueOf( leftSideMissingValueStrategy, SKIP_IF_ANY_VALUE_MISSING ) );
         validationRule.getLeftSide().setDataElementsInExpression( expressionService.getDataElementsInExpression( leftSideExpression ) );
 
         validationRule.getRightSide().setExpression( rightSideExpression );
         validationRule.getRightSide().setDescription( rightSideDescription );
-        validationRule.getRightSide().setNullIfBlank( rightSideNullIfBlank );
+        validationRule.getRightSide().setMissingValueStrategy( safeValueOf( rightSideMissingValueStrategy, SKIP_IF_ANY_VALUE_MISSING ) );
         validationRule.getRightSide().setDataElementsInExpression( expressionService.getDataElementsInExpression( rightSideExpression ) );
         validationRule.setOrganisationUnitLevel( organisationUnitLevel );
         

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties	2014-05-18 00:49:40 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties	2014-08-28 12:01:44 +0000
@@ -153,4 +153,7 @@
 number_of_user_groups_to_alert=Number of user groups to alert
 send_alerts=Send alerts
 visible_when_rule_is_violated=visible when rule is violated
-instruction=Instruction
\ No newline at end of file
+instruction=Instruction
+skip_if_any_value_is_missing=Skip if any value is missing
+skip_if_all_values_are_missing=Skip if all values are missing
+never_skip=Never skip

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/addValidationRuleForm.vm'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/addValidationRuleForm.vm	2014-03-04 00:22:37 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/addValidationRuleForm.vm	2014-08-28 12:01:44 +0000
@@ -97,13 +97,13 @@
 			<input type="hidden" id="leftSideDescription" name="leftSideDescription">
 			<input type="hidden" id="leftSideExpression" name="leftSideExpression">
 			<input type="hidden" id="leftSideTextualExpression" name="leftSideTextualExpression">
-			<input type="hidden" id="leftSideNullIfBlank" name="leftSideNullIfBlank">
+			<input type="hidden" id="leftSideMissingValueStrategy" name="leftSideMissingValueStrategy">
 			
 			<input type="button" value="$i18n.getString( 'edit_right_side' )" style="width:10em" onclick="editRightExpression();"></td>
 			<input type="hidden" id="rightSideDescription" name="rightSideDescription">
 			<input type="hidden" id="rightSideExpression" name="rightSideExpression">
 			<input type="hidden" id="rightSideTextualExpression" name="rightSideTextualExpression">
-			<input type="hidden" id="rightSideNullIfBlank" name="rightSideNullIfBlank">
+			<input type="hidden" id="rightSideMissingValueStrategy" name="rightSideMissingValueStrategy">
 		</td>	
 	</tr>
 	<tr>

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/expressionBuilderForm.vm'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/expressionBuilderForm.vm	2014-07-26 18:27:49 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/expressionBuilderForm.vm	2014-08-28 12:01:44 +0000
@@ -19,16 +19,20 @@
 	</colgroup>
 	<tr>
 		<th colspan="2">$i18n.getString( "description" )</th>		
-		<th>$i18n.getString( "constants" )</th>		
+		<th>$i18n.getString( "constants" )</th>
 	</tr>
 	<tr>
-		<td>
+		<td valign="top">
 			<input type="text" id="description" name="description" style="width:100%" class="{validate:{required:true}}"/><br>
-			<input type="checkbox" id="nullIfBlank" name="nullIfBlank" value="true">&nbsp;<label for="nullIfBlank">$encoder.htmlEncode( $i18n.getString( "skip_for_missing_values" ) )</label>
-			<div class="tipText" style="margin-top: 4px">$encoder.htmlEncode( $i18n.getString( "tip" ) ): $encoder.htmlEncode( $i18n.getString( "use" ) ) abs(x) ln(x) log(x) sqrt(x) mod(x,y)</div>
+			<input type="radio" id="missingValueStrategyA" name="missingValueStrategy" value="SKIP_IF_ANY_VALUE_MISSING">
+				<label for="missingValueStrategyA">$i18n.getString( "skip_if_any_value_is_missing" )</label><br>
+			<input type="radio" id="missingValueStrategyB" name="missingValueStrategy" value="SKIP_IF_ALL_VALUES_MISSING">
+				<label for="missingValueStrategyB">$i18n.getString( "skip_if_all_values_are_missing" )</label><br>
+			<input type="radio" id="missingValueStrategyC" name="missingValueStrategy" value="NEVER_SKIP">
+				<label for="missingValueStrategyC">$i18n.getString( "never_skip" )</label>
 		</td>
-		<td></td>
-		<td>
+		<td valign="top"></td>
+		<td valign="top">
 			<select id="constantId" name="constantId" size="3" style="width:100%" ondblclick="insertText( 'expression', this.value )">
 			</select>
 		</td>

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expression.js'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expression.js	2013-10-13 18:58:45 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expression.js	2014-08-28 12:01:44 +0000
@@ -63,7 +63,6 @@
         {
             addOptionById( "dataElementId", "[" + objects[i].operandId + "]", objects[i].operandName );
         }
-
     } );
 }
 
@@ -125,26 +124,6 @@
     } );
 }
 
-function validateExpressionReceived( xmlObject )
-{
-    var type = xmlObject.getAttribute( 'type' );
-    var message = xmlObject.firstChild.nodeValue;
-
-    if ( type == "success" )
-    {
-        var description = byId( "expDescription" ).value;
-        var expression = byId( "expression" ).value;
-        var textualDescription = byId( "textualExpression" ).innerHTML;
-        var side = byId( "side" ).value;
-        saveExpression( side, description, expression, textualDescription );
-        disable( 'periodTypeName' );
-    } 
-    else if ( type == "error" )
-    {
-        byId( "textualExpression" ).innerHTML = message;
-    }
-}
-
 function saveExpression( side, description, expression, textualDescription )
 {
     if ( side == "left" )

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expressionBuilder.js'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expressionBuilder.js	2014-07-26 18:27:49 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/javascript/expressionBuilder.js	2014-08-28 12:01:44 +0000
@@ -9,7 +9,7 @@
 		minWidth: 840,
 		minHeight: 560,
 		width: 840,
-		height: 630,
+		height: 655,
 		title: "Expression"
 	});
 		
@@ -24,11 +24,13 @@
 function editLeftExpression()
 {		
 	left = true;
+	var strategy = $( '#leftSideMissingValueStrategy' ).val();
+	strategy = ( strategy ) ? strategy : 'SKIP_IF_ANY_VALUE_MISSING';
 	
 	$( '#expression' ).val( $( '#leftSideExpression' ).val() );
 	$( '#description' ).val( $( '#leftSideDescription' ).val() );
 	$( '#formulaText' ).text( $( '#leftSideTextualExpression' ).val() );
-	$( '#nullIfBlank' ).attr( 'checked', ( $( '#leftSideNullIfBlank' ).val() == 'true' || $( '#leftSideNullIfBlank' ).val() == '' ) );
+	$( 'input[name="missingValueStrategy"][value="' + strategy + '"]' ).prop( 'checked', true );
 	
 	dialog.dialog("open");
 }
@@ -36,11 +38,13 @@
 function editRightExpression()
 {
 	left = false;
+	var strategy = $( '#rightSideMissingValueStrategy' ).val();
+	strategy = ( strategy ) ? strategy : 'SKIP_IF_ANY_VALUE_MISSING';
 	
 	$( '#expression' ).val( $( '#rightSideExpression' ).val() );
 	$( '#description' ).val( $( '#rightSideDescription' ).val() );
 	$( '#formulaText' ).text( $( '#rightSideTextualExpression' ).val() );
-	$( '#nullIfBlank' ).attr( 'checked', ( $( '#rightSideNullIfBlank' ).val() == 'true' || $( '#rightSideNullIfBlank' ).val() == '' ) );
+	$( 'input[name="missingValueStrategy"][value="' + strategy + '"]' ).prop( 'checked', true );
 	
 	dialog.dialog("open");
 }
@@ -116,8 +120,10 @@
 
 function insertExpression()
 {
-	var expression = $( '#expression' ).val();
-	var description = $( '#description' ).val();
+	var expression = $( '#expression' ).val(),
+		description = $( '#description' ).val(),
+		formulaText = $( '#formulaText' ).text(),
+		missingValueStrategy = $( 'input[name="missingValueStrategy"]:checked' ).val();
 	
 	jQuery.postJSON( '../dhis-web-commons-ajax-json/getExpressionText.action', 
 	{
@@ -127,23 +133,23 @@
 	{
 		if ( json.response == 'error' )
 		{
-			markInvalid( 'expression-container textarea[id=expression]' , json.message );
+			markInvalid( 'expression-container textarea[id=expression]', json.message );
 		}
 		else 
 		{								
 			if ( left )
 			{
 				$( '#leftSideExpression' ).val( expression );
-				$( '#leftSideDescription' ).val( description );					
-				$( '#leftSideTextualExpression' ).val( $( '#formulaText' ).text() );
-				$( '#leftSideNullIfBlank' ).val( $( '#nullIfBlank' ).is( ':checked' ) );
+				$( '#leftSideDescription' ).val( description );
+				$( '#leftSideTextualExpression' ).val( formulaText );
+				$( '#leftSideMissingValueStrategy' ).val( missingValueStrategy );
 			}
 			else
 			{
 				$( '#rightSideExpression' ).val( expression );
-				$( '#rightSideDescription' ).val( description );					
-				$( '#rightSideTextualExpression' ).val( $( '#formulaText' ).text() );
-				$( '#rightSideNullIfBlank' ).val( $( '#nullIfBlank' ).is( ':checked' ) );								
+				$( '#rightSideDescription' ).val( description );
+				$( '#rightSideTextualExpression' ).val( formulaText );
+				$( '#rightSideMissingValueStrategy' ).val( missingValueStrategy );
 			}
 			
 			dialog.dialog( "close" );

=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/updateValidationRuleForm.vm'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/updateValidationRuleForm.vm	2014-07-26 19:04:03 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/updateValidationRuleForm.vm	2014-08-28 12:01:44 +0000
@@ -105,13 +105,13 @@
 				<input type="hidden" id="leftSideDescription" name="leftSideDescription" value="$!validationRule.leftSide.description">
 				<input type="hidden" id="leftSideExpression" name="leftSideExpression" value="$!validationRule.leftSide.expression">
 				<input type="hidden" id="leftSideTextualExpression" name="leftSideTextualExpression" value="$!leftSideTextualExpression">
-				<input type="hidden" id="leftSideNullIfBlank" name="leftSideNullIfBlank" value="$!validationRule.leftSide.nullIfBlank">
+				<input type="hidden" id="leftSideMissingValueStrategy" name="leftSideMissingValueStrategy" value="$!validationRule.leftSide.missingValueStrategy">
 				
 				<input type="button" value="$i18n.getString( 'edit_right_side' )" style="width:10em" onclick="editRightExpression();">
 				<input type="hidden" id="rightSideDescription" name="rightSideDescription" value="$!validationRule.rightSide.description">
 				<input type="hidden" id="rightSideExpression" name="rightSideExpression" value="$!validationRule.rightSide.expression">
 				<input type="hidden" id="rightSideTextualExpression" name="rightSideTextualExpression" value="$!rightSideTextualExpression">
-				<input type="hidden" id="rightSideNullIfBlank" name="rightSideNullIfBlank" value="$!validationRule.rightSide.nullIfBlank">
+				<input type="hidden" id="rightSideMissingValueStrategy" name="rightSideMissingValueStrategy" value="$!validationRule.rightSide.missingValueStrategy">
 		</td>
 	</tr>
 	<tr>