dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #40417
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 20497: Program indicator, using lenient evaluation of expressions, useful for null handling
------------------------------------------------------------
revno: 20497
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Sun 2015-10-04 22:21:21 +0200
message:
Program indicator, using lenient evaluation of expressions, useful for null handling
modified:
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java
dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionFunctions.java
dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionUtils.java
dhis-2/dhis-support/dhis-support-commons/src/test/java/org/hisp/dhis/commons/util/ExpressionUtilsTest.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-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java 2015-09-27 09:29:50 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java 2015-10-04 20:21:21 +0000
@@ -62,7 +62,6 @@
import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValueService;
import org.hisp.dhis.trackedentitydatavalue.TrackedEntityDataValue;
import org.hisp.dhis.trackedentitydatavalue.TrackedEntityDataValueService;
-import org.hisp.dhis.util.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
@@ -81,6 +80,8 @@
put( DaysBetweenSqlFunction.KEY, new DaysBetweenSqlFunction() ).
put( ConditionalSqlFunction.KEY, new ConditionalSqlFunction() ).build();
+ private static final String NULL_REPLACEMENT = "null";
+
// -------------------------------------------------------------------------
// Dependencies
// -------------------------------------------------------------------------
@@ -252,7 +253,7 @@
if ( dataValue == null )
{
- value = String.valueOf( ObjectUtils.firstNonNull( indicator.getMissingValueReplacement(), 0 ) );
+ value = NULL_REPLACEMENT;
}
else
{
@@ -282,7 +283,7 @@
if ( attributeValue == null )
{
- value = String.valueOf( ObjectUtils.firstNonNull( indicator.getMissingValueReplacement(), 0 ) );
+ value = NULL_REPLACEMENT;
}
else
{
=== modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionFunctions.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionFunctions.java 2015-10-01 14:39:13 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionFunctions.java 2015-10-04 20:21:21 +0000
@@ -51,7 +51,7 @@
{
if ( value == null )
{
- throw new IllegalArgumentException( "Argument is null: " + value );
+ return null;
}
return Math.max( 0d, value.doubleValue() );
@@ -68,7 +68,7 @@
{
if ( value == null )
{
- throw new IllegalArgumentException( "Argument is null: " + value );
+ return null;
}
return ( value.doubleValue() >= 0d ) ? 1d : 0d;
=== modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionUtils.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionUtils.java 2015-10-01 15:36:32 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionUtils.java 2015-10-04 20:21:21 +0000
@@ -47,6 +47,7 @@
public class ExpressionUtils
{
private static final JexlEngine JEXL = new JexlEngine();
+ private static final JexlEngine JEXL_STRICT = new JexlEngine();
private static final Map<String, String> EL_SQL_MAP = new HashMap<>();
private static final String IGNORED_KEYWORDS_REGEX =
@@ -62,7 +63,12 @@
JEXL.setFunctions( functions );
JEXL.setCache( 512 );
JEXL.setSilent( false );
- JEXL.setStrict( true );
+ JEXL.setLenient( true ); // Lenient
+
+ JEXL_STRICT.setFunctions( functions );
+ JEXL_STRICT.setCache( 512 );
+ JEXL_STRICT.setSilent( false );
+ JEXL_STRICT.setStrict( true ); // Strict
EL_SQL_MAP.put( "&&", "and" );
EL_SQL_MAP.put( "\\|\\|", "or" );
@@ -81,9 +87,22 @@
*/
public static Object evaluate( String expression, Map<String, Object> vars )
{
+ return evaluate( expression, vars, false );
+ }
+
+ /**
+ * @param expression the expression.
+ * @param vars the variables, can be null.
+ * @param strict indicates whether to use strict or lenient engine mode.
+ * @return the result of the evaluation.
+ */
+ private static Object evaluate( String expression, Map<String, Object> vars, boolean strict )
+ {
expression = expression.replaceAll( IGNORED_KEYWORDS_REGEX, StringUtils.EMPTY );
- Expression exp = JEXL.createExpression( expression );
+ JexlEngine engine = strict ? JEXL_STRICT : JEXL;
+
+ Expression exp = engine.createExpression( expression );
JexlContext context = vars != null ? new MapContext( vars ) : new MapContext();
@@ -166,7 +185,7 @@
{
try
{
- Object result = evaluate( expression, vars );
+ Object result = evaluate( expression, vars, true );
return result != null;
}
=== modified file 'dhis-2/dhis-support/dhis-support-commons/src/test/java/org/hisp/dhis/commons/util/ExpressionUtilsTest.java'
--- dhis-2/dhis-support/dhis-support-commons/src/test/java/org/hisp/dhis/commons/util/ExpressionUtilsTest.java 2015-10-01 15:36:32 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/test/java/org/hisp/dhis/commons/util/ExpressionUtilsTest.java 2015-10-04 20:21:21 +0000
@@ -51,6 +51,7 @@
assertEquals( 3d, ExpressionUtils.evaluateToDouble( "3", null ), DELTA );
assertEquals( 3.45, ExpressionUtils.evaluateToDouble( "3.45", null ), DELTA );
assertEquals( 5d, ExpressionUtils.evaluateToDouble( "2 + 3", null ), DELTA );
+ assertEquals( 2d, ExpressionUtils.evaluateToDouble( "5 + -3", null ), DELTA );
assertEquals( 15.6, ExpressionUtils.evaluateToDouble( "12.4 + 3.2", null ), DELTA );
assertEquals( 2.0, ExpressionUtils.evaluateToDouble( "2 > 1 ? 2.0 : 1.0", null ), DELTA );
assertEquals( 1.0, ExpressionUtils.evaluateToDouble( "2 > 4 ? 2.0 : 1.0", null ), DELTA );
@@ -65,6 +66,15 @@
assertEquals( 1d, ExpressionUtils.evaluateToDouble( "d2:zing(d2:oizp(3))", null ), DELTA );
assertEquals( 2d, ExpressionUtils.evaluateToDouble( "d2:zpvc(1,3)", null ), DELTA );
assertEquals( 3d, ExpressionUtils.evaluateToDouble( "d2:zpvc(1,-1,2,-3,0)", null ), DELTA );
+ assertEquals( 4d, ExpressionUtils.evaluateToDouble( "d2:condition('3 > 2',4,3)", null ), DELTA );
+ assertEquals( 3d, ExpressionUtils.evaluateToDouble( "2 + null + 1", null ), DELTA );
+ assertEquals( 4d, ExpressionUtils.evaluateToDouble( "null + 4", null ), DELTA );
+ assertEquals( 5d, ExpressionUtils.evaluateToDouble( "(3 + 2) - null", null ), DELTA );
+ assertEquals( 9d, ExpressionUtils.evaluateToDouble( "(3 + 2) - null + 4 + null", null ), DELTA );
+ assertEquals( 2d, ExpressionUtils.evaluateToDouble( "d2:zing(null) + 2", null ), DELTA );
+ assertEquals( 2d, ExpressionUtils.evaluateToDouble( "d2:oizp(null) + 2", null ), DELTA );
+ assertEquals( 3d, ExpressionUtils.evaluateToDouble( "d2:zpvc(1,null,2,-3,0)", null ), DELTA );
+ assertEquals( 2d, ExpressionUtils.evaluateToDouble( "d2:zpvc(null,null,2,-3,0)", null ), DELTA );
}
@Test
@@ -96,7 +106,7 @@
"((d2:zing(4) + d2:zing(0) + d2:zing(-1)) / d2:zpvc(2,0,-1) * 0.25) + " +
"((d2:zing(8) + d2:zing(0) + d2:zing(-1)) / d2:zpvc(2,0,-1) * 0.75)";
- assertEquals( 3.5, ExpressionUtils.evaluateToDouble( expression, null ), DELTA );
+ assertEquals( 3.5, ExpressionUtils.evaluateToDouble( expression, null ), DELTA );
}
@Test
@@ -200,9 +210,9 @@
assertTrue( ExpressionUtils.isValid( "average(2+1)", null ) );
assertFalse( ExpressionUtils.isValid( "2 a 3", null ) );
- assertFalse( ExpressionUtils.isValid( "v2 + 3", vars ) );
- assertFalse( ExpressionUtils.isValid( "4 + abc", vars ) );
- assertFalse( ExpressionUtils.isValid( "'goat' == goat", null ) );
+ assertFalse( ExpressionUtils.isValid( "4 b", vars ) );
+ assertFalse( ExpressionUtils.isValid( "4 + A", vars ) );
+ assertFalse( ExpressionUtils.isValid( "4 + someunkownvar", vars ) );
assertFalse( ExpressionUtils.isValid( "aver(2+1)", null ) );
}