Skip to content

Commit

Permalink
fixed DecisionService execution stack not updating when having Compos…
Browse files Browse the repository at this point in the history
…eDecisionResultBehavior hitpolicy (#3760)
  • Loading branch information
yvoswillens authored and tijsrademakers committed Nov 17, 2023
1 parent 6c178cc commit 8ad5e1e
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,16 @@ public void composeRuleResult(int ruleNumber, String outputName, Object outputVa
@Override
public void composeDecisionResults(ELExecutionContext executionContext) {
List<Map<String, Object>> decisionResults = new ArrayList<>(executionContext.getRuleResults().values());

updateStackWithDecisionResults(decisionResults, executionContext);

DecisionExecutionAuditContainer auditContainer = executionContext.getAuditContainer();
auditContainer.setDecisionResult(decisionResults);
auditContainer.setMultipleResults(multipleResults);
}

@Override
public void updateStackWithDecisionResults(List<Map<String, Object>> decisionResults, ELExecutionContext executionContext) {
decisionResults.forEach(result -> result.forEach((k, v) -> executionContext.getStackVariables().put(k, v)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
*/
package org.flowable.dmn.engine.impl.hitpolicy;

import java.util.List;
import java.util.Map;

import org.flowable.dmn.engine.impl.el.ELExecutionContext;

/**
Expand All @@ -20,4 +23,5 @@
public interface ComposeDecisionResultBehavior {

void composeDecisionResults(ELExecutionContext executionContext);
void updateStackWithDecisionResults(List<Map<String, Object>> decisionResults, ELExecutionContext executionContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,14 @@ public void composeDecisionResults(final ELExecutionContext executionContext) {
if (CommandContextUtil.getDmnEngineConfiguration().isStrictMode() == false && validationFailed) {
executionContext.getAuditContainer().setValidationMessage(String.format("HitPolicy %s violated; multiple valid rules with different outcomes. Setting last valid rule result as final result.", getHitPolicyName()));
}
executionContext.getAuditContainer().addDecisionResultObject(ruleResults.get(ruleResults.size() - 1));

List<Map<String, Object>> decisionResults = new ArrayList<>();
decisionResults.add(ruleResults.get(ruleResults.size() - 1));

updateStackWithDecisionResults(decisionResults, executionContext);

// put decision results on audit container
executionContext.getAuditContainer().setDecisionResult(decisionResults);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ public void composeDecisionResults(ELExecutionContext executionContext) {
}
}
}

updateStackWithDecisionResults(decisionResults, executionContext);

// put decision results on audit container
executionContext.getAuditContainer().setDecisionResult(decisionResults);
// the `multipleResults` flag depends on the aggregator. If there is no aggregation there are more results.
executionContext.getAuditContainer().setMultipleResults(isMultipleResults(executionContext.getAggregator()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,21 @@ public void composeDecisionResults(final ELExecutionContext executionContext) {
}

// sort on predefined list(s) of output values
ruleResults.sort(new Comparator<Map<String, Object>>() {

@Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
CompareToBuilder compareToBuilder = new CompareToBuilder();
for (Map.Entry<String, List<Object>> entry : executionContext.getOutputValues().entrySet()) {
List<Object> outputValues = entry.getValue();
if (outputValues != null && !outputValues.isEmpty()) {
compareToBuilder.append(o1.get(entry.getKey()), o2.get(entry.getKey()),
new OutputOrderComparator<>(outputValues.toArray(new Comparable[outputValues.size()])));
compareToBuilder.toComparison();
}
ruleResults.sort((o1, o2) -> {
CompareToBuilder compareToBuilder = new CompareToBuilder();
for (Map.Entry<String, List<Object>> entry : executionContext.getOutputValues().entrySet()) {
List<Object> outputValues = entry.getValue();
if (outputValues != null && !outputValues.isEmpty()) {
compareToBuilder.append(o1.get(entry.getKey()), o2.get(entry.getKey()),
new OutputOrderComparator<>(outputValues.toArray(new Comparable[outputValues.size()])));
compareToBuilder.toComparison();
}
return compareToBuilder.toComparison();
}
return compareToBuilder.toComparison();
});

updateStackWithDecisionResults(ruleResults, executionContext);

DecisionExecutionAuditContainer auditContainer = executionContext.getAuditContainer();
auditContainer.setDecisionResult(ruleResults);
auditContainer.setMultipleResults(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void evaluateRuleValidity(int ruleNumber, ELExecutionContext executionCon
@Override
public void composeDecisionResults(ELExecutionContext executionContext) {
List<Map<String, Object>> ruleResults = new ArrayList<>(executionContext.getRuleResults().values());
List<Map<String, Object>> decisionResult = null;
List<Map<String, Object>> decisionResults;

if (ruleResults.size() > 1 && CommandContextUtil.getDmnEngineConfiguration().isStrictMode() == false) {
Map<String, Object> lastResult = new HashMap<>();
Expand All @@ -71,11 +71,12 @@ public void composeDecisionResults(ELExecutionContext executionContext) {
}

executionContext.getAuditContainer().setValidationMessage(String.format("HitPolicy %s violated; multiple valid rules. Setting last valid rule result as final result.", getHitPolicyName()));
decisionResult = Collections.singletonList(lastResult);
decisionResults = Collections.singletonList(lastResult);
} else {
decisionResult = ruleResults;
decisionResults = ruleResults;
}

executionContext.getAuditContainer().setDecisionResult(decisionResult);
updateStackWithDecisionResults(decisionResults, executionContext);
executionContext.getAuditContainer().setDecisionResult(decisionResults);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,22 @@ public void executeDecisionServiceWithSingleResultMultipleResults() {
.isInstanceOf(FlowableException.class)
.hasMessageContaining("more than one result in decision: decision1");
}

@Test
@DmnDeployment(resources = "org/flowable/dmn/engine/test/runtime/decisionServiceStackUpdate.dmn")
public void executeDecisionServiceWithCollectStackUpdate() {
DmnEngine dmnEngine = flowableDmnRule.getDmnEngine();
DmnDecisionService dmnRuleService = dmnEngine.getDmnDecisionService();

Map<String, Object> result = dmnRuleService.createExecuteDecisionBuilder()
.decisionKey("expandedDecisionService")
.variable("inputVariable1", 5D)
.executeDecisionServiceWithSingleResult();

Map<String, Object> expectedResult = new HashMap<>();
expectedResult.put("serviceOutput1", "larger than 30");

assertThat(result)
.containsAllEntriesOf(expectedResult);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<definitions xmlns="http://www.omg.org/spec/DMN/20180521/MODEL/" id="definition_47a8ccd5-7efa-11ea-9435-acde48001122"
name="decisionService1" namespace="http://www.flowable.org/dmn">
<decision id="decision1" name="Decision 1">
<informationRequirement id="sid-7C9FC3B2-BC15-40EB-ABD7-32AFC0EBF4F3">
<requiredDecision href="#decision2"></requiredDecision>
</informationRequirement>
<decisionTable id="decisionTable_dffebb42-6761-4777-a09c-6c06c22c4cf0" hitPolicy="FIRST">
<input>
<inputExpression id="inputExpression_7db43806-e0c5-4c02-9d85-85dcbb5bd98b" typeRef="number">
<text>outputVariable1</text>
</inputExpression>
</input>
<output id="outputExpression_3ef3ef56-ef7a-4833-ac93-13d518904c81" name="serviceOutput1" typeRef="string"></output>
<rule>
<inputEntry id="inputEntry_7db43806-e0c5-4c02-9d85-85dcbb5bd98b_1">
<text><![CDATA[> 40]]></text>
</inputEntry>
<outputEntry id="outputEntry_3ef3ef56-ef7a-4833-ac93-13d518904c81_1">
<text>
<![CDATA["larger than 30"]]>
</text>
</outputEntry>
</rule>
</decisionTable>
</decision>
<decision id="decision2" name="Decision 2">
<decisionTable id="decisionTable_c00ca5b5-6e20-4477-a50c-c7a89ddf9987" hitPolicy="COLLECT" aggregation="SUM">
<input>
<inputExpression id="inputVariable1" typeRef="double">
<text>inputVariable1</text>
</inputExpression>
</input>
<output id="output1" label="Output 1" name="outputVariable1" typeRef="number" />
<rule>
<inputEntry id="inputEntry1">
<text><![CDATA[< 10]]></text>
</inputEntry>
<outputEntry id="outputEntry1_1">
<text>10</text>
</outputEntry>
</rule>
<rule>
<inputEntry id="inputEntry2">
<text><![CDATA[< 20]]></text>
</inputEntry>
<outputEntry id="outputEntry2_1">
<text>20</text>
</outputEntry>
</rule>
<rule>
<inputEntry id="inputEntry3">
<text><![CDATA[< 30]]></text>
</inputEntry>
<outputEntry id="outputEntry3_1">
<text>30</text>
</outputEntry>
</rule>
<rule>
<inputEntry id="inputEntry4">
<text><![CDATA[< 40]]></text>
</inputEntry>
<outputEntry id="outputEntry4_1">
<text>30</text>
</outputEntry>
</rule>
</decisionTable>
</decision>
<decisionService id="expandedDecisionService" name="expandedDecisionService">
<outputDecision href="#decision1"></outputDecision>
<encapsulatedDecision href="#decision2"></encapsulatedDecision>
</decisionService>
</definitions>

0 comments on commit 8ad5e1e

Please sign in to comment.