This is an automated email from the ASF dual-hosted git repository.
gitgabrio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/main by this push:
new f1307e131c [incubator-kie-issues#1543] Add the "id" of executed rules
to the AfterEvaluateDecisionTableEvent (#6127)
f1307e131c is described below
commit f1307e131c42dcb0780c19ede653c3a895b2be3b
Author: Gabriele Cardosi <[email protected]>
AuthorDate: Fri Oct 18 10:29:39 2024 +0200
[incubator-kie-issues#1543] Add the "id" of executed rules to the
AfterEvaluateDecisionTableEvent (#6127)
* [incubator-kie-issues#1543] Add the "id" of executed rules to the
AfterEvaluateDecisionTableEvent
* [incubator-kie-issues#1543] Fix TODO
* [incubator-kie-issues#1543] Fix license header
* [incubator-kie-issues#1543] Minor refactoring on unrelated test
* [incubator-kie-issues#1543] Fix as per PR review
---------
Co-authored-by: Gabriele-Cardosi <[email protected]>
---
.../event/AfterEvaluateDecisionTableEvent.java | 4 +
.../core/jsr223/JSR223DTExpressionEvaluator.java | 6 +-
.../kie/dmn/core/ast/DMNDTExpressionEvaluator.java | 10 +-
.../dmn/core/compiler/DMNEvaluatorCompiler.java | 2 +-
.../DMNAlphaNetworkEvaluatorImpl.java | 5 +-
.../dmn/core/compiler/alphanetbased/Results.java | 49 ++-
.../impl/AfterEvaluateDecisionTableEventImpl.java | 17 +-
.../dmn/core/impl/DMNRuntimeEventManagerUtils.java | 4 +-
.../java/org/kie/dmn/core/DMNInputRuntimeTest.java | 38 +-
.../runtime/decisiontables/DTDecisionRule.java | 8 +-
.../runtime/decisiontables/DecisionTableImpl.java | 14 +-
.../dmn/feel/runtime/decisiontables/HitPolicy.java | 482 ++++++++++-----------
.../events/DecisionTableRulesMatchedEvent.java | 9 +-
.../events/DecisionTableRulesSelectedEvent.java | 9 +-
.../runtime/functions/DecisionTableFunction.java | 2 +-
.../ForIterationUtilsTest.java | 4 +-
.../feel/runtime/functions/DateFunctionTest.java | 2 +-
17 files changed, 369 insertions(+), 296 deletions(-)
diff --git
a/kie-dmn/kie-dmn-api/src/main/java/org/kie/dmn/api/core/event/AfterEvaluateDecisionTableEvent.java
b/kie-dmn/kie-dmn-api/src/main/java/org/kie/dmn/api/core/event/AfterEvaluateDecisionTableEvent.java
index 3fac12be82..6daa2958bd 100644
---
a/kie-dmn/kie-dmn-api/src/main/java/org/kie/dmn/api/core/event/AfterEvaluateDecisionTableEvent.java
+++
b/kie-dmn/kie-dmn-api/src/main/java/org/kie/dmn/api/core/event/AfterEvaluateDecisionTableEvent.java
@@ -33,4 +33,8 @@ public interface AfterEvaluateDecisionTableEvent extends
DMNEvent {
List<Integer> getMatches();
List<Integer> getSelected();
+
+ List<String> getMatchesIds();
+
+ List<String> getSelectedIds();
}
diff --git
a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
index afa8009e4d..93fe8a412e 100644
---
a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
+++
b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java
@@ -106,7 +106,11 @@ public class JSR223DTExpressionEvaluator implements
DMNExpressionEvaluator {
LOG.debug("failed evaluate", e);
throw new RuntimeException(e);
} finally {
- DMNRuntimeEventManagerUtils.fireAfterEvaluateDecisionTable( dmrem,
node.getName(), node.getName(), dt.getId(), result, (r != null ? r.matchedRules
: null), (r != null ? r.fired : null) );
+ DMNRuntimeEventManagerUtils.fireAfterEvaluateDecisionTable( dmrem,
node.getName(), node.getName(), dt.getId(), result,
+ (r !=
null ? r.matchedRules : null),
+ (r !=
null ? r.fired : null),
+ (r !=
null ? r.matchedIds : null),
+ (r !=
null ? r.firedIds : null));
}
}
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
index 8293f82e67..4b1cc02daf 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNDTExpressionEvaluator.java
@@ -103,7 +103,11 @@ public class DMNDTExpressionEvaluator
r = processEvents( events, dmrem, result, node );
return new EvaluatorResultImpl( dtr, r.hasErrors ?
ResultType.FAILURE : ResultType.SUCCESS );
} finally {
- DMNRuntimeEventManagerUtils.fireAfterEvaluateDecisionTable( dmrem,
node.getName(), dt.getName(), dtNodeId, result, (r != null ? r.matchedRules :
null), (r != null ? r.fired : null) );
+ DMNRuntimeEventManagerUtils.fireAfterEvaluateDecisionTable( dmrem,
node.getName(), dt.getName(), dtNodeId, result,
+ (r !=
null ? r.matchedRules : null),
+ (r !=
null ? r.fired : null),
+ (r !=
null ? r.matchedIds : null),
+ (r !=
null ? r.firedIds : null));
}
}
@@ -112,8 +116,10 @@ public class DMNDTExpressionEvaluator
for ( FEELEvent e : events ) {
if ( e instanceof DecisionTableRulesMatchedEvent ) {
r.matchedRules = ((DecisionTableRulesMatchedEvent)
e).getMatches();
+ r.matchedIds = ((DecisionTableRulesMatchedEvent)
e).getMatchesIds();
} else if ( e instanceof DecisionTableRulesSelectedEvent ) {
r.fired = ((DecisionTableRulesSelectedEvent) e).getFired();
+ r.firedIds = ((DecisionTableRulesSelectedEvent)
e).getFiredIds();
} else if ( e.getSeverity() == FEELEvent.Severity.ERROR ) {
MsgUtil.reportMessage( logger,
DMNMessage.Severity.ERROR,
@@ -143,6 +149,8 @@ public class DMNDTExpressionEvaluator
public boolean hasErrors = false;
public List<Integer> matchedRules;
public List<Integer> fired;
+ public List<String> matchedIds;
+ public List<String> firedIds;
}
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNEvaluatorCompiler.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNEvaluatorCompiler.java
index 57b4bc8f12..a4e384da78 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNEvaluatorCompiler.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNEvaluatorCompiler.java
@@ -678,7 +678,7 @@ public class DMNEvaluatorCompiler implements
DMNDecisionLogicCompiler {
java.util.List<DTDecisionRule> rules = new ArrayList<>();
index = 0;
for ( DecisionRule dr : dt.getRule() ) {
- DTDecisionRule rule = new DTDecisionRule( index );
+ DTDecisionRule rule = new DTDecisionRule( index, dr.getId() );
for ( int i = 0; i < dr.getInputEntry().size(); i++ ) {
UnaryTests ut = dr.getInputEntry().get(i);
final java.util.List<UnaryTest> tests;
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/DMNAlphaNetworkEvaluatorImpl.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/DMNAlphaNetworkEvaluatorImpl.java
index cbffc8b5c8..3334277049 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/DMNAlphaNetworkEvaluatorImpl.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/DMNAlphaNetworkEvaluatorImpl.java
@@ -111,7 +111,10 @@ public class DMNAlphaNetworkEvaluatorImpl implements
DMNExpressionEvaluator {
} finally {
evalCtx.exitFrame();
DMNRuntimeEventManagerUtils.fireAfterEvaluateDecisionTable(eventManager,
node.getName(), decisionTableName, decisionTableId, dmnResult,
-
(eventResults != null ? eventResults.matchedRules : null), (eventResults !=
null ? eventResults.fired : null));
+
(eventResults != null ? eventResults.matchedRules : null),
+
(eventResults != null ? eventResults.fired : null),
+
(eventResults != null ? eventResults.matchedIds : null),
+
(eventResults != null ? eventResults.firedIds : null));
}
}
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/Results.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/Results.java
index ec7de3836c..ca42e119ae 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/Results.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/alphanetbased/Results.java
@@ -7,7 +7,7 @@
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
@@ -29,9 +29,9 @@ import java.util.stream.Stream;
import org.drools.model.functions.Function1;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule;
import org.kie.dmn.feel.runtime.decisiontables.DecisionTable;
import org.kie.dmn.feel.runtime.decisiontables.HitPolicy;
-import org.kie.dmn.feel.runtime.decisiontables.Indexed;
import org.kie.dmn.feel.runtime.events.DecisionTableRulesMatchedEvent;
import org.kie.dmn.feel.runtime.events.HitPolicyViolationEvent;
@@ -49,7 +49,8 @@ public class Results {
public void addResult(ResultObject resultObject) {
resultGroupedByRow
- .computeIfAbsent(resultObject.row, i -> new
ArrayList<>(1)) // 10 (the default for Java) columns output are not that usual
+ .computeIfAbsent(resultObject.row, i -> new
ArrayList<>(1)) // 10 (the default for Java) columns
+ // output are not that usual
.add(resultObject);
}
@@ -57,8 +58,8 @@ public class Results {
resultGroupedByRow.clear();
}
- List<Indexed> matches() {
- return indexes().map(i -> (Indexed) () -> i).collect(toList());
+ List<DTDecisionRule> matches() {
+ return indexes().map(i -> new DTDecisionRule(i,
null)).collect(toList());
}
private Stream<Integer> indexes() {
@@ -147,25 +148,39 @@ public class Results {
}
events.add(new HitPolicyViolationEvent(
FEELEvent.Severity.WARN,
- String.format("No rule matched for decision table '%s' and
no default values were defined. Setting result to null.",
decisionTable.getName()),
+ String.format("No rule matched for decision table '%s' and
no default values were defined. " +
+ "Setting result to null.",
decisionTable.getName()),
decisionTable.getName(),
Collections.emptyList()));
}
- List<? extends Indexed> matchIndexes = items.matches();
- evaluationContext.notifyEvt( () -> {
- List<Integer> matchedIndexes =
matchIndexes.stream().map( dr -> dr.getIndex() + 1
).collect(Collectors.toList() );
- return new
DecisionTableRulesMatchedEvent(FEELEvent.Severity.INFO,
-
String.format("Rules matched for decision table '%s': %s",
decisionTable.getName(), matchIndexes),
-
decisionTable.getName(),
-
decisionTable.getName(),
-
matchedIndexes );
- }
+ List<DTDecisionRule> matchingDecisionRules = items.matches();
+ evaluationContext.notifyEvt(() -> {
+ List<Integer> matches = new
ArrayList<>();
+ List<String> matchesId = new
ArrayList<>();
+ matchingDecisionRules.forEach(dr -> {
+ matches.add(dr.getIndex() + 1);
+ if (dr.getId() != null &&
!dr.getId().isEmpty()) {
+ matchesId.add(dr.getId());
+ }
+ });
+ return new
DecisionTableRulesMatchedEvent(FEELEvent.Severity.INFO,
+
String.format("Rules matched for " +
+
"decision " +
+
"table '%s': " +
+
"%s",
+
decisionTable.getName(), matchingDecisionRules),
+
decisionTable.getName(),
+
decisionTable.getName(),
+
matches,
+
matchesId);
+ }
);
List<Object> resultObjects = items.evaluateResults(evaluationContext);
- Map<Integer, String> errorMessages =
checkResults(decisionTable.getOutputs(), evaluationContext, matchIndexes,
resultObjects );
+ Map<Integer, String> errorMessages =
checkResults(decisionTable.getOutputs(), evaluationContext,
matchingDecisionRules
+ , resultObjects);
if (!errorMessages.isEmpty()) {
List<Integer> offending = new ArrayList<>(errorMessages.keySet());
events.add(new HitPolicyViolationEvent(
@@ -178,6 +193,6 @@ public class Results {
return null;
}
- return hitPolicy.getDti().dti(evaluationContext, decisionTable,
matchIndexes, resultObjects);
+ return hitPolicy.getDti().dti(evaluationContext, decisionTable,
matchingDecisionRules, resultObjects);
}
}
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/AfterEvaluateDecisionTableEventImpl.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/AfterEvaluateDecisionTableEventImpl.java
index edfb392bc0..76d80fccfb 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/AfterEvaluateDecisionTableEventImpl.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/AfterEvaluateDecisionTableEventImpl.java
@@ -33,14 +33,18 @@ public class AfterEvaluateDecisionTableEventImpl
private final DMNResult result;
private final List<Integer> matches;
private final List<Integer> fired;
+ private final List<String> matchesIds;
+ private final List<String> firedIds;
- public AfterEvaluateDecisionTableEventImpl(String nodeName, String dtName,
String dtId, DMNResult result, List<Integer> matches, List<Integer> fired) {
+ public AfterEvaluateDecisionTableEventImpl(String nodeName, String dtName,
String dtId, DMNResult result, List<Integer> matches, List<Integer> fired,
List<String> matchesIds, List<String> firedIds) {
this.nodeName = nodeName;
this.dtName = dtName;
this.dtId = dtId;
this.result = result;
this.matches = matches;
this.fired = fired;
+ this.matchesIds = matchesIds;
+ this.firedIds = firedIds;
}
@Override
@@ -73,9 +77,18 @@ public class AfterEvaluateDecisionTableEventImpl
return fired == null ? Collections.emptyList() : fired;
}
+ @Override
+ public List<String> getMatchesIds() {
+ return matchesIds == null ? Collections.emptyList() : matchesIds;
+ }
+
+ @Override
+ public List<String> getSelectedIds() {return firedIds == null ?
Collections.emptyList() : firedIds;
+ }
+
@Override
public String toString() {
- return "AfterEvaluateDecisionTableEvent{ nodeName='"+nodeName+"'
decisionTableName='" + dtName + "' matches=" + getMatches() + " fired=" +
getSelected() + " }";
+ return "AfterEvaluateDecisionTableEvent{ nodeName='"+nodeName+"'
decisionTableName='" + dtName + "' matches=" + getMatches() + " fired=" +
getSelected() + "' matchesIds=" + getMatchesIds() + " firedIds=" +
getSelectedIds() + " }";
}
}
diff --git
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeEventManagerUtils.java
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeEventManagerUtils.java
index d4a65088c7..6469590ca8 100644
---
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeEventManagerUtils.java
+++
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeEventManagerUtils.java
@@ -103,9 +103,9 @@ public final class DMNRuntimeEventManagerUtils {
}
}
- public static void fireAfterEvaluateDecisionTable( DMNRuntimeEventManager
eventManager, String nodeName, String dtName, String dtId, DMNResult result,
List<Integer> matches, List<Integer> fired ) {
+ public static void fireAfterEvaluateDecisionTable( DMNRuntimeEventManager
eventManager, String nodeName, String dtName, String dtId, DMNResult result,
List<Integer> matches, List<Integer> fired, List<String> matchedIds,
List<String> firedIds ) {
if( eventManager.hasListeners() ) {
- AfterEvaluateDecisionTableEvent event = new
AfterEvaluateDecisionTableEventImpl(nodeName, dtName, dtId, result, matches,
fired);
+ AfterEvaluateDecisionTableEvent event = new
AfterEvaluateDecisionTableEventImpl(nodeName, dtName, dtId, result, matches,
fired, matchedIds, firedIds);
notifyListeners(eventManager, l ->
l.afterEvaluateDecisionTable(event));
}
}
diff --git
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java
index d89ff7ef4c..5f24586968 100644
---
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java
+++
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java
@@ -42,6 +42,7 @@ import org.kie.dmn.api.core.ast.InputDataNode;
import org.kie.dmn.api.core.ast.ItemDefNode;
import org.kie.dmn.api.core.event.AfterConditionalEvaluationEvent;
import org.kie.dmn.api.core.event.AfterEvaluateConditionalEvent;
+import org.kie.dmn.api.core.event.AfterEvaluateDecisionTableEvent;
import org.kie.dmn.api.core.event.DMNRuntimeEventListener;
import org.kie.dmn.core.api.DMNFactory;
import org.kie.dmn.core.api.event.DefaultDMNRuntimeEventListener;
@@ -384,26 +385,36 @@ public class DMNInputRuntimeTest extends
BaseInterpretedVsCompiledTest {
@ParameterizedTest
@MethodSource("params")
- void conditionalIfCheck(boolean useExecModelCompiler) {
+ void evaluationHitIdsCheck(boolean useExecModelCompiler) {
init(useExecModelCompiler);
final String ifElementId = "_3C702CE4-E5A0-4B6F-905D-C2621FFFA387";
final String thenElementId = "_6481FF12-61B5-451C-B775-4143D9B6CD6B";
final String elseElementId = "_2CD02CB2-6B56-45C4-B461-405E89D45633";
+ final String ruleId0 = "_1578BD9E-2BF9-4BFC-8956-1A736959C937";
+ final String ruleId1 = "_31CD7AA3-A806-4E7E-B512-821F82043620";
+ final String ruleId3 = "_2545E1A8-93D3-4C8A-A0ED-8AD8B10A58F9";
+ final String ruleId4 = "_510A50DA-D5A4-4F06-B0BE-7F8F2AA83740";
final DMNRuntime runtime =
DMNRuntimeUtil.createRuntime("valid_models/DMNv1_5/RiskScore_Simple.dmn",
this.getClass() );
- final List<AfterEvaluateConditionalEvent>
afterEvaluateConditionalEvents = new ArrayList<>();
- final List<AfterConditionalEvaluationEvent>
afterConditionalEvaluationEvents = new ArrayList<>();
+ final List<String> evaluateConditionalIds = new ArrayList<>();
+ final List<String> conditionalEvaluationIds = new ArrayList<>();
+ final List<String> executedRuleIds = new ArrayList<>();
runtime.addListener(new DefaultDMNRuntimeEventListener() {
+ @Override
+ public void
afterConditionalEvaluation(AfterConditionalEvaluationEvent event) {
+ conditionalEvaluationIds.add(event.getExecutedId());
+ }
+
@Override
public void afterEvaluateConditional(AfterEvaluateConditionalEvent
event) {
- afterEvaluateConditionalEvents.add(event);
+ evaluateConditionalIds.add(event.getExecutedId());
}
@Override
- public void
afterConditionalEvaluation(AfterConditionalEvaluationEvent event) {
- afterConditionalEvaluationEvents.add(event);
+ public void
afterEvaluateDecisionTable(AfterEvaluateDecisionTableEvent event) {
+ executedRuleIds.addAll(event.getSelectedIds());
}
});
@@ -419,20 +430,23 @@ public class DMNInputRuntimeTest extends
BaseInterpretedVsCompiledTest {
final DMNResult dmnResult1 = runtime.evaluateAll( dmnModel, ctx1 );
assertThat(dmnResult1.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult1.getMessages())).isFalse();
assertThat( dmnResult1.getContext().get( "Risk Score"
)).isEqualTo(BigDecimal.valueOf(50));
- assertThat(afterEvaluateConditionalEvents).hasSize(1).allMatch(event
-> event.getExecutedId().equals(ifElementId));
- assertThat(afterConditionalEvaluationEvents).hasSize(1).allMatch(event
-> event.getExecutedId().equals(elseElementId));
+ assertThat(evaluateConditionalIds).hasSize(1).allMatch(id ->
id.equals(ifElementId));
+ assertThat(conditionalEvaluationIds).hasSize(1).allMatch(id ->
id.equals(elseElementId));
+ assertThat(executedRuleIds).hasSize(2).contains(ruleId0, ruleId3);
//
- afterEvaluateConditionalEvents.clear();
- afterConditionalEvaluationEvents.clear();
+ evaluateConditionalIds.clear();
+ conditionalEvaluationIds.clear();
+ executedRuleIds.clear();
final DMNContext ctx2 = runtime.newContext();
ctx2.set("Credit Score", "Excellent");
ctx2.set("DTI", 10);
final DMNResult dmnResult2 = runtime.evaluateAll( dmnModel, ctx2 );
assertThat(dmnResult2.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult1.getMessages())).isFalse();
assertThat( dmnResult2.getContext().get( "Risk Score"
)).isEqualTo(BigDecimal.valueOf(20));
- assertThat(afterEvaluateConditionalEvents).hasSize(1).allMatch(event
-> event.getExecutedId().equals(ifElementId));
- assertThat(afterConditionalEvaluationEvents).hasSize(1).allMatch(event
-> event.getExecutedId().equals(thenElementId));
+ assertThat(evaluateConditionalIds).hasSize(1).allMatch(id ->
id.equals(ifElementId));
+ assertThat(conditionalEvaluationIds).hasSize(1).allMatch(id ->
id.equals(thenElementId));
+ assertThat(executedRuleIds).hasSize(2).contains(ruleId1, ruleId4);
}
@ParameterizedTest
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DTDecisionRule.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DTDecisionRule.java
index dd08d9f831..1576c78915 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DTDecisionRule.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DTDecisionRule.java
@@ -52,11 +52,13 @@ th OutputClause.
*/
public class DTDecisionRule implements Indexed {
private int index;
+ private String id;
private List<UnaryTest> inputEntry;
private List<CompiledExpression> outputEntry;
- public DTDecisionRule(int index) {
+ public DTDecisionRule(int index, String id) {
this.index = index;
+ this.id = id;
}
/**
@@ -86,4 +88,8 @@ the output components of this DecisionRule.
public int getIndex() {
return index;
}
+
+ public String getId() {
+ return id;
+ }
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
index 362e110087..27374bcb42 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/DecisionTableImpl.java
@@ -257,12 +257,20 @@ public class DecisionTableImpl implements DecisionTable {
}
}
ctx.notifyEvt( () -> {
- List<Integer> matches = matchingDecisionRules.stream().map( dr ->
dr.getIndex() + 1 ).collect( Collectors.toList() );
+ List<Integer> matches = new ArrayList<>();
+ List<String> matchesId = new ArrayList<>();
+ matchingDecisionRules.forEach(dr -> {
+ matches.add( dr.getIndex() + 1 );
+ if (dr.getId() != null && !dr.getId().isEmpty()) {
+ matchesId.add(dr.getId());
+ }
+ });
return new DecisionTableRulesMatchedEvent(FEELEvent.Severity.INFO,
- "Rules matched for
decision table '" + getName() + "': " + matches.toString(),
+ "Rules matched for
decision table '" + getName() + "': " + matches,
getName(),
getName(),
- matches );
+ matches,
+ matchesId);
}
);
return matchingDecisionRules;
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/HitPolicy.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/HitPolicy.java
index 21acca05f1..53e5f92c0f 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/HitPolicy.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/decisiontables/HitPolicy.java
@@ -7,7 +7,7 @@
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
@@ -43,28 +43,29 @@ import static java.util.stream.Collectors.toSet;
import static java.util.stream.IntStream.range;
public enum HitPolicy {
- UNIQUE( "U", "UNIQUE", HitPolicy::unique, null ),
- FIRST( "F", "FIRST", HitPolicy::first, null ),
- PRIORITY( "P", "PRIORITY", HitPolicy::priority, null ),
- ANY( "A", "ANY", HitPolicy::any, null ),
- COLLECT( "C", "COLLECT", HitPolicy::ruleOrder, Collections.EMPTY_LIST ),
// Collect – return a list of the outputs in arbitrary order
- COLLECT_SUM( "C+", "COLLECT SUM", HitPolicy::sumCollect, null ),
- COLLECT_COUNT( "C#", "COLLECT COUNT", HitPolicy::countCollect,
BigDecimal.ZERO ),
- COLLECT_MIN( "C<", "COLLECT MIN", HitPolicy::minCollect, null ),
- COLLECT_MAX( "C>", "COLLECT MAX", HitPolicy::maxCollect, null ),
- RULE_ORDER( "R", "RULE ORDER", HitPolicy::ruleOrder, null ),
- OUTPUT_ORDER( "O", "OUTPUT ORDER", HitPolicy::outputOrder, null );
-
- private final String shortName;
- private final String longName;
+ UNIQUE("U", "UNIQUE", HitPolicy::unique, null),
+ FIRST("F", "FIRST", HitPolicy::first, null),
+ PRIORITY("P", "PRIORITY", HitPolicy::priority, null),
+ ANY("A", "ANY", HitPolicy::any, null),
+ COLLECT("C", "COLLECT", HitPolicy::ruleOrder, Collections.EMPTY_LIST),
// Collect – return a list of the
+ // outputs in arbitrary order
+ COLLECT_SUM("C+", "COLLECT SUM", HitPolicy::sumCollect, null),
+ COLLECT_COUNT("C#", "COLLECT COUNT", HitPolicy::countCollect,
BigDecimal.ZERO),
+ COLLECT_MIN("C<", "COLLECT MIN", HitPolicy::minCollect, null),
+ COLLECT_MAX("C>", "COLLECT MAX", HitPolicy::maxCollect, null),
+ RULE_ORDER("R", "RULE ORDER", HitPolicy::ruleOrder, null),
+ OUTPUT_ORDER("O", "OUTPUT ORDER", HitPolicy::outputOrder, null);
+
+ private final String shortName;
+ private final String longName;
private final HitPolicyDTI dti;
- private final Object defaultValue;
+ private final Object defaultValue;
HitPolicy(final String shortName, final String longName) {
- this( shortName, longName, HitPolicy::notImplemented, null );
+ this(shortName, longName, HitPolicy::notImplemented, null);
}
- HitPolicy(final String shortName, final String longName, final
HitPolicyDTI dti, Object defaultValue ) {
+ HitPolicy(final String shortName, final String longName, final
HitPolicyDTI dti, Object defaultValue) {
this.shortName = shortName;
this.longName = longName;
this.dti = dti;
@@ -83,16 +84,18 @@ public enum HitPolicy {
return dti;
}
- public Object getDefaultValue() { return defaultValue; }
+ public Object getDefaultValue() {
+ return defaultValue;
+ }
public static HitPolicy fromString(String policy) {
policy = policy.toUpperCase();
- for ( HitPolicy c : HitPolicy.values() ) {
- if ( c.shortName.equals( policy ) || c.longName.equals( policy ) )
{
+ for (HitPolicy c : HitPolicy.values()) {
+ if (c.shortName.equals(policy) || c.longName.equals(policy)) {
return c;
}
}
- throw new IllegalArgumentException( "Unknown hit policy: " + policy );
+ throw new IllegalArgumentException("Unknown hit policy: " + policy);
}
/* ---------------------------------------
@@ -100,19 +103,20 @@ public enum HitPolicy {
--------------------------------------- */
@FunctionalInterface
public interface HitPolicyDTI {
+
Object dti(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results);
}
public static Object notImplemented(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- throw new RuntimeException( "Not implemented" );
+ throw new RuntimeException("Not implemented");
}
/**
@@ -121,57 +125,40 @@ public enum HitPolicy {
public static Object unique(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- if ( matches.size() > 1 ) {
- ctx.notifyEvt( () -> {
- List<Integer> ruleMatches =
matches.stream().map( m -> m.getIndex() + 1 ).collect( toList() );
- return new HitPolicyViolationEvent(
- FEELEvent.Severity.ERROR,
- "UNIQUE hit policy decision
tables can only have one matching rule. " +
- "Multiple matches found for
decision table '" + dt.getName() + "'. Matched rules: " + ruleMatches,
- dt.getName(),
- ruleMatches );
- }
+ if (matches.size() > 1) {
+ ctx.notifyEvt(() -> {
+ List<Integer> ruleMatches =
matches.stream().map(m -> m.getIndex() + 1).collect(toList());
+ return new HitPolicyViolationEvent(
+ FEELEvent.Severity.ERROR,
+ "UNIQUE hit policy decision tables can
only have one matching rule. " +
+ "Multiple matches found for
decision table '" + dt.getName() + "'. " +
+ "Matched rules: " + ruleMatches,
+ dt.getName(),
+ ruleMatches);
+ }
);
return null;
}
- if ( matches.size() == 1 ) {
- ctx.notifyEvt( () -> {
- int index = matches.get( 0 ).getIndex()
+ 1;
- return new
DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rule fired for decision table
'" + dt.getName() + "': " + index,
- dt.getName(),
- dt.getName(),
- Collections.singletonList(
index ) );
- }
- );
- return results.get( 0 );
+ if (matches.size() == 1) {
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, matches);
+ return results.get(0);
}
return null;
}
/**
- * First – return the first match in rule order
+ * First – return the first match in rule order
*/
public static Object first(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- if ( matches.size() >= 1 ) {
- ctx.notifyEvt( () -> {
- int index = matches.get( 0 ).getIndex()
+ 1;
- return new
DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rule fired for decision table
'" + dt.getName() + "': " + index,
- dt.getName(),
- dt.getName(),
- Collections.singletonList(
index ) );
- }
- );
- return results.get( 0 );
+ if (!matches.isEmpty()) {
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, matches);
+ return results.get(0);
}
return null;
}
@@ -182,174 +169,87 @@ public enum HitPolicy {
public static Object any(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- if ( matches.size() >= 1 ) {
+ if (!matches.isEmpty()) {
long distinctOutputEntry = results.stream()
.distinct()
.count();
- if ( distinctOutputEntry > 1 ) {
- ctx.notifyEvt( () -> {
- List<Integer> ruleMatches =
matches.stream().map( m -> m.getIndex() + 1 ).collect( toList() );
- return new HitPolicyViolationEvent(
- FEELEvent.Severity.ERROR,
- "'Multiple rules can match,
but they [must] all have the same output '" + dt.getName() + "'. Matched
rules: " + ruleMatches,
- dt.getName(),
- ruleMatches );
- }
+ if (distinctOutputEntry > 1) {
+ ctx.notifyEvt(() -> {
+ List<Integer> ruleMatches =
+ matches.stream().map(m ->
m.getIndex() + 1).collect(toList());
+ return new HitPolicyViolationEvent(
+ FEELEvent.Severity.ERROR,
+ "'Multiple rules can match, but they
[must] all have the same output '" + dt.getName() + "'. Matched rules: " +
ruleMatches,
+ dt.getName(),
+ ruleMatches);
+ }
);
return null;
}
-
- ctx.notifyEvt( () -> {
- int index = matches.get( 0 ).getIndex()
+ 1;
- return new
DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rule fired for decision table
'" + dt.getName() + "': " + index,
- dt.getName(),
- dt.getName(),
- Collections.singletonList(
index ) );
- }
- );
- return results.get( 0 );
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, matches);
+ return results.get(0);
}
return null;
}
/**
- * Priority – multiple rules can match, with different outputs. The output
that comes first in the supplied output values list is returned
+ * Priority – multiple rules can match, with different outputs. The output
that comes first in the supplied
+ * output values list is returned
*/
public static Object priority(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- if ( matches.isEmpty() ) {
+ if (matches.isEmpty()) {
return null;
}
- List<Pair<? extends Indexed, Object>> pairs = sortPairs( ctx, dt,
matches, results );
- ctx.notifyEvt( () -> {
- List<Integer> indexes =
Collections.singletonList( pairs.get( 0 ).getLeft().getIndex() + 1 );
- return new DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rules fired for decision table '"
+ dt.getName() + "': " + indexes,
- dt.getName(),
- dt.getName(),
- indexes );
- }
- );
-
- return pairs.get( 0 ).getRight();
+ List<Pair<DTDecisionRule, Object>> pairs = sortPairs(ctx, dt, matches,
results);
+ int index = pairs.get(0).getLeft().getIndex() + 1;
+ String id = pairs.get(0).getLeft().getId();
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, index, id);
+ return pairs.get(0).getRight();
}
/**
- * Output order – return a list of outputs in the order of the output
values list
+ * Output order – return a list of outputs in the order of the output
values list
*/
public static Object outputOrder(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
- List<Object> results ) {
- if ( matches.isEmpty() ) {
+ List<DTDecisionRule> matches,
+ List<Object> results) {
+ if (matches.isEmpty()) {
return null;
}
- List<Pair<? extends Indexed, Object>> pairs = sortPairs( ctx, dt,
matches, results );
- ctx.notifyEvt( () -> {
- List<Integer> indexes = pairs.stream().map(
p -> p.getLeft().getIndex() + 1 ).collect( toList() );
- return new DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rules fired for decision table '"
+ dt.getName() + "': " + indexes,
- dt.getName(),
- dt.getName(),
- indexes );
- }
- );
-
- return pairs.stream().map( p -> p.getRight() ).collect(
Collectors.toList() );
- }
-
- private static List<Pair<? extends Indexed, Object>> sortPairs(
EvaluationContext ctx, DecisionTable dt, List<? extends Indexed> matches,
List<Object> results) {
- List<Pair<? extends Indexed,Object>> pairs = new ArrayList<>( );
- for( int i = 0; i < matches.size(); i++ ) {
- pairs.add( new Pair<>( matches.get( i ), results.get( i ) ) );
- }
-
- if ( dt.getOutputs().size() == 1 && !dt.getOutputs().get( 0
).getOutputValues().isEmpty() ) {
- // single output, just sort the results
- List<UnaryTest> outs = dt.getOutputs().get( 0 ).getOutputValues();
- pairs.sort( (r1, r2) -> {
- return sortByOutputsOrder( ctx, outs, r1.getRight(),
r2.getRight() );
- } );
- } else if ( dt.getOutputs().size() > 1 ) {
- // multiple outputs, collect the ones that have values listed
- List<? extends DecisionTable.OutputClause> priorities =
dt.getOutputs().stream().filter( o -> !o.getOutputValues().isEmpty() ).collect(
toList() );
- pairs.sort( (r1, r2) -> {
- Map<String, Object> m1 = (Map<String, Object>) r1.getRight();
- Map<String, Object> m2 = (Map<String, Object>) r2.getRight();
- for ( DecisionTable.OutputClause oc : priorities ) {
- int o = sortByOutputsOrder( ctx, oc.getOutputValues(),
m1.get( oc.getName() ), m2.get( oc.getName() ) );
- if ( o != 0 ) {
- return o;
- }
- }
- // unable to sort, so keep order
- return 0;
- } );
- }
- return pairs;
- }
-
- private static int sortByOutputsOrder(EvaluationContext ctx,
List<UnaryTest> outs, Object r1, Object r2) {
- boolean r1found = false;
- boolean r2found = false;
- for( int index = 0; index < outs.size() && !r1found && !r2found;
index++ ) {
- UnaryTest ut = outs.get( index );
- if( ut.apply( ctx, r1 ) ) {
- r1found = true;
- }
- if( ut.apply( ctx, r2 ) ) {
- r2found = true;
- }
+ List<Pair<DTDecisionRule, Object>> pairs = sortPairs(ctx, dt, matches,
results);
+ int index = pairs.get(0).getLeft().getIndex() + 1;
+ String id = pairs.get(0).getLeft().getId();
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, index, id);
- }
- if ( r1found && r2found ) {
- return 0;
- } else if ( r1found ) {
- return -1;
- } else if ( r2found ) {
- return 1;
- } else {
- return 0;
- }
+ return pairs.stream().map(Pair::getRight).collect(Collectors.toList());
}
/**
* Rule order – return a list of outputs in rule order
- * Collect – return a list of the outputs in arbitrary order
+ * Collect – return a list of the outputs in arbitrary order
*/
public static Object ruleOrder(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- if ( matches.isEmpty() ) {
+ if (matches.isEmpty()) {
return null;
}
- ctx.notifyEvt( () -> {
- List<Integer> indexes =
matches.stream().map( m -> m.getIndex() + 1 ).collect( toList() );
- return new DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rules fired for decision table '"
+ dt.getName() + "': " + indexes,
- dt.getName(),
- dt.getName(),
- indexes );
- }
- );
+ notifyDecisionTableRulesSelectedEventWithList(ctx, dt, matches);
return results;
}
public static <T> Collector<T, ?, Object> singleValueOrContext(List<?
extends DecisionTable.OutputClause> outputs) {
- return new SingleValueOrContextCollector<>( outputs.stream().map(
DecisionTable.OutputClause::getName ).collect( toList() ) );
+ return new
SingleValueOrContextCollector<>(outputs.stream().map(DecisionTable.OutputClause::getName).collect(toList()));
}
public static Object generalizedCollect(
@@ -358,16 +258,17 @@ public enum HitPolicy {
List<?> results,
Function<Stream<Object>, Object> resultCollector) {
final List<Map<String, Object>> raw;
- final List<String> names = dt.getOutputs().stream().map( o ->
o.getName() != null ? o.getName() : dt.getName() ).collect( toList() );
- if ( names.size() > 1 ) {
+ final List<String> names =
+ dt.getOutputs().stream().map(o -> o.getName() != null ?
o.getName() : dt.getName()).collect(toList());
+ if (names.size() > 1) {
raw = (List<Map<String, Object>>) results;
} else {
- raw = results.stream().map( (Object r) ->
Collections.singletonMap( names.get( 0 ), r ) ).collect( toList() );
+ raw = results.stream().map((Object r) ->
Collections.singletonMap(names.get(0), r)).collect(toList());
}
- return range( 0, names.size() )
- .mapToObj( index -> names.get( index ) )
- .map( name -> resultCollector.apply( raw.stream().map( r ->
r.get( name ) ) ) )
- .collect( singleValueOrContext( dt.getOutputs() ) );
+ return range(0, names.size())
+ .mapToObj(index -> names.get(index))
+ .map(name -> resultCollector.apply(raw.stream().map(r ->
r.get(name))))
+ .collect(singleValueOrContext(dt.getOutputs()));
}
/**
@@ -376,23 +277,14 @@ public enum HitPolicy {
public static Object countCollect(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- ctx.notifyEvt( () -> {
- List<Integer> indexes =
matches.stream().map( m -> m.getIndex() + 1 ).collect( toList() );
- return new DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rules fired for decision table '"
+ dt.getName() + "': " + indexes,
- dt.getName(),
- dt.getName(),
- indexes );
- }
- );
+ notifyDecisionTableRulesSelectedEventWithList(ctx, dt, matches);
return generalizedCollect(
ctx,
dt,
results,
- x -> new BigDecimal( x.collect( toSet() ).size() ) );
+ x -> new BigDecimal(x.collect(toSet()).size()));
}
/**
@@ -401,24 +293,14 @@ public enum HitPolicy {
public static Object minCollect(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
Object result = generalizedCollect(
ctx,
dt,
results,
- x -> x.map( y -> (Comparable) y ).collect( minBy(
Comparator.naturalOrder() ) ).orElse( null ) );
- ctx.notifyEvt( () -> {
- int resultIdx = results.indexOf( result );
- List<Integer> indexes = resultIdx >= 0 ?
Collections.singletonList( matches.get( resultIdx ).getIndex() + 1 ) :
Collections.emptyList();
- return new DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rules fired for decision table '"
+ dt.getName() + "': " + indexes,
- dt.getName(),
- dt.getName(),
- indexes );
- }
- );
+ x -> x.map(y -> (Comparable)
y).collect(minBy(Comparator.naturalOrder())).orElse(null));
+ notifyDecisionTableRulesSelectedEventByResultIdx(ctx, dt, matches,
results, result);
return result;
}
@@ -428,57 +310,159 @@ public enum HitPolicy {
public static Object maxCollect(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
Object result = generalizedCollect(
ctx,
dt,
results,
- x -> x.map( y -> (Comparable) y ).collect( maxBy(
Comparator.naturalOrder() ) ).orElse( null ) );
- ctx.notifyEvt( () -> {
- int resultIdx = results.indexOf( result );
- List<Integer> indexes = resultIdx >= 0 ?
Collections.singletonList( matches.get( resultIdx ).getIndex() + 1 ) :
Collections.emptyList();
- return new DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rules fired for decision table '"
+ dt.getName() + "': " + indexes,
- dt.getName(),
- dt.getName(),
- indexes );
- }
- );
+ x -> x.map(y -> (Comparable)
y).collect(maxBy(Comparator.naturalOrder())).orElse(null));
+ notifyDecisionTableRulesSelectedEventByResultIdx(ctx, dt, matches,
results, result);
return result;
}
/**
- * C+ – return the sum of the outputs
+ * C+ – return the sum of the outputs
*/
public static Object sumCollect(
EvaluationContext ctx,
DecisionTable dt,
- List<? extends Indexed> matches,
+ List<DTDecisionRule> matches,
List<Object> results) {
- ctx.notifyEvt( () -> {
- List<Integer> indexes =
matches.stream().map( m -> m.getIndex() + 1 ).collect( toList() );
- return new DecisionTableRulesSelectedEvent(
- FEELEvent.Severity.INFO,
- "Rules fired for decision table '"
+ dt.getName() + "': " + indexes,
- dt.getName(),
- dt.getName(),
- indexes );
- }
- );
+ notifyDecisionTableRulesSelectedEventWithList(ctx, dt, matches);
return generalizedCollect(
ctx,
dt,
results,
- x -> x.reduce( BigDecimal.ZERO, (a, b) -> {
- if ( !(a instanceof Number && b instanceof Number) ) {
+ x -> x.reduce(BigDecimal.ZERO, (a, b) -> {
+ if (!(a instanceof Number && b instanceof Number)) {
return null;
} else {
- BigDecimal aB = new BigDecimal( a.toString() );
- BigDecimal bB = new BigDecimal( b.toString() );
- return aB.add( bB );
+ BigDecimal aB = new BigDecimal(a.toString());
+ BigDecimal bB = new BigDecimal(b.toString());
+ return aB.add(bB);
}
- } ) );
+ }));
+ }
+
+ private static void
notifyDecisionTableRulesSelectedEventByResultIdx(EvaluationContext ctx,
+
DecisionTable dt,
+
List<DTDecisionRule> matches,
+
List<Object> results,
+
Object result) {
+ int resultIdx = results.indexOf(result);
+ List<Integer> indexes = resultIdx >= 0 ?
+ Collections.singletonList(matches.get(resultIdx).getIndex() +
1) :
+ Collections.emptyList();
+ List<String> matchesId = resultIdx >= 0 ?
+ Collections.singletonList(matches.get(resultIdx).getId() + 1) :
+ Collections.emptyList();
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, indexes, matchesId);
+ }
+
+ private static void
notifyDecisionTableRulesSelectedEventWithList(EvaluationContext ctx,
+
DecisionTable dt,
+
List<DTDecisionRule> matches) {
+ List<Integer> indexes = new ArrayList<>();
+ List<String> matchesId = new ArrayList<>();
+ matches.forEach(dr -> {
+ indexes.add(dr.getIndex() + 1);
+ if (dr.getId() != null && !dr.getId().isEmpty()) {
+ matchesId.add(dr.getId());
+ }
+ });
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, indexes, matchesId);
+ }
+
+ private static void
notifyDecisionTableRulesSelectedEvent(EvaluationContext ctx,
+ DecisionTable dt,
+
List<DTDecisionRule> matches) {
+ int index = matches.get(0).getIndex() + 1;
+ String id = matches.get(0).getId();
+ notifyDecisionTableRulesSelectedEvent(ctx, dt, index, id);
+ }
+
+ private static void
notifyDecisionTableRulesSelectedEvent(EvaluationContext ctx,
+ DecisionTable dt,
+ int index,
+ String id) {
+ ctx.notifyEvt(() -> new DecisionTableRulesSelectedEvent(
+ FEELEvent.Severity.INFO,
+ "Rule fired for decision table '" + dt.getName() + "': " +
index,
+ dt.getName(),
+ dt.getName(),
+ Collections.singletonList(index),
+ Collections.singletonList(id))
+ );
+ }
+
+ private static void
notifyDecisionTableRulesSelectedEvent(EvaluationContext ctx,
+ DecisionTable dt,
+ List<Integer>
indexes,
+ List<String>
matchesId) {
+ ctx.notifyEvt(() -> new DecisionTableRulesSelectedEvent(
+ FEELEvent.Severity.INFO,
+ "Rules fired for decision table '" + dt.getName() + "': " +
indexes,
+ dt.getName(),
+ dt.getName(),
+ indexes,
+ matchesId)
+ );
+ }
+
+ private static List<Pair<DTDecisionRule, Object>>
sortPairs(EvaluationContext ctx, DecisionTable dt,
+
List<DTDecisionRule> matches, List<Object> results) {
+ List<Pair<DTDecisionRule, Object>> pairs = new ArrayList<>();
+ for (int i = 0; i < matches.size(); i++) {
+ pairs.add(new Pair<>(matches.get(i), results.get(i)));
+ }
+
+ if (dt.getOutputs().size() == 1 &&
!dt.getOutputs().get(0).getOutputValues().isEmpty()) {
+ // single output, just sort the results
+ List<UnaryTest> outs = dt.getOutputs().get(0).getOutputValues();
+ pairs.sort((r1, r2) -> {
+ return sortByOutputsOrder(ctx, outs, r1.getRight(),
r2.getRight());
+ });
+ } else if (dt.getOutputs().size() > 1) {
+ // multiple outputs, collect the ones that have values listed
+ List<? extends DecisionTable.OutputClause> priorities =
+ dt.getOutputs().stream().filter(o ->
!o.getOutputValues().isEmpty()).collect(toList());
+ pairs.sort((r1, r2) -> {
+ Map<String, Object> m1 = (Map<String, Object>) r1.getRight();
+ Map<String, Object> m2 = (Map<String, Object>) r2.getRight();
+ for (DecisionTable.OutputClause oc : priorities) {
+ int o = sortByOutputsOrder(ctx, oc.getOutputValues(),
m1.get(oc.getName()), m2.get(oc.getName()));
+ if (o != 0) {
+ return o;
+ }
+ }
+ // unable to sort, so keep order
+ return 0;
+ });
+ }
+ return pairs;
+ }
+
+ private static int sortByOutputsOrder(EvaluationContext ctx,
List<UnaryTest> outs, Object r1, Object r2) {
+ boolean r1found = false;
+ boolean r2found = false;
+ for (int index = 0; index < outs.size() && !r1found && !r2found;
index++) {
+ UnaryTest ut = outs.get(index);
+ if (ut.apply(ctx, r1)) {
+ r1found = true;
+ }
+ if (ut.apply(ctx, r2)) {
+ r2found = true;
+ }
+ }
+ if (r1found && r2found) {
+ return 0;
+ } else if (r1found) {
+ return -1;
+ } else if (r2found) {
+ return 1;
+ } else {
+ return 0;
+ }
}
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesMatchedEvent.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesMatchedEvent.java
index 60d4ee04f0..45d1dad350 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesMatchedEvent.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesMatchedEvent.java
@@ -32,12 +32,14 @@ public class DecisionTableRulesMatchedEvent
private final String nodeName;
private final String dtName;
private final List<Integer> matches;
+ private final List<String> matchesIds;
- public DecisionTableRulesMatchedEvent(Severity severity, String msg,
String nodeName, String dtName, List<Integer> matches) {
+ public DecisionTableRulesMatchedEvent(Severity severity, String msg,
String nodeName, String dtName, List<Integer> matches, List<String> matchesIds)
{
super( severity, msg, null );
this.nodeName = nodeName;
this.dtName = dtName;
this.matches = matches;
+ this.matchesIds = matchesIds;
}
public String getNodeName() {
@@ -52,6 +54,10 @@ public class DecisionTableRulesMatchedEvent
return matches;
}
+ public List<String> getMatchesIds() {
+ return matchesIds;
+ }
+
@Override
public String toString() {
return "DecisionTableRulesMatchedEvent{" +
@@ -60,6 +66,7 @@ public class DecisionTableRulesMatchedEvent
", nodeName='" + nodeName + '\'' +
", dtName='" + dtName + '\'' +
", matches='" + matches + '\'' +
+ ", matchesIds='" + matchesIds + '\'' +
'}';
}
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesSelectedEvent.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesSelectedEvent.java
index 4adb80d220..c156941983 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesSelectedEvent.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/events/DecisionTableRulesSelectedEvent.java
@@ -40,12 +40,14 @@ public class DecisionTableRulesSelectedEvent
private final String nodeName;
private final String dtName;
private final List<Integer> fired;
+ private final List<String> firedIds;
- public DecisionTableRulesSelectedEvent(Severity severity, String msg,
String nodeName, String dtName, List<Integer> fired) {
+ public DecisionTableRulesSelectedEvent(Severity severity, String msg,
String nodeName, String dtName, List<Integer> fired, List<String> firedIds) {
super( severity, msg, null );
this.nodeName = nodeName;
this.dtName = dtName;
this.fired = fired;
+ this.firedIds = firedIds;
}
public String getNodeName() {
@@ -58,6 +60,10 @@ public class DecisionTableRulesSelectedEvent
return fired;
}
+ public List<String> getFiredIds() {
+ return firedIds;
+ }
+
@Override
public String toString() {
return "DecisionTableRulesMatchedEvent{" +
@@ -66,6 +72,7 @@ public class DecisionTableRulesSelectedEvent
", nodeName='" + nodeName + '\'' +
", dtName='" + dtName + '\'' +
", fired='" + fired + '\'' +
+ ", firedIds='" + firedIds + '\'' +
'}';
}
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java
index 80437477ad..651f334eda 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java
@@ -153,7 +153,7 @@ public class DecisionTableFunction
*/
private static DTDecisionRule toDecisionRule(EvaluationContext mainCtx,
FEEL embeddedFEEL, int index, List<?> rule, int inputSize) {
// TODO should be check indeed block of inputSize n inputs, followed
by block of outputs.
- DTDecisionRule dr = new DTDecisionRule( index );
+ DTDecisionRule dr = new DTDecisionRule( index, null );
for ( int i = 0; i < rule.size(); i++ ) {
Object o = rule.get( i );
if ( i < inputSize ) {
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/forexpressioniterators/ForIterationUtilsTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/forexpressioniterators/ForIterationUtilsTest.java
index 43547f1508..852ed9e205 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/forexpressioniterators/ForIterationUtilsTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/forexpressioniterators/ForIterationUtilsTest.java
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- * <p>
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- * <p>
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateFunctionTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateFunctionTest.java
index db9ece6621..f1462b8d79 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateFunctionTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateFunctionTest.java
@@ -32,7 +32,7 @@ class DateFunctionTest {
@BeforeEach
void setUp() {
- dateFunction = new DateFunction();
+ dateFunction = DateFunction.INSTANCE;
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]