How to find DecisionTable by name from a drools DMNModel object

97 views Asked by At

I am using RedHat drools DMN capability. I have set up a 'DMNRuntimeEventListener' in order to collect information about the decision table that has just run. In that event listener there is a callback method afterEvaluateDecisionTable which is called. That method receives a AfterEvaluateDecisionTableEvent object. That object does not provide a pointer to the DecisionTable that it just executed.

Instead, that object provides (1) the name of the decision node, and (2) the name of the decision table. This is a little odd because the DecisionTable object does not have a name. It has an id, and a label. But it does not have a getName() method or anything that I can find related to that.

I have the DMNModel object for the model that is being executed. From that, it is easy to find the DecisionNode by name, and the name given works. If the entire decision node is a decision table, then I don't need the decision table name, and everything works fine.

But DMN allows you to nest decision tables with other expression structures, such as a Context object. Context objects can be nested within other Context objects. So the decision node can be an elaborate tree with multiple DecisionTable objects within it. In this case, I need to find the decision table by name.

I can iterate through the tree of children, and occasionally I find objects that are in fact instanceof DecisionTable objects. OK, all I need to do is to find the name of that decision table.

  • getId() returns a GUID and does not match the name given
  • getLabel() returns a null
  • getIdentifierString() returns the same as getId()

I was pointed to this example code for getting a name:

public static String nameOrIDOfTable(DecisionTable sourceDT) {
    if (sourceDT.getOutputLabel() != null && !sourceDT.getOutputLabel().isEmpty()) {
        return sourceDT.getOutputLabel();
    } else if (sourceDT.getParent() instanceof NamedElement) { // DT is decision logic of Decision, and similar cases.
        return ((NamedElement) sourceDT.getParent()).getName();
    } else if (sourceDT.getParent() instanceof FunctionDefinition && sourceDT.getParent().getParent() instanceof NamedElement) { // DT is decision logic of BKM.
        return ((NamedElement) sourceDT.getParent().getParent()).getName();
    } else {
        return new StringBuilder("[ID: ").append(sourceDT.getId()).append("]").toString();
    }
}

  This suggests looking at the following and here at the values that I get:  

  • getOutputLabel() is null
  • parent (ContextEntry) is not a NamedElement and does not have a getName() method
  • parent of the parent (Context) is not a NamedElement and does not have a getName() method

So this method would generate a name for the decision table, but it does not match the name I have been given by the listener. No method provides the name of the decision table (feature request: it would be really nice if the listener callback just provided a link to the DecisionTable object)   So then I start looking into the drools source to figure out how the evaluation code finds the name. What I find is that the name is PASSED IN to the evaluation method, so the name of the decision table depends on the method that calls for evaluation. I would have to analyze all the code that calls for evaluation, in order to determine what this value for decisionTableName means, because it seems to mean different things depending on who is calling for the evaluation.

Can anyone suggest a CORRECT way to find the name of the decision table that will always correspond to the name that the listener callback has provided?

1

There are 1 answers

1
tarilabs On BEST ANSWER

The most appropriate way for your real use-case (correlate AfterEvaluateDecisionTableEvent with the "xml" DecisionTable element) would be to go via element ID.

To locate a DecisionTable in a given DMNModel, you can use something similar to this one-liner:

public static DecisionTable locateDTbyId(DMNModel dmnModel, String id) {
   return dmnModel.getDefinitions()
           .findAllChildren(DecisionTable.class)
           .stream().filter(d -> d.getId().equals(id))
           .findFirst().orElseThrow(IllegalStateException::new);
}

as for the listener events for the Decision Table before/after to be augmented with the decision table ID, PR is submitted, ref https://github.com/kiegroup/drools/pull/4860

This would align, for instance, to ContextEntry event logic as well (there again ID are used).

Thanks for having reported the gap, for feature request you can follow the instruction in https://www.drools.org/community/getHelp.html