Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hisp.dhis.rules.RuleConditionEvaluator Maven / Gradle / Ivy
package org.hisp.dhis.rules;
import org.apache.commons.lang3.StringUtils;
import org.hisp.dhis.antlr.Parser;
import org.hisp.dhis.antlr.ParserExceptionWithoutContext;
import org.hisp.dhis.rules.models.*;
import org.hisp.dhis.rules.parser.expression.CommonExpressionVisitor;
import org.hisp.dhis.rules.utils.RuleEngineUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import java.util.*;
import static org.hisp.dhis.rules.parser.expression.ParserUtils.FUNCTION_EVALUATE;
public class RuleConditionEvaluator
{
private static final Logger log = LoggerFactory.getLogger( RuleConditionEvaluator.class.getName() );
public List getEvaluatedAndErrorRuleEffects( TrackerObjectType targetType, String targetUid, Map valueMap,
Map> supplementaryData, List rules )
{
List ruleEffects = new ArrayList<>();
for (RuleEvaluationResult ruleEvaluationResult : getRuleEvaluationResults( targetType, targetUid, valueMap, supplementaryData, rules)) {
ruleEffects.addAll( ruleEvaluationResult.getRuleEffects() );
}
return ruleEffects;
}
public List getRuleEffects( TrackerObjectType targetType, String targetUid, Map valueMap,
Map> supplementaryData, List rules )
{
List ruleEffects = new ArrayList<>();
for (RuleEvaluationResult ruleEvaluationResult : getRuleEvaluationResults( targetType, targetUid, valueMap, supplementaryData, rules)) {
if ( !ruleEvaluationResult.isError() ) {
ruleEffects.addAll( ruleEvaluationResult.getRuleEffects() );
}
}
return ruleEffects;
}
public List getRuleEvaluationResults( TrackerObjectType targetType, String targetUid,
Map valueMap,
Map> supplementaryData, List rules )
{
List ruleEvaluationResults = new ArrayList<>();
rules = orderRules( rules );
valueMap = new HashMap<>( valueMap );
for ( Rule rule : orderRules( rules ) )
{
log.debug( "Evaluating programrule: " + rule.name() );
try {
List ruleEffects = new ArrayList<>();
if ( Boolean.valueOf( process( rule.condition(), valueMap, supplementaryData ) ) )
{
for ( RuleAction action : rule.actions() )
{
try {
//Check if action is assigning value to calculated variable
if ( isAssignToCalculatedValue( action ) )
{
RuleActionAssign ruleActionAssign = (RuleActionAssign) action;
updateValueMap(
Utils.unwrapVariableName(ruleActionAssign.content()),
RuleVariableValue.create(process( ruleActionAssign.data(), valueMap, supplementaryData),
RuleValueType.TEXT),
valueMap
);
}
else
{
ruleEffects.add( create( rule, action, valueMap, supplementaryData ) );
}
} catch ( Exception e ) {
addRuleErrorResult( rule,action, e, targetType, targetUid, ruleEvaluationResults );
}
}
ruleEvaluationResults.add(RuleEvaluationResult.evaluatedResult(rule, ruleEffects));
} else {
ruleEvaluationResults.add(RuleEvaluationResult.notEvaluatedResult(rule));
}
} catch ( Exception e ) {
addRuleErrorResult(rule, null, e, targetType, targetUid, ruleEvaluationResults);
}
}
for (RuleEvaluationResult ruleEvaluationResult : ruleEvaluationResults) {
log.debug("Rule " + ruleEvaluationResult.getRule().name() + " with id " + ruleEvaluationResult.getRule().uid() +
" executed for " + targetType.getName() + "(" + targetUid + ")" +
" with condition (" + ruleEvaluationResult.getRule().condition() + ")" +
" was evaluated " + ruleEvaluationResult.isEvaluatedAs());
}
return ruleEvaluationResults;
}
private void addRuleErrorResult( Rule rule, RuleAction ruleAction, Exception e, TrackerObjectType targetType,
String targetUid, List ruleEvaluationResults )
{
String errorMessage;
if ( ruleAction != null && e instanceof ParserExceptionWithoutContext )
{
errorMessage = "Action " + ruleAction.getClass().getName() +
" from rule " + rule.name() + " with id " + rule.uid() +
" executed for " + targetType.getName() + "(" + targetUid + ")" +
" with condition (" + rule.condition() + ")" +
" raised an error: " + e.getMessage();
}
else if ( ruleAction != null )
{
errorMessage = "Action " + ruleAction.getClass().getName() +
" from rule " + rule.name() + " with id " + rule.uid() +
" executed for " + targetType.getName() + "(" + targetUid + ")" +
" with condition (" + rule.condition() + ")" +
" raised an unexpected exception: " + e.getMessage();
}
else if(e instanceof ParserExceptionWithoutContext)
{
errorMessage = "Rule " + rule.name() + " with id " + rule.uid() +
" executed for " + targetType.getName() + "(" + targetUid + ")" +
" with condition (" + rule.condition() + ")" +
" raised an error: " + e.getMessage();
}
else
{
errorMessage = "Rule " + rule.name() + " with id " + rule.uid() +
" executed for " + targetType.getName() + "(" + targetUid + ")" +
" with condition (" + rule.condition() + ")" +
" raised an unexpected exception: " + e.getMessage();
}
log.error(errorMessage);
ruleEvaluationResults.add(RuleEvaluationResult.errorRule(rule, errorMessage));
}
private List orderRules( List rules )
{
List ruleList = new ArrayList<>( rules );
Collections.sort( ruleList, new Comparator()
{
@Override
public int compare( Rule rule1, Rule rule2 )
{
Integer priority1 = rule1.priority();
Integer priority2 = rule2.priority();
if ( priority1 != null && priority2 != null )
{
return priority1.compareTo( priority2 );
}
else if ( priority1 != null )
{
return -1;
}
else if ( priority2 != null )
{
return 1;
}
else
{
return 0;
}
}
} );
return ruleList;
}
private String process( String condition, Map valueMap,
Map> supplementaryData )
{
if ( condition.isEmpty() )
{
return "";
}
CommonExpressionVisitor commonExpressionVisitor = CommonExpressionVisitor.newBuilder()
.withFunctionMap( RuleEngineUtils.FUNCTIONS )
.withFunctionMethod( FUNCTION_EVALUATE )
.withVariablesMap( valueMap )
.withSupplementaryData( supplementaryData )
.validateCommonProperties();
Object result = Parser.visit( condition, commonExpressionVisitor, !isOldAndroidVersion( valueMap, supplementaryData ) );
return convertInteger( result ).toString();
}
private Object convertInteger( Object result )
{
if ( result instanceof Double && (Double) result % 1 == 0 )
{
return ((Double) result).intValue();
}
return result;
}
private Boolean isOldAndroidVersion( Map valueMap, Map> supplementaryData )
{
return valueMap.containsKey( "environment" ) &&
Objects.equals( valueMap.get( "environment" ).value(), TriggerEnvironment.ANDROIDCLIENT.getClientName() ) &&
supplementaryData.containsKey( "android_version" ) &&
Integer.parseInt( supplementaryData.get( "android_version" ).get( 0 ) ) < 21;
}
private Boolean isAssignToCalculatedValue( RuleAction ruleAction )
{
return ruleAction instanceof RuleActionAssign && ((RuleActionAssign) ruleAction).field().isEmpty();
}
private void updateValueMap( String variable, RuleVariableValue value, Map valueMap )
{
valueMap.put( variable, value );
}
@Nonnull
private RuleEffect create( @Nonnull Rule rule,
@Nonnull RuleAction ruleAction,
Map valueMap,
Map> supplementaryData )
{
if ( ruleAction instanceof RuleActionAssign )
{
RuleActionAssign ruleActionAssign = (RuleActionAssign) ruleAction;
String data = process( ruleActionAssign.data(), valueMap, supplementaryData );
updateValueMap( ruleActionAssign.field(), RuleVariableValue.create( data, RuleValueType.TEXT ), valueMap );
if ( StringUtils.isEmpty( data ) && StringUtils.isEmpty( ruleActionAssign.data() ) )
{
return RuleEffect.create( rule.uid(), ruleAction, ruleActionAssign.data() );
}
else
{
return RuleEffect.create( rule.uid(), ruleAction, data );
}
}
return RuleEffect.create( rule.uid(), ruleAction, process( ruleAction.data(), valueMap, supplementaryData ) );
}
}