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]

Reply via email to