← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 22116: JEP functions, code style

 

------------------------------------------------------------
revno: 22116
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2016-03-02 22:51:09 +0100
message:
  JEP functions, code style
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/ArithmeticMean.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/Count.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/CustomFunctions.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MaxValue.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MedianValue.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MinValue.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/StandardDeviation.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/VectorSum.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/expression/ExpressionService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2016-03-02 21:51:09 +0000
@@ -391,5 +391,4 @@
      * @param indicators the collection of Indicators.
      */
     List<DataElementOperand> getOperandsInIndicators( List<Indicator> indicators );
-
 }

=== 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	2016-01-08 19:07:20 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java	2016-03-02 21:51:09 +0000
@@ -89,991 +89,1031 @@
  * @author Lars Helge Overland
  */
 public class DefaultExpressionService
-implements ExpressionService
+    implements ExpressionService
 {
-	private static final Log log = LogFactory.getLog( DefaultExpressionService.class );
-
-	// -------------------------------------------------------------------------
-	// Dependencies
-	// -------------------------------------------------------------------------
-
-	private GenericStore<Expression> expressionStore;
-
-	public void setExpressionStore( GenericStore<Expression> expressionStore )
-	{
-		this.expressionStore = expressionStore;
-	}
-
-	private DataElementService dataElementService;
-
-	public void setDataElementService( DataElementService dataElementService )
-	{
-		this.dataElementService = dataElementService;
-	}
-
-	private ConstantService constantService;
-
-	public void setConstantService( ConstantService constantService )
-	{
-		this.constantService = constantService;
-	}
-
-	private DataElementCategoryService categoryService;
-
-	public void setCategoryService( DataElementCategoryService categoryService )
-	{
-		this.categoryService = categoryService;
-	}
-
-	private OrganisationUnitGroupService organisationUnitGroupService;
-
-	public void setOrganisationUnitGroupService( OrganisationUnitGroupService organisationUnitGroupService )
-	{
-		this.organisationUnitGroupService = organisationUnitGroupService;
-	}
-
-	private DimensionService dimensionService;
-
-	public void setDimensionService( DimensionService dimensionService )
-	{
-		this.dimensionService = dimensionService;
-	}
-
-	private IdentifiableObjectManager idObjectManager;
-
-	public void setIdObjectManager( IdentifiableObjectManager idObjectManager )
-	{
-		this.idObjectManager = idObjectManager;
-	}
-
-	// -------------------------------------------------------------------------
-	// Expression CRUD operations
-	// -------------------------------------------------------------------------
-
-	@Override
-	@Transactional
-	public int addExpression( Expression expression )
-	{
-		return expressionStore.save( expression );
-	}
-
-	@Override
-	@Transactional
-	public void deleteExpression( Expression expression )
-	{
-		expressionStore.delete( expression );
-	}
-
-	@Override
-	@Transactional
-	public Expression getExpression( int id )
-	{
-		return expressionStore.get( id );
-	}
-
-	@Override
-	@Transactional
-	public void updateExpression( Expression expression )
-	{
-		expressionStore.update( expression );
-	}
-
-	@Override
-	@Transactional
-	public List<Expression> getAllExpressions()
-	{
-		return expressionStore.getAll();
-	}
-
-	// -------------------------------------------------------------------------
-	// Business logic
-	// -------------------------------------------------------------------------
-
-	@Override
-	public Double getIndicatorValue( Indicator indicator, Period period, Map<? extends DimensionalItemObject, Double> valueMap,
-			Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap )
-	{
-		if ( indicator == null || indicator.getExplodedNumeratorFallback() == null || indicator.getExplodedDenominatorFallback() == null )
-		{
-			return null;
-		}
-
-		Integer days = period != null ? period.getDaysInPeriod() : null;
-
-		final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), 
-				valueMap, constantMap, orgUnitCountMap, days, NEVER_SKIP );
-
-		if ( denominatorExpression == null )
-		{
-			return null;
-		}
-
-		final double denominatorValue = calculateExpression( denominatorExpression );
-
-		if ( !isEqual( denominatorValue, 0d ) )
-		{
-			final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), 
-					valueMap, constantMap, orgUnitCountMap, days, NEVER_SKIP );
-
-			if ( numeratorExpression == null )
-			{
-				return null;
-			}
-
-			final double numeratorValue = calculateExpression( numeratorExpression );
-
-			final double annualizationFactor = period != null ? DateUtils.getAnnualizationFactor( indicator, period.getStartDate(), period.getEndDate() ) : 1d;
-			final double factor = indicator.getIndicatorType().getFactor();
-			final double aggregatedValue = ( numeratorValue / denominatorValue ) * factor * annualizationFactor;
-
-			return aggregatedValue;
-		}
-
-		return null;
-	}
-
-	@Override
-	public Double getExpressionValue( Expression expression, Map<? extends DimensionalItemObject, Double> valueMap,
-			Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days )
-	{
-		return getExpressionValue( expression, valueMap, constantMap, orgUnitCountMap, days, null, null );
-	}
-
-	@Override
-	public Double getExpressionValue( Expression expression, Map<? extends DimensionalItemObject, Double> valueMap,
-			Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days,
-			Set<DataElementOperand> incompleteValues)
-	{
-		return getExpressionValue( expression, valueMap, constantMap, orgUnitCountMap, days, incompleteValues, null );
-	}
-
-	@Override
-	public Double getExpressionValue( Expression expression, Map<? extends DimensionalItemObject, Double> valueMap,
-			Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, 
-			Set<DataElementOperand> incompleteValues,
-			ListMap<String, Double> aggregateMap)
-	{
-		String expressionString = generateExpression( expression.getExplodedExpressionFallback(), valueMap, constantMap, 
-				orgUnitCountMap, days, expression.getMissingValueStrategy(), incompleteValues, aggregateMap );
-		
-		Double result = expressionString != null ? calculateExpression( expressionString ) : null;
-		
-		log.debug("getExpressionValue("+expression.getExpression()+") ==> '"+expressionString+"' ==> "+result);
-		
-		return result;
-	}
-
-	@Override
-	@Transactional
-	public Set<DataElement> getDataElementsInExpression( String expression )
-	{
-		return getDataElementsInExpressionInternal( OPERAND_PATTERN, expression );
-	}
-
-	private Set<DataElement> getDataElementsInExpressionInternal( Pattern pattern, String expression )
-	{
-		Set<DataElement> dataElements = new HashSet<>();
-
-		if ( expression != null )
-		{
-			final Matcher matcher = pattern.matcher( expression );
-
-			while ( matcher.find() )
-			{
-				final DataElement dataElement = dataElementService.getDataElement( matcher.group( 1 ) );
-
-				if ( dataElement != null )
-				{
-					dataElements.add( dataElement );
-				}
-			}
-		}
-
-		return dataElements;
-	}
-
-	@Override
-	@Transactional
-	public Set<DataElementCategoryOptionCombo> getOptionCombosInExpression( String expression )
-	{
-		Set<DataElementCategoryOptionCombo> optionCombosInExpression = new HashSet<>();
-
-		if ( expression != null )
-		{
-			final Matcher matcher = OPTION_COMBO_OPERAND_PATTERN.matcher( expression );
-
-			while ( matcher.find() )
-			{
-				DataElementCategoryOptionCombo categoryOptionCombo = categoryService.
-						getDataElementCategoryOptionCombo( matcher.group( 2 ) );
-
-				if ( categoryOptionCombo != null )
-				{
-					optionCombosInExpression.add( categoryOptionCombo );
-				}
-			}
-		}
-
-		return optionCombosInExpression;
-	}
-
-	@Override
-	@Transactional
-	public Set<DataElementOperand> getOperandsInExpression( String expression )
-	{
-		Set<DataElementOperand> operandsInExpression = new HashSet<>();
-
-		if ( expression != null )
-		{
-			final Matcher matcher = OPTION_COMBO_OPERAND_PATTERN.matcher( expression );
-
-			while ( matcher.find() )
-			{
-				DataElementOperand operand = DataElementOperand.getOperand( matcher.group() );
-
-				if ( operand.getOptionComboId() != null )
-				{
-					operandsInExpression.add( operand );
-				}
-			}
-		}
-
-		return operandsInExpression;
-	}
-
-	@Override
-	@Transactional
-	public Set<String> getAggregatesInExpression( String expression )
-	{
-		Pattern prefix=CustomFunctions.getAggregatePrefixPattern();
-		Set<String> aggregates = new HashSet<>();
-
-		if ( expression != null )
-		{
-			final Matcher matcher = prefix.matcher(expression);
-			int scan=0, len=expression.length();
-
-			while ((scan<len)&&( matcher.find(scan) ))
-			{
-				int start=matcher.end();
-				int end=Expression.matchExpression(expression,start);
-				if (end<0) {
-					log.warn("Bad expression starting at "+start+" in "+expression);}
-				if (end>0) {
-					aggregates.add(expression.substring(start,end));
-					scan=end+1;}
-				else scan=start+1;
-			}
-		}
-
-		return aggregates;
-	}
-
-	@Override
-	@Transactional
-	public Set<DataElement> getDataElementsInIndicators( Collection<Indicator> indicators )
-	{
-		Set<DataElement> dataElements = new HashSet<>();
-
-		for ( Indicator indicator : indicators )
-		{
-			dataElements.addAll( getDataElementsInExpression( indicator.getNumerator() ) );
-			dataElements.addAll( getDataElementsInExpression( indicator.getDenominator() ) );
-		}
-
-		return dataElements;
-	}
-
-	@Override
-	@Transactional
-	public Set<DataElement> getDataElementTotalsInIndicators( Collection<Indicator> indicators )
-	{
-		Set<DataElement> dataElements = new HashSet<>();
-
-		for ( Indicator indicator : indicators )
-		{
-			dataElements.addAll( getDataElementsInExpressionInternal( DATA_ELEMENT_TOTAL_PATTERN, indicator.getNumerator() ) );
-			dataElements.addAll( getDataElementsInExpressionInternal( DATA_ELEMENT_TOTAL_PATTERN, indicator.getDenominator() ) );
-		}
-
-		return dataElements;
-	}
-
-	@Override
-	@Transactional
-	public Set<DataElement> getDataElementWithOptionCombosInIndicators( Collection<Indicator> indicators )
-	{
-		Set<DataElement> dataElements = new HashSet<>();
-
-		for ( Indicator indicator : indicators )
-		{
-			dataElements.addAll( getDataElementsInExpressionInternal( OPTION_COMBO_OPERAND_PATTERN, indicator.getNumerator() ) );
-			dataElements.addAll( getDataElementsInExpressionInternal( OPTION_COMBO_OPERAND_PATTERN, indicator.getDenominator() ) );
-		}
-
-		return dataElements;
-	}
-
-	@Override
-	public Set<DimensionalItemObject> getDimensionalItemObjectsInExpression( String expression )
-	{
-		Set<DimensionalItemObject> dimensionItems = Sets.newHashSet();
-
-		if ( expression == null || expression.isEmpty() )
-		{
-			return dimensionItems;
-		}
-
-		Matcher matcher = VARIABLE_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			String dimensionItem = matcher.group( 2 );
-
-			DimensionalItemObject dimensionItemObject = dimensionService.getDataDimensionalItemObject( dimensionItem );
-
-			if ( dimensionItemObject != null )
-			{
-				dimensionItems.add( dimensionItemObject );
-			}
-		}
-
-		return dimensionItems;
-	}
-
-	@Override
-	public Set<DimensionalItemObject> getDimensionalItemObjectsInIndicators( Collection<Indicator> indicators )
-	{
-		Set<DimensionalItemObject> items = Sets.newHashSet();
-
-		for ( Indicator indicator : indicators )
-		{
-			items.addAll( getDimensionalItemObjectsInExpression( indicator.getNumerator() ) );
-			items.addAll( getDimensionalItemObjectsInExpression( indicator.getDenominator() ) );
-		}
-
-		return items;
-	}
-
-	@Override
-	public Set<OrganisationUnitGroup> getOrganisationUnitGroupsInExpression( String expression )
-	{
-		Set<OrganisationUnitGroup> groupsInExpression = new HashSet<>();
-
-		if ( expression != null )
-		{            
-			final Matcher matcher = OU_GROUP_PATTERN.matcher( expression );
-
-			while ( matcher.find() )
-			{
-				final OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( matcher.group( 1 ) );
-
-				if ( group != null )
-				{
-					groupsInExpression.add( group );
-				}
-			}
-		}
-
-		return groupsInExpression;
-	}
-
-	@Override
-	public Set<OrganisationUnitGroup> getOrganisationUnitGroupsInIndicators( Collection<Indicator> indicators )
-	{
-		Set<OrganisationUnitGroup> groups = new HashSet<>();
-
-		if ( indicators != null )
-		{   
-			for ( Indicator indicator : indicators )
-			{
-				groups.addAll( getOrganisationUnitGroupsInExpression( indicator.getNumerator() ) );
-				groups.addAll( getOrganisationUnitGroupsInExpression( indicator.getDenominator() ) );
-			}
-		}
-
-		return groups;
-	}
-
-	@Override
-	@Transactional
-	public void filterInvalidIndicators( List<Indicator> indicators )
-	{
-		if ( indicators != null )
-		{
-			Iterator<Indicator> iterator = indicators.iterator();
-
-			while ( iterator.hasNext() )
-			{
-				Indicator indicator = iterator.next();
-
-				if ( !expressionIsValid( indicator.getNumerator() ).isValid() ||
-						!expressionIsValid( indicator.getDenominator() ).isValid() )
-				{
-					iterator.remove();
-					log.warn( "Indicator is invalid: " + indicator + ", " + indicator.getNumerator() + ", " + indicator.getDenominator() );
-				}
-			}
-		}
-	}
-
-	@Override
-	@Transactional
-	public ExpressionValidationOutcome expressionIsValid( String expression )
-	{
-		if ( expression == null || expression.isEmpty() )
-		{
-			return ExpressionValidationOutcome.EXPRESSION_IS_EMPTY;
-		}
-
-		// ---------------------------------------------------------------------
-		// Operands
-		// ---------------------------------------------------------------------
-
-		StringBuffer sb = new StringBuffer();
-		Matcher matcher = VARIABLE_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			String dimensionItem = matcher.group( 2 );
-
-			if ( dimensionService.getDataDimensionalItemObject( dimensionItem ) == null )
-			{
-				return ExpressionValidationOutcome.DIMENSIONAL_ITEM_OBJECT_DOES_NOT_EXIST;
-			}
-
-			matcher.appendReplacement( sb, "1.1" );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Constants
-		// ---------------------------------------------------------------------
-
-		matcher = CONSTANT_PATTERN.matcher( expression );
-		sb = new StringBuffer();
-
-		while ( matcher.find() )
-		{
-			String constant = matcher.group( 1 );
-
-			if ( idObjectManager.getNoAcl( Constant.class, constant ) == null )
-			{
-				return ExpressionValidationOutcome.CONSTANT_DOES_NOT_EXIST;
-			}
-
-			matcher.appendReplacement( sb, "1.1" );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Org unit groups
-		// ---------------------------------------------------------------------
-
-		matcher = OU_GROUP_PATTERN.matcher( expression );
-		sb = new StringBuffer();
-
-		while ( matcher.find() )
-		{
-			String group = matcher.group( 1 );
-
-			if ( idObjectManager.getNoAcl( OrganisationUnitGroup.class, group ) == null )
-			{
-				return ExpressionValidationOutcome.ORG_UNIT_GROUP_DOES_NOT_EXIST;
-			}
-
-			matcher.appendReplacement( sb, "1.1" );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Days
-		// ---------------------------------------------------------------------
-
-		expression = expression.replaceAll( DAYS_EXPRESSION, "1.1" );
-
-		// ---------------------------------------------------------------------
-		// Well-formed expression
-		// ---------------------------------------------------------------------
-
-		if ( MathUtils.expressionHasErrors( expression ) )
-		{
-			return ExpressionValidationOutcome.EXPRESSION_IS_NOT_WELL_FORMED;
-		}
-
-		return ExpressionValidationOutcome.VALID;
-	}
-
-	@Override
-	@Transactional
-	public String getExpressionDescription( String expression )
-	{
-		if ( expression == null || expression.isEmpty() )
-		{
-			return null;
-		}
-
-		// ---------------------------------------------------------------------
-		// Operands
-		// ---------------------------------------------------------------------
-
-		StringBuffer sb = new StringBuffer();
-		Matcher matcher = VARIABLE_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			String dimensionItem = matcher.group( 2 );
-
-			DimensionalItemObject dimensionItemObject = dimensionService.getDataDimensionalItemObject( dimensionItem );
-
-			if ( dimensionItemObject == null )
-			{
-				throw new InvalidIdentifierReferenceException( "Identifier does not reference a dimensional item object: " + dimensionItem );
-			}
-
-			matcher.appendReplacement( sb, Matcher.quoteReplacement( dimensionItemObject.getDisplayName() ) );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Constants
-		// ---------------------------------------------------------------------
-
-		sb = new StringBuffer();
-		matcher = CONSTANT_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			String co = matcher.group( 1 );
-
-			Constant constant = constantService.getConstant( co );
-
-			if ( constant == null )
-			{
-				throw new InvalidIdentifierReferenceException( "Identifier does not reference a constant: " + co );
-			}
-
-			matcher.appendReplacement( sb, Matcher.quoteReplacement( constant.getDisplayName() ) );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Org unit groups
-		// ---------------------------------------------------------------------
-
-		sb = new StringBuffer();
-		matcher = OU_GROUP_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			String oug = matcher.group( 1 );
-
-			OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( oug );
-
-			if ( group == null )
-			{
-				throw new InvalidIdentifierReferenceException( "Identifier does not reference an organisation unit group: " + oug );
-			}
-
-			matcher.appendReplacement( sb, Matcher.quoteReplacement( group.getDisplayName() ) );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Days
-		// ---------------------------------------------------------------------
-
-		sb = new StringBuffer();
-		matcher = DAYS_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			matcher.appendReplacement( sb, DAYS_DESCRIPTION );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		return expression;
-	}
-
-	@Override
-	@Transactional
-	public void explodeValidationRuleExpressions( Collection<ValidationRule> validationRules )
-	{
-		if ( validationRules != null && !validationRules.isEmpty() )
-		{
-			Set<String> dataElementTotals = new HashSet<>();
-
-			for ( ValidationRule rule : validationRules )
-			{
-				dataElementTotals.addAll( RegexUtils.getMatches( DATA_ELEMENT_TOTAL_PATTERN, rule.getLeftSide().getExpression(), 1 ) );
-				dataElementTotals.addAll( RegexUtils.getMatches( DATA_ELEMENT_TOTAL_PATTERN, rule.getRightSide().getExpression(), 1 ) );
-			}
-
-			if ( !dataElementTotals.isEmpty() )
-			{
-				final ListMap<String, String> dataElementMap = dataElementService.getDataElementCategoryOptionComboMap( dataElementTotals );
-
-				if ( !dataElementMap.isEmpty() )
-				{
-					for ( ValidationRule rule : validationRules )
-					{
-						rule.getLeftSide().setExplodedExpression( explodeExpression( rule.getLeftSide().getExplodedExpressionFallback(), dataElementMap ) );
-						rule.getRightSide().setExplodedExpression( explodeExpression( rule.getRightSide().getExplodedExpressionFallback(), dataElementMap ) );
-					}
-				}
-			}            
-		}
-	}
-
-	private String explodeExpression( String expression, ListMap<String, String> dataElementOptionComboMap )
-	{
-		if ( expression == null || expression.isEmpty() )
-		{
-			return null;
-		}
-
-		StringBuffer sb = new StringBuffer();
-		Matcher matcher = OPERAND_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			if ( operandIsTotal( matcher ) )
-			{
-				final StringBuilder replace = new StringBuilder( PAR_OPEN );
-
-				String de = matcher.group( 1 );
-
-				List<String> cocs = dataElementOptionComboMap.get( de );
-
-				for ( String coc : cocs )
-				{
-					replace.append( EXP_OPEN ).append( de ).append( SEPARATOR ).append(
-							coc ).append( EXP_CLOSE ).append( "+" );
-				}
-
-				replace.deleteCharAt( replace.length() - 1 ).append( PAR_CLOSE );
-				matcher.appendReplacement( sb, Matcher.quoteReplacement( replace.toString() ) );
-			}
-		}
-
-		return TextUtils.appendTail( matcher, sb );
-	}
-
-	@Override
-	@Transactional
-	public String explodeExpression( String expression )
-	{
-		if ( expression == null || expression.isEmpty() )
-		{
-			return null;
-		}
-
-		StringBuffer sb = new StringBuffer();
-		Matcher matcher = OPERAND_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			if ( operandIsTotal( matcher ) )
-			{
-				final StringBuilder replace = new StringBuilder( PAR_OPEN );
-
-				final DataElement dataElement = idObjectManager.getNoAcl( DataElement.class, matcher.group( 1 ) );
-
-				final DataElementCategoryCombo categoryCombo = dataElement.getCategoryCombo();
-
-				for ( DataElementCategoryOptionCombo categoryOptionCombo : categoryCombo.getOptionCombos() )
-				{
-					replace.append( EXP_OPEN ).append( dataElement.getUid() ).append( SEPARATOR ).append(
-							categoryOptionCombo.getUid() ).append( EXP_CLOSE ).append( "+" );
-				}
-
-				replace.deleteCharAt( replace.length() - 1 ).append( PAR_CLOSE );
-				matcher.appendReplacement( sb, Matcher.quoteReplacement( replace.toString() ) );
-			}
-		}
-
-		return TextUtils.appendTail( matcher, sb );
-	}
-
-	@Override
-	@Transactional
-	public void substituteExpressions( Collection<Indicator> indicators, Integer days )
-	{
-		if ( indicators != null && !indicators.isEmpty() )
-		{
-			Map<String, Constant> constants = new CachingMap<String, Constant>().
-					load( idObjectManager.getAllNoAcl( Constant.class ), c -> c.getUid() );
-
-			Map<String, OrganisationUnitGroup> orgUnitGroups = new CachingMap<String, OrganisationUnitGroup>().
-					load( idObjectManager.getAllNoAcl( OrganisationUnitGroup.class ), g -> g.getUid() );
-
-			for ( Indicator indicator : indicators )
-			{
-				indicator.setExplodedNumerator( substituteExpression( indicator.getNumerator(), constants, orgUnitGroups, days ) );
-				indicator.setExplodedDenominator( substituteExpression( indicator.getDenominator(), constants, orgUnitGroups, days ) );
-			}
-		}                
-	}
-
-	private String substituteExpression( String expression, Map<String, Constant> constants, Map<String, OrganisationUnitGroup> orgUnitGroups, Integer days )
-	{
-		if ( expression == null || expression.isEmpty() )
-		{
-			return null;
-		}
-
-		// ---------------------------------------------------------------------
-		// Constants
-		// ---------------------------------------------------------------------
-
-		StringBuffer sb = new StringBuffer();        
-		Matcher matcher = CONSTANT_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			String co = matcher.group( 1 );
-
-			Constant constant = constants.get( co );
-
-			String replacement = constant != null ? String.valueOf( constant.getValue() ) : NULL_REPLACEMENT; 
-
-			matcher.appendReplacement( sb, Matcher.quoteReplacement( replacement ) );
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Org unit groups
-		// ---------------------------------------------------------------------
-
-		sb = new StringBuffer();
-		matcher = OU_GROUP_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{
-			String oug = matcher.group( 1 );
-
-			OrganisationUnitGroup group = orgUnitGroups.get( oug );
-
-			String replacement = group != null ? String.valueOf( group.getMembers().size() ) : NULL_REPLACEMENT;
-
-			matcher.appendReplacement( sb, replacement );            
-
-			//TODO sub tree
-		}
-
-		expression = TextUtils.appendTail( matcher, sb );
-
-		// ---------------------------------------------------------------------
-		// Days
-		// ---------------------------------------------------------------------
-
-		sb = new StringBuffer();
-		matcher = DAYS_PATTERN.matcher( expression );
-
-		while ( matcher.find() )
-		{            
-			String replacement = days != null ? String.valueOf( days ) : NULL_REPLACEMENT;
-
-			matcher.appendReplacement( sb, replacement );
-		}
-
-		return TextUtils.appendTail( matcher, sb );
-	}
-
-	@Override
-	public String generateExpression( String expression, Map<? extends DimensionalItemObject, Double> valueMap, 
-			Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, MissingValueStrategy missingValueStrategy )
-	{
-		return generateExpression( expression, valueMap, constantMap, orgUnitCountMap, days, missingValueStrategy, null, null );
-	}
-
-	private String generateExpression( String expression, Map<? extends DimensionalItemObject, Double> valueMap, 
-			Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days, 
-			MissingValueStrategy missingValueStrategy, Set<DataElementOperand> incompleteValues,
-			Map<String, List<Double>> aggregateMap)
-	{
-		if ( expression == null || expression.isEmpty() )
-		{
-			return null;
-		}
-
-		Map<String, Double> dimensionItemValueMap = valueMap.entrySet().stream().
-				collect( Collectors.toMap( e -> e.getKey().getDimensionItem(), e -> e.getValue() ) );
-
-		Set<String> incompleteItems = incompleteValues != null ? incompleteValues.
-				stream().map( i -> i.getDimensionItem() ).collect( Collectors.toSet() ) : Sets.newHashSet();
-
-				missingValueStrategy = missingValueStrategy == null ? NEVER_SKIP : missingValueStrategy;
-
-				// ---------------------------------------------------------------------
-				// Substitute aggregates
-				// ---------------------------------------------------------------------
-
-				StringBuffer sb = new StringBuffer();
-
-				Pattern prefix=CustomFunctions.getAggregatePrefixPattern();
-				Matcher matcher = prefix.matcher( expression );
-
-				int scan=0, len=expression.length(), tail=0;
-				while ((scan<len)&&(matcher.find(scan)))
-				{
-					int start=matcher.end();
-					int end=Expression.matchExpression(expression, start);
-					if (end<0) {
-						sb.append(expression.substring(scan,start));
-						scan=start+1; 
-						tail=start;
-					}
-					else if ((aggregateMap==null)||(expression.charAt(start)=='<')) {
-						sb.append(expression.substring(scan,end));
-						scan=end+1; tail=end;
-					}
-					else {
-						String sub_expression=expression.substring(start,end);
-						List<Double> samples = aggregateMap.get( sub_expression );
-
-						if (samples == null) {
-							if (SKIP_IF_ANY_VALUE_MISSING.equals( missingValueStrategy )) {
-								return null;}
-							else {}}
-						else {
-							String literal = ( samples == null) ? ("[]") : (samples.toString());
-							sb.append(expression.substring(scan,start));
-							sb.append(literal);}
-						scan=end; tail=end;
-					}
-				}
-
-				sb.append(expression.substring(tail));
-				expression = sb.toString();
-				
-				// ---------------------------------------------------------------------
-				// DimensionalItemObjects
-				// ---------------------------------------------------------------------
-
-				sb = new StringBuffer();
-				matcher = VARIABLE_PATTERN.matcher( expression );
-
-				int matchCount = 0;
-				int valueCount = 0;
-
-				while ( matcher.find() )
-				{
-					matchCount++;
-
-					String dimItem = matcher.group( 2 );
-
-					final Double value = dimensionItemValueMap.get( dimItem );
-
-					boolean missingValue = value == null || incompleteItems.contains( dimItem );
-
-					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, Matcher.quoteReplacement( replacement ) );
-				}
-
-				if ( SKIP_IF_ALL_VALUES_MISSING.equals( missingValueStrategy ) && matchCount > 0 && valueCount == 0 )
-				{
-					return null;
-				}
-
-				expression = TextUtils.appendTail( matcher, sb );
-
-				// ---------------------------------------------------------------------
-				// Constants
-				// ---------------------------------------------------------------------
-
-				sb = new StringBuffer();
-				matcher = CONSTANT_PATTERN.matcher( expression );
-
-				while ( matcher.find() )
-				{
-					final Double constant = constantMap != null ? constantMap.get( matcher.group( 1 ) ) : null;
-
-					String replacement = constant != null ? String.valueOf( constant ) : NULL_REPLACEMENT;
-
-					matcher.appendReplacement( sb, replacement );
-				}
-
-				expression = TextUtils.appendTail( matcher, sb );
-
-				// ---------------------------------------------------------------------
-				// Org unit groups
-				// ---------------------------------------------------------------------
-
-				sb = new StringBuffer();
-				matcher = OU_GROUP_PATTERN.matcher( expression );
-
-				while ( matcher.find() )
-				{
-					final Integer count = orgUnitCountMap != null ? orgUnitCountMap.get( matcher.group( 1 ) ) : null;
-
-					String replacement = count != null ? String.valueOf( count ) : NULL_REPLACEMENT;
-
-					matcher.appendReplacement( sb, replacement );
-				}
-
-				expression = TextUtils.appendTail( matcher, sb );        
-
-				// ---------------------------------------------------------------------
-				// Days
-				// ---------------------------------------------------------------------
-
-				sb = new StringBuffer();
-				matcher = DAYS_PATTERN.matcher( expression );
-
-				while ( matcher.find() )
-				{
-					String replacement = days != null ? String.valueOf( days ) : NULL_REPLACEMENT;
-
-					matcher.appendReplacement( sb, replacement );
-				}
-
-				return TextUtils.appendTail( matcher, sb );
-	}
-
-	@Override
-	@Transactional
-	public List<DataElementOperand> getOperandsInIndicators( List<Indicator> indicators )
-	{
-		final List<DataElementOperand> operands = new ArrayList<>();
-
-		for ( Indicator indicator : indicators )
-		{
-			Set<DataElementOperand> temp = getOperandsInExpression( indicator.getExplodedNumerator() );
-			operands.addAll( temp != null ? temp : new HashSet<DataElementOperand>() );
-
-			temp = getOperandsInExpression( indicator.getExplodedDenominator() );            
-			operands.addAll( temp != null ? temp : new HashSet<DataElementOperand>() );
-		}
-
-		return operands;
-	}
-
-	// -------------------------------------------------------------------------
-	// Supportive methods
-	// -------------------------------------------------------------------------
-
-	private boolean operandIsTotal( Matcher matcher )
-	{
-		return matcher != null && StringUtils.trimToEmpty( matcher.group( 2 ) ).isEmpty();
-	}
+    private static final Log log = LogFactory.getLog( DefaultExpressionService.class );
+
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private GenericStore<Expression> expressionStore;
+
+    public void setExpressionStore( GenericStore<Expression> expressionStore )
+    {
+        this.expressionStore = expressionStore;
+    }
+
+    private DataElementService dataElementService;
+
+    public void setDataElementService( DataElementService dataElementService )
+    {
+        this.dataElementService = dataElementService;
+    }
+
+    private ConstantService constantService;
+
+    public void setConstantService( ConstantService constantService )
+    {
+        this.constantService = constantService;
+    }
+
+    private DataElementCategoryService categoryService;
+
+    public void setCategoryService( DataElementCategoryService categoryService )
+    {
+        this.categoryService = categoryService;
+    }
+
+    private OrganisationUnitGroupService organisationUnitGroupService;
+
+    public void setOrganisationUnitGroupService( OrganisationUnitGroupService organisationUnitGroupService )
+    {
+        this.organisationUnitGroupService = organisationUnitGroupService;
+    }
+
+    private DimensionService dimensionService;
+
+    public void setDimensionService( DimensionService dimensionService )
+    {
+        this.dimensionService = dimensionService;
+    }
+
+    private IdentifiableObjectManager idObjectManager;
+
+    public void setIdObjectManager( IdentifiableObjectManager idObjectManager )
+    {
+        this.idObjectManager = idObjectManager;
+    }
+
+    // -------------------------------------------------------------------------
+    // Expression CRUD operations
+    // -------------------------------------------------------------------------
+
+    @Override
+    @Transactional
+    public int addExpression( Expression expression )
+    {
+        return expressionStore.save( expression );
+    }
+
+    @Override
+    @Transactional
+    public void deleteExpression( Expression expression )
+    {
+        expressionStore.delete( expression );
+    }
+
+    @Override
+    @Transactional
+    public Expression getExpression( int id )
+    {
+        return expressionStore.get( id );
+    }
+
+    @Override
+    @Transactional
+    public void updateExpression( Expression expression )
+    {
+        expressionStore.update( expression );
+    }
+
+    @Override
+    @Transactional
+    public List<Expression> getAllExpressions()
+    {
+        return expressionStore.getAll();
+    }
+
+    // -------------------------------------------------------------------------
+    // Business logic
+    // -------------------------------------------------------------------------
+
+    @Override
+    public Double getIndicatorValue( Indicator indicator, Period period,
+        Map<? extends DimensionalItemObject, Double> valueMap, Map<String, Double> constantMap,
+        Map<String, Integer> orgUnitCountMap )
+    {
+        if ( indicator == null || indicator.getExplodedNumeratorFallback() == null
+            || indicator.getExplodedDenominatorFallback() == null )
+        {
+            return null;
+        }
+
+        Integer days = period != null ? period.getDaysInPeriod() : null;
+
+        final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), valueMap,
+            constantMap, orgUnitCountMap, days, NEVER_SKIP );
+
+        if ( denominatorExpression == null )
+        {
+            return null;
+        }
+
+        final double denominatorValue = calculateExpression( denominatorExpression );
+
+        if ( !isEqual( denominatorValue, 0d ) )
+        {
+            final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), valueMap,
+                constantMap, orgUnitCountMap, days, NEVER_SKIP );
+
+            if ( numeratorExpression == null )
+            {
+                return null;
+            }
+
+            final double numeratorValue = calculateExpression( numeratorExpression );
+
+            final double annualizationFactor = period != null
+                ? DateUtils.getAnnualizationFactor( indicator, period.getStartDate(), period.getEndDate() ) : 1d;
+            final double factor = indicator.getIndicatorType().getFactor();
+            final double aggregatedValue = (numeratorValue / denominatorValue) * factor * annualizationFactor;
+
+            return aggregatedValue;
+        }
+
+        return null;
+    }
+
+    @Override
+    public Double getExpressionValue( Expression expression, Map<? extends DimensionalItemObject, Double> valueMap,
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days )
+    {
+        return getExpressionValue( expression, valueMap, constantMap, orgUnitCountMap, days, null, null );
+    }
+
+    @Override
+    public Double getExpressionValue( Expression expression, Map<? extends DimensionalItemObject, Double> valueMap,
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days,
+        Set<DataElementOperand> incompleteValues )
+    {
+        return getExpressionValue( expression, valueMap, constantMap, orgUnitCountMap, days, incompleteValues, null );
+    }
+
+    @Override
+    public Double getExpressionValue( Expression expression, Map<? extends DimensionalItemObject, Double> valueMap,
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days,
+        Set<DataElementOperand> incompleteValues, ListMap<String, Double> aggregateMap )
+    {
+        String expressionString = generateExpression( expression.getExplodedExpressionFallback(), valueMap, constantMap,
+            orgUnitCountMap, days, expression.getMissingValueStrategy(), incompleteValues, aggregateMap );
+
+        Double result = expressionString != null ? calculateExpression( expressionString ) : null;
+        
+        return result;
+    }
+
+    @Override
+    @Transactional
+    public Set<DataElement> getDataElementsInExpression( String expression )
+    {
+        return getDataElementsInExpressionInternal( OPERAND_PATTERN, expression );
+    }
+
+    private Set<DataElement> getDataElementsInExpressionInternal( Pattern pattern, String expression )
+    {
+        Set<DataElement> dataElements = new HashSet<>();
+
+        if ( expression != null )
+        {
+            final Matcher matcher = pattern.matcher( expression );
+
+            while ( matcher.find() )
+            {
+                final DataElement dataElement = dataElementService.getDataElement( matcher.group( 1 ) );
+
+                if ( dataElement != null )
+                {
+                    dataElements.add( dataElement );
+                }
+            }
+        }
+
+        return dataElements;
+    }
+
+    @Override
+    @Transactional
+    public Set<DataElementCategoryOptionCombo> getOptionCombosInExpression( String expression )
+    {
+        Set<DataElementCategoryOptionCombo> optionCombosInExpression = new HashSet<>();
+
+        if ( expression != null )
+        {
+            final Matcher matcher = OPTION_COMBO_OPERAND_PATTERN.matcher( expression );
+
+            while ( matcher.find() )
+            {
+                DataElementCategoryOptionCombo categoryOptionCombo = categoryService
+                    .getDataElementCategoryOptionCombo( matcher.group( 2 ) );
+
+                if ( categoryOptionCombo != null )
+                {
+                    optionCombosInExpression.add( categoryOptionCombo );
+                }
+            }
+        }
+
+        return optionCombosInExpression;
+    }
+
+    @Override
+    @Transactional
+    public Set<DataElementOperand> getOperandsInExpression( String expression )
+    {
+        Set<DataElementOperand> operandsInExpression = new HashSet<>();
+
+        if ( expression != null )
+        {
+            final Matcher matcher = OPTION_COMBO_OPERAND_PATTERN.matcher( expression );
+
+            while ( matcher.find() )
+            {
+                DataElementOperand operand = DataElementOperand.getOperand( matcher.group() );
+
+                if ( operand.getOptionComboId() != null )
+                {
+                    operandsInExpression.add( operand );
+                }
+            }
+        }
+
+        return operandsInExpression;
+    }
+
+    @Override
+    @Transactional
+    public Set<String> getAggregatesInExpression( String expression )
+    {
+        Pattern prefix = CustomFunctions.getAggregatePrefixPattern();
+        Set<String> aggregates = new HashSet<>();
+
+        if ( expression != null )
+        {
+            final Matcher matcher = prefix.matcher( expression );
+            
+            int scan = 0, len = expression.length();
+
+            while ( (scan < len) && (matcher.find( scan )) )
+            {
+                int start = matcher.end();
+                
+                int end = Expression.matchExpression( expression, start );
+                
+                if ( end < 0 )
+                {
+                    log.warn( "Bad expression starting at " + start + " in " + expression );
+                }
+                else if ( end > 0 )
+                {
+                    aggregates.add( expression.substring( start, end ) );
+                    scan = end + 1;
+                }
+                else
+                {
+                    scan = start + 1;
+                }
+            }
+        }
+
+        return aggregates;
+    }
+
+    @Override
+    @Transactional
+    public Set<DataElement> getDataElementsInIndicators( Collection<Indicator> indicators )
+    {
+        Set<DataElement> dataElements = new HashSet<>();
+
+        for ( Indicator indicator : indicators )
+        {
+            dataElements.addAll( getDataElementsInExpression( indicator.getNumerator() ) );
+            dataElements.addAll( getDataElementsInExpression( indicator.getDenominator() ) );
+        }
+
+        return dataElements;
+    }
+
+    @Override
+    @Transactional
+    public Set<DataElement> getDataElementTotalsInIndicators( Collection<Indicator> indicators )
+    {
+        Set<DataElement> dataElements = new HashSet<>();
+
+        for ( Indicator indicator : indicators )
+        {
+            dataElements
+                .addAll( getDataElementsInExpressionInternal( DATA_ELEMENT_TOTAL_PATTERN, indicator.getNumerator() ) );
+            dataElements.addAll(
+                getDataElementsInExpressionInternal( DATA_ELEMENT_TOTAL_PATTERN, indicator.getDenominator() ) );
+        }
+
+        return dataElements;
+    }
+
+    @Override
+    @Transactional
+    public Set<DataElement> getDataElementWithOptionCombosInIndicators( Collection<Indicator> indicators )
+    {
+        Set<DataElement> dataElements = new HashSet<>();
+
+        for ( Indicator indicator : indicators )
+        {
+            dataElements.addAll( getDataElementsInExpressionInternal( OPTION_COMBO_OPERAND_PATTERN, indicator.getNumerator() ) );
+            dataElements.addAll( getDataElementsInExpressionInternal( OPTION_COMBO_OPERAND_PATTERN, indicator.getDenominator() ) );
+        }
+
+        return dataElements;
+    }
+
+    @Override
+    public Set<DimensionalItemObject> getDimensionalItemObjectsInExpression( String expression )
+    {
+        Set<DimensionalItemObject> dimensionItems = Sets.newHashSet();
+
+        if ( expression == null || expression.isEmpty() )
+        {
+            return dimensionItems;
+        }
+
+        Matcher matcher = VARIABLE_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String dimensionItem = matcher.group( 2 );
+
+            DimensionalItemObject dimensionItemObject = dimensionService.getDataDimensionalItemObject( dimensionItem );
+
+            if ( dimensionItemObject != null )
+            {
+                dimensionItems.add( dimensionItemObject );
+            }
+        }
+
+        return dimensionItems;
+    }
+
+    @Override
+    public Set<DimensionalItemObject> getDimensionalItemObjectsInIndicators( Collection<Indicator> indicators )
+    {
+        Set<DimensionalItemObject> items = Sets.newHashSet();
+
+        for ( Indicator indicator : indicators )
+        {
+            items.addAll( getDimensionalItemObjectsInExpression( indicator.getNumerator() ) );
+            items.addAll( getDimensionalItemObjectsInExpression( indicator.getDenominator() ) );
+        }
+
+        return items;
+    }
+
+    @Override
+    public Set<OrganisationUnitGroup> getOrganisationUnitGroupsInExpression( String expression )
+    {
+        Set<OrganisationUnitGroup> groupsInExpression = new HashSet<>();
+
+        if ( expression != null )
+        {
+            final Matcher matcher = OU_GROUP_PATTERN.matcher( expression );
+
+            while ( matcher.find() )
+            {
+                final OrganisationUnitGroup group = organisationUnitGroupService
+                    .getOrganisationUnitGroup( matcher.group( 1 ) );
+
+                if ( group != null )
+                {
+                    groupsInExpression.add( group );
+                }
+            }
+        }
+
+        return groupsInExpression;
+    }
+
+    @Override
+    public Set<OrganisationUnitGroup> getOrganisationUnitGroupsInIndicators( Collection<Indicator> indicators )
+    {
+        Set<OrganisationUnitGroup> groups = new HashSet<>();
+
+        if ( indicators != null )
+        {
+            for ( Indicator indicator : indicators )
+            {
+                groups.addAll( getOrganisationUnitGroupsInExpression( indicator.getNumerator() ) );
+                groups.addAll( getOrganisationUnitGroupsInExpression( indicator.getDenominator() ) );
+            }
+        }
+
+        return groups;
+    }
+
+    @Override
+    @Transactional
+    public void filterInvalidIndicators( List<Indicator> indicators )
+    {
+        if ( indicators != null )
+        {
+            Iterator<Indicator> iterator = indicators.iterator();
+
+            while ( iterator.hasNext() )
+            {
+                Indicator indicator = iterator.next();
+
+                if ( !expressionIsValid( indicator.getNumerator() ).isValid()
+                    || !expressionIsValid( indicator.getDenominator() ).isValid() )
+                {
+                    iterator.remove();
+                    log.warn( "Indicator is invalid: " + indicator + ", " + indicator.getNumerator() + ", "
+                        + indicator.getDenominator() );
+                }
+            }
+        }
+    }
+
+    @Override
+    @Transactional
+    public ExpressionValidationOutcome expressionIsValid( String expression )
+    {
+        if ( expression == null || expression.isEmpty() )
+        {
+            return ExpressionValidationOutcome.EXPRESSION_IS_EMPTY;
+        }
+
+        // ---------------------------------------------------------------------
+        // Operands
+        // ---------------------------------------------------------------------
+
+        StringBuffer sb = new StringBuffer();
+        Matcher matcher = VARIABLE_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String dimensionItem = matcher.group( 2 );
+
+            if ( dimensionService.getDataDimensionalItemObject( dimensionItem ) == null )
+            {
+                return ExpressionValidationOutcome.DIMENSIONAL_ITEM_OBJECT_DOES_NOT_EXIST;
+            }
+
+            matcher.appendReplacement( sb, "1.1" );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Constants
+        // ---------------------------------------------------------------------
+
+        matcher = CONSTANT_PATTERN.matcher( expression );
+        sb = new StringBuffer();
+
+        while ( matcher.find() )
+        {
+            String constant = matcher.group( 1 );
+
+            if ( idObjectManager.getNoAcl( Constant.class, constant ) == null )
+            {
+                return ExpressionValidationOutcome.CONSTANT_DOES_NOT_EXIST;
+            }
+
+            matcher.appendReplacement( sb, "1.1" );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+        sb = new StringBuffer();
+
+        while ( matcher.find() )
+        {
+            String group = matcher.group( 1 );
+
+            if ( idObjectManager.getNoAcl( OrganisationUnitGroup.class, group ) == null )
+            {
+                return ExpressionValidationOutcome.ORG_UNIT_GROUP_DOES_NOT_EXIST;
+            }
+
+            matcher.appendReplacement( sb, "1.1" );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Days
+        // ---------------------------------------------------------------------
+
+        expression = expression.replaceAll( DAYS_EXPRESSION, "1.1" );
+
+        // ---------------------------------------------------------------------
+        // Well-formed expression
+        // ---------------------------------------------------------------------
+
+        if ( MathUtils.expressionHasErrors( expression ) )
+        {
+            return ExpressionValidationOutcome.EXPRESSION_IS_NOT_WELL_FORMED;
+        }
+
+        return ExpressionValidationOutcome.VALID;
+    }
+
+    @Override
+    @Transactional
+    public String getExpressionDescription( String expression )
+    {
+        if ( expression == null || expression.isEmpty() )
+        {
+            return null;
+        }
+
+        // ---------------------------------------------------------------------
+        // Operands
+        // ---------------------------------------------------------------------
+
+        StringBuffer sb = new StringBuffer();
+        Matcher matcher = VARIABLE_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String dimensionItem = matcher.group( 2 );
+
+            DimensionalItemObject dimensionItemObject = dimensionService.getDataDimensionalItemObject( dimensionItem );
+
+            if ( dimensionItemObject == null )
+            {
+                throw new InvalidIdentifierReferenceException( "Identifier does not reference a dimensional item object: " + dimensionItem );
+            }
+
+            matcher.appendReplacement( sb, Matcher.quoteReplacement( dimensionItemObject.getDisplayName() ) );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Constants
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = CONSTANT_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String co = matcher.group( 1 );
+
+            Constant constant = constantService.getConstant( co );
+
+            if ( constant == null )
+            {
+                throw new InvalidIdentifierReferenceException( "Identifier does not reference a constant: " + co );
+            }
+
+            matcher.appendReplacement( sb, Matcher.quoteReplacement( constant.getDisplayName() ) );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String oug = matcher.group( 1 );
+
+            OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( oug );
+
+            if ( group == null )
+            {
+                throw new InvalidIdentifierReferenceException( "Identifier does not reference an organisation unit group: " + oug );
+            }
+
+            matcher.appendReplacement( sb, Matcher.quoteReplacement( group.getDisplayName() ) );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Days
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = DAYS_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            matcher.appendReplacement( sb, DAYS_DESCRIPTION );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        return expression;
+    }
+
+    @Override
+    @Transactional
+    public void explodeValidationRuleExpressions( Collection<ValidationRule> validationRules )
+    {
+        if ( validationRules != null && !validationRules.isEmpty() )
+        {
+            Set<String> dataElementTotals = new HashSet<>();
+
+            for ( ValidationRule rule : validationRules )
+            {
+                dataElementTotals.addAll(
+                    RegexUtils.getMatches( DATA_ELEMENT_TOTAL_PATTERN, rule.getLeftSide().getExpression(), 1 ) );
+                dataElementTotals.addAll(
+                    RegexUtils.getMatches( DATA_ELEMENT_TOTAL_PATTERN, rule.getRightSide().getExpression(), 1 ) );
+            }
+
+            if ( !dataElementTotals.isEmpty() )
+            {
+                final ListMap<String, String> dataElementMap = dataElementService
+                    .getDataElementCategoryOptionComboMap( dataElementTotals );
+
+                if ( !dataElementMap.isEmpty() )
+                {
+                    for ( ValidationRule rule : validationRules )
+                    {
+                        rule.getLeftSide().setExplodedExpression(
+                            explodeExpression( rule.getLeftSide().getExplodedExpressionFallback(), dataElementMap ) );
+                        rule.getRightSide().setExplodedExpression(
+                            explodeExpression( rule.getRightSide().getExplodedExpressionFallback(), dataElementMap ) );
+                    }
+                }
+            }
+        }
+    }
+
+    private String explodeExpression( String expression, ListMap<String, String> dataElementOptionComboMap )
+    {
+        if ( expression == null || expression.isEmpty() )
+        {
+            return null;
+        }
+
+        StringBuffer sb = new StringBuffer();
+        Matcher matcher = OPERAND_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            if ( operandIsTotal( matcher ) )
+            {
+                final StringBuilder replace = new StringBuilder( PAR_OPEN );
+
+                String de = matcher.group( 1 );
+
+                List<String> cocs = dataElementOptionComboMap.get( de );
+
+                for ( String coc : cocs )
+                {
+                    replace.append( EXP_OPEN ).append( de ).append( SEPARATOR ).
+                        append( coc ).append( EXP_CLOSE ).append( "+" );
+                }
+
+                replace.deleteCharAt( replace.length() - 1 ).append( PAR_CLOSE );
+                matcher.appendReplacement( sb, Matcher.quoteReplacement( replace.toString() ) );
+            }
+        }
+
+        return TextUtils.appendTail( matcher, sb );
+    }
+
+    @Override
+    @Transactional
+    public String explodeExpression( String expression )
+    {
+        if ( expression == null || expression.isEmpty() )
+        {
+            return null;
+        }
+
+        StringBuffer sb = new StringBuffer();
+        Matcher matcher = OPERAND_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            if ( operandIsTotal( matcher ) )
+            {
+                final StringBuilder replace = new StringBuilder( PAR_OPEN );
+
+                final DataElement dataElement = idObjectManager.getNoAcl( DataElement.class, matcher.group( 1 ) );
+
+                final DataElementCategoryCombo categoryCombo = dataElement.getCategoryCombo();
+
+                for ( DataElementCategoryOptionCombo categoryOptionCombo : categoryCombo.getOptionCombos() )
+                {
+                    replace.append( EXP_OPEN ).append( dataElement.getUid() ).append( SEPARATOR ).
+                        append( categoryOptionCombo.getUid() ).append( EXP_CLOSE ).append( "+" );
+                }
+
+                replace.deleteCharAt( replace.length() - 1 ).append( PAR_CLOSE );
+                matcher.appendReplacement( sb, Matcher.quoteReplacement( replace.toString() ) );
+            }
+        }
+
+        return TextUtils.appendTail( matcher, sb );
+    }
+
+    @Override
+    @Transactional
+    public void substituteExpressions( Collection<Indicator> indicators, Integer days )
+    {
+        if ( indicators != null && !indicators.isEmpty() )
+        {
+            Map<String, Constant> constants = new CachingMap<String, Constant>()
+                .load( idObjectManager.getAllNoAcl( Constant.class ), c -> c.getUid() );
+
+            Map<String, OrganisationUnitGroup> orgUnitGroups = new CachingMap<String, OrganisationUnitGroup>()
+                .load( idObjectManager.getAllNoAcl( OrganisationUnitGroup.class ), g -> g.getUid() );
+
+            for ( Indicator indicator : indicators )
+            {
+                indicator.setExplodedNumerator( substituteExpression( 
+                    indicator.getNumerator(), constants, orgUnitGroups, days ) );
+                indicator.setExplodedDenominator( substituteExpression( 
+                    indicator.getDenominator(), constants, orgUnitGroups, days ) );
+            }
+        }
+    }
+
+    private String substituteExpression( String expression, Map<String, Constant> constants,
+        Map<String, OrganisationUnitGroup> orgUnitGroups, Integer days )
+    {
+        if ( expression == null || expression.isEmpty() )
+        {
+            return null;
+        }
+
+        // ---------------------------------------------------------------------
+        // Constants
+        // ---------------------------------------------------------------------
+
+        StringBuffer sb = new StringBuffer();
+        Matcher matcher = CONSTANT_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String co = matcher.group( 1 );
+
+            Constant constant = constants.get( co );
+
+            String replacement = constant != null ? String.valueOf( constant.getValue() ) : NULL_REPLACEMENT;
+
+            matcher.appendReplacement( sb, Matcher.quoteReplacement( replacement ) );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String oug = matcher.group( 1 );
+
+            OrganisationUnitGroup group = orgUnitGroups.get( oug );
+
+            String replacement = group != null ? String.valueOf( group.getMembers().size() ) : NULL_REPLACEMENT;
+
+            matcher.appendReplacement( sb, replacement );
+
+            // TODO sub tree
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Days
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = DAYS_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String replacement = days != null ? String.valueOf( days ) : NULL_REPLACEMENT;
+
+            matcher.appendReplacement( sb, replacement );
+        }
+
+        return TextUtils.appendTail( matcher, sb );
+    }
+
+    @Override
+    public String generateExpression( String expression, Map<? extends DimensionalItemObject, Double> valueMap,
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days,
+        MissingValueStrategy missingValueStrategy )
+    {
+        return generateExpression( expression, valueMap, constantMap, orgUnitCountMap, days, missingValueStrategy, null,
+            null );
+    }
+
+    private String generateExpression( String expression, Map<? extends DimensionalItemObject, Double> valueMap,
+        Map<String, Double> constantMap, Map<String, Integer> orgUnitCountMap, Integer days,
+        MissingValueStrategy missingValueStrategy, Set<DataElementOperand> incompleteValues,
+        Map<String, List<Double>> aggregateMap )
+    {
+        if ( expression == null || expression.isEmpty() )
+        {
+            return null;
+        }
+
+        Map<String, Double> dimensionItemValueMap = valueMap.entrySet().stream().
+            collect( Collectors.toMap( e -> e.getKey().getDimensionItem(), e -> e.getValue() ) );
+
+        Set<String> incompleteItems = incompleteValues != null ? 
+            incompleteValues.stream().map( i -> i.getDimensionItem() ).collect( Collectors.toSet() ) : Sets.newHashSet();
+
+        missingValueStrategy = missingValueStrategy == null ? NEVER_SKIP : missingValueStrategy;
+
+        // ---------------------------------------------------------------------
+        // Substitute aggregates
+        // ---------------------------------------------------------------------
+
+        StringBuffer sb = new StringBuffer();
+
+        Pattern prefix = CustomFunctions.getAggregatePrefixPattern();
+        Matcher matcher = prefix.matcher( expression );
+
+        int scan = 0, len = expression.length(), tail = 0;
+        
+        while ( (scan < len) && (matcher.find( scan )) )
+        {
+            int start = matcher.end();
+            int end = Expression.matchExpression( expression, start );
+            
+            if ( end < 0 )
+            {
+                sb.append( expression.substring( scan, start ) );
+                scan = start + 1;
+                tail = start;
+            }
+            else if ( ( aggregateMap == null) || ( expression.charAt( start ) == '<' ) )
+            {
+                sb.append( expression.substring( scan, end ) );
+                scan = end + 1;
+                tail = end;
+            }
+            else
+            {
+                String sub_expression = expression.substring( start, end );
+                List<Double> samples = aggregateMap.get( sub_expression );
+
+                if ( samples == null )
+                {
+                    if ( SKIP_IF_ANY_VALUE_MISSING.equals( missingValueStrategy ) )
+                    {
+                        return null;
+                    }
+                    else
+                    {
+                    }
+                }
+                else
+                {
+                    String literal = (samples == null) ? ("[]") : (samples.toString());
+                    sb.append( expression.substring( scan, start ) );
+                    sb.append( literal );
+                }
+                
+                scan = end;
+                tail = end;
+            }
+        }
+
+        sb.append( expression.substring( tail ) );
+        expression = sb.toString();
+
+        // ---------------------------------------------------------------------
+        // DimensionalItemObjects
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = VARIABLE_PATTERN.matcher( expression );
+
+        int matchCount = 0;
+        int valueCount = 0;
+
+        while ( matcher.find() )
+        {
+            matchCount++;
+
+            String dimItem = matcher.group( 2 );
+
+            final Double value = dimensionItemValueMap.get( dimItem );
+
+            boolean missingValue = value == null || incompleteItems.contains( dimItem );
+
+            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, Matcher.quoteReplacement( replacement ) );
+        }
+
+        if ( SKIP_IF_ALL_VALUES_MISSING.equals( missingValueStrategy ) && matchCount > 0 && valueCount == 0 )
+        {
+            return null;
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Constants
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = CONSTANT_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            final Double constant = constantMap != null ? constantMap.get( matcher.group( 1 ) ) : null;
+
+            String replacement = constant != null ? String.valueOf( constant ) : NULL_REPLACEMENT;
+
+            matcher.appendReplacement( sb, replacement );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            final Integer count = orgUnitCountMap != null ? orgUnitCountMap.get( matcher.group( 1 ) ) : null;
+
+            String replacement = count != null ? String.valueOf( count ) : NULL_REPLACEMENT;
+
+            matcher.appendReplacement( sb, replacement );
+        }
+
+        expression = TextUtils.appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Days
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = DAYS_PATTERN.matcher( expression );
+
+        while ( matcher.find() )
+        {
+            String replacement = days != null ? String.valueOf( days ) : NULL_REPLACEMENT;
+
+            matcher.appendReplacement( sb, replacement );
+        }
+
+        return TextUtils.appendTail( matcher, sb );
+    }
+
+    @Override
+    @Transactional
+    public List<DataElementOperand> getOperandsInIndicators( List<Indicator> indicators )
+    {
+        final List<DataElementOperand> operands = new ArrayList<>();
+
+        for ( Indicator indicator : indicators )
+        {
+            Set<DataElementOperand> temp = getOperandsInExpression( indicator.getExplodedNumerator() );
+            operands.addAll( temp != null ? temp : new HashSet<DataElementOperand>() );
+
+            temp = getOperandsInExpression( indicator.getExplodedDenominator() );
+            operands.addAll( temp != null ? temp : new HashSet<DataElementOperand>() );
+        }
+
+        return operands;
+    }
+
+    // -------------------------------------------------------------------------
+    // Supportive methods
+    // -------------------------------------------------------------------------
+
+    private boolean operandIsTotal( Matcher matcher )
+    {
+        return matcher != null && StringUtils.trimToEmpty( matcher.group( 2 ) ).isEmpty();
+    }
 }

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/ArithmeticMean.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/ArithmeticMean.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/ArithmeticMean.java	2016-03-02 21:51:09 +0000
@@ -53,11 +53,10 @@
     public void run( Stack inStack )
         throws ParseException
     {
-
-        // check the stack
         checkStack( inStack );
 
         Object param = inStack.pop();
+        
         if ( param instanceof List )
         {
             List<Double> vals = CustomFunctions.checkVector( param );
@@ -78,6 +77,8 @@
             }
         }
         else
+        {
             throw new ParseException( "Invalid aggregate value in expression" );
+        }
     }
 }

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/Count.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/Count.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/Count.java	2016-03-02 21:51:09 +0000
@@ -53,7 +53,6 @@
     public void run( Stack inStack )
         throws ParseException
     {
-        // check the stack
         checkStack( inStack );
 
         Object param = inStack.pop();

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/CustomFunctions.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/CustomFunctions.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/CustomFunctions.java	2016-03-02 21:51:09 +0000
@@ -44,7 +44,6 @@
  */
 public class CustomFunctions
 {
-
     private static Boolean init_done = false;
 
     public static Map<String, PostfixMathCommandI> aggregate_functions = new HashMap<String, PostfixMathCommandI>();
@@ -52,7 +51,10 @@
     public static void addFunctions( JEP parser )
     {
         if ( !(init_done) )
+        {
             initCustomFunctions();
+        }
+        
         for ( Entry<String, PostfixMathCommandI> e : aggregate_functions.entrySet() )
         {
             String fname = e.getKey();
@@ -68,14 +70,20 @@
     public static Pattern getAggregatePrefixPattern()
     {
         if ( !(init_done) )
+        {
             initCustomFunctions();
+        }
+        
         if ( n_aggregates == aggregate_functions.size() )
+        {
             return aggregate_prefix;
+        }
         else
         {
             StringBuffer s = new StringBuffer();
             int i = 0;
             s.append( "(" );
+            
             for ( String key : aggregate_functions.keySet() )
             {
                 if ( i > 0 )
@@ -84,6 +92,7 @@
                     i++;
                 s.append( key );
             }
+            
             s.append( ")\\s*\\(" );
             aggregate_prefix = Pattern.compile( s.toString() );
             n_aggregates = aggregate_functions.size();
@@ -103,23 +112,34 @@
         if ( param instanceof List )
         {
             List<?> vals = (List<?>) param;
+            
             for ( Object val : vals )
             {
                 if ( !(val instanceof Double) )
+                {
                     throw new ParseException( "Non numeric vector" );
+                }
             }
+            
             return (List<Double>) param;
         }
         else
+        {
             throw new ParseException( "Invalid vector argument" );
+        }
     }
 
     private synchronized static void initCustomFunctions()
     {
         if ( init_done )
+        {
             return;
+        }
         else
+        {
             init_done = true;
+        }
+        
         CustomFunctions.addAggregateFunction( "AVG", new ArithmeticMean() );
         CustomFunctions.addAggregateFunction( "STDDEV", new StandardDeviation() );
         CustomFunctions.addAggregateFunction( "MEDIAN", new MedianValue() );

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MaxValue.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MaxValue.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MaxValue.java	2016-03-02 21:51:09 +0000
@@ -53,19 +53,24 @@
     public void run( Stack inStack )
         throws ParseException
     {
-        // check the stack
         checkStack( inStack );
 
         Object param = inStack.pop();
         List<Double> vals = CustomFunctions.checkVector( param );
         Double max = null;
+        
         for ( Double v : vals )
         {
             if ( max == null )
+            {
                 max = v;
+            }
             else if ( v > max )
+            {
                 max = v;
+            }
         }
+        
         inStack.push( new Double( max ) );
     }
 }

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MedianValue.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MedianValue.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MedianValue.java	2016-03-02 21:51:09 +0000
@@ -53,7 +53,6 @@
     public void run( Stack inStack )
         throws ParseException
     {
-        // check the stack
         checkStack( inStack );
 
         Object param = inStack.pop();
@@ -65,6 +64,8 @@
             inStack.push( new Double( (vals.get( n / 2 ) + vals.get( n / 2 + 1 )) / 2 ) );
         }
         else
+        {
             inStack.push( new Double( vals.get( (n + 1) / 2 ) ) );
+        }
     }
 }

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MinValue.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MinValue.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/MinValue.java	2016-03-02 21:51:09 +0000
@@ -53,7 +53,6 @@
     public void run( Stack inStack )
         throws ParseException
     {
-        // check the stack
         checkStack( inStack );
 
         Object param = inStack.pop();
@@ -62,9 +61,13 @@
         for ( Double v : vals )
         {
             if ( min == null )
+            {
                 min = v;
+            }
             else if ( v < min )
+            {
                 min = v;
+            }
         }
         inStack.push( new Double( min ) );
     }

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/StandardDeviation.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/StandardDeviation.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/StandardDeviation.java	2016-03-02 21:51:09 +0000
@@ -53,12 +53,12 @@
     public void run( Stack inStack )
         throws ParseException
     {
-        // check the stack
         checkStack( inStack );
 
         Object param = inStack.pop();
         List<Double> vals = CustomFunctions.checkVector( param );
         int n = vals.size();
+        
         if ( n == 0 )
         {
             inStack.push( new Double( 0 ) );
@@ -66,16 +66,19 @@
         else
         {
             double sum = 0, sum2 = 0, mean, variance;
+            
             for ( Double v : vals )
             {
                 sum = sum + v;
             }
 
             mean = sum / n;
+            
             for ( Double v : vals )
             {
                 sum2 = sum2 + ((v - mean) * (v - mean));
             }
+            
             variance = sum2 / n;
             inStack.push( new Double( Math.sqrt( variance ) ) );
         }

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/VectorSum.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/VectorSum.java	2016-01-13 12:54:38 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/jep/VectorSum.java	2016-03-02 21:51:09 +0000
@@ -53,10 +53,10 @@
     public void run( Stack inStack )
         throws ParseException
     {
-        // check the stack
         checkStack( inStack );
 
         Object param = inStack.pop();
+        
         if ( param instanceof List )
         {
             List<Double> vals = CustomFunctions.checkVector( param );
@@ -76,6 +76,8 @@
             }
         }
         else
+        {
             throw new ParseException( "Invalid aggregate value in expression" );
+        }
     }
 }