Search code examples
camundadmn

Camunda: How to get DMN to emit two variable/values to context of BPM workflow?


I want the two output values from DMN row, be sent to BPMN context, e.g DMN.output.var1=val1, DMN.output.var2=val2.

Input: (SPACE=LAW, THING=VANDALISM)

Output: (ROUT_TO_DEPT=BY_LAW, OUT_CATEGORY=INSPECTION)

These two variables must be in context, and available to next step in BPMN.

However I'm getting an error, how to make it happen?

DMN enter image description here

Error

enter image description here

Stacktrace:

Caused by: org.camunda.bpm.engine.ProcessEngineException: ENGINE-22002 The decision result mapper 'CollectEntriesDecisionResultMapper{}' failed to process '[{ROUT_TO_DEPT=Value 'BY_LAW' of type 'PrimitiveValueType[string]', isTransient=false, OUT_CATETORY=Value 'INSPECTION' of type 'PrimitiveValueType[string]', isTransient=false}]'. The decision outputs should only contains values for one output name but found '[ROUT_TO_DEPT, OUT_CATETORY]'.
        at org.camunda.bpm.engine.impl.dmn.DecisionLogger.decisionResultCollectMappingException(DecisionLogger.java:44)
        at org.camunda.bpm.engine.impl.dmn.result.CollectEntriesDecisionResultMapper.mapDecisionResult(CollectEntriesDecisionResultMapper.java:46)
        at org.camunda.bpm.engine.impl.util.DecisionEvaluationUtil.evaluateDecision(DecisionEvaluationUtil.java:79)
        at org.camunda.bpm.engine.impl.bpmn.behavior.DmnBusinessRuleTaskActivityBehavior$1.call(DmnBusinessRuleTaskActivityBehavior.java:56)
        at org.camunda.bpm.engine.impl.bpmn.behavior.DmnBusinessRuleTaskActivityBehavior$1.call(DmnBusinessRuleTaskActivityBehavior.java:53)
        at org.camunda.bpm.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior.executeWithErrorPropagation(AbstractBpmnActivityBehavior.java:90)
        at org.camunda.bpm.engine.impl.bpmn.behavior.DmnBusinessRuleTaskActivityBehavior.execute(DmnBusinessRuleTaskActivityBehavior.java:53)
        at org.camunda.bpm.engine.impl.pvm.runtime.operation.PvmAtomicOperationActivityExecute$2.callback(PvmAtomicOperationActivityExecute.java:61)
        at org.camunda.bpm.engine.impl.pvm.runtime.operation.PvmAtomicOperationActivityExecute$2.callback(PvmAtomicOperationActivityExecute.java:50)
        at org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl.continueIfExecutionDoesNotAffectNextOperation(PvmExecutionImpl.java:1996)
        at org.camunda.bpm.engine.impl.pvm.runtime.operation.PvmAtomicOperationActivityExecute.execute(PvmAtomicOperationActivityExecute.java:42)
        at org.camunda.bpm.engine.impl.pvm.runtime.operation.PvmAtomicOperationActivityExecute.execute(PvmAtomicOperationActivityExecute.java:31)
        at org.camunda.bpm.engine.impl.interceptor.AtomicOperationInvocation.execute(AtomicOperationInvocation.java:96)
        at org.camunda.bpm.engine.impl.interceptor.CommandInvocationContext.invokeNext(CommandInvocationContext.java:128)

I tried to make it as resultList variable, however what I wanted is two output variables - a tuple.

enter image description here

enter image description here

Edit 1: If I choose "singleResult" option, I'm able to get it as a map in one single variable, however I want TWO varibles going to next STEP in a BPMN flow.

enter image description here

enter image description here


Solution

  • The mapping to resultList is used to map a list of rows with multiple output columns. Switching to singleResult was the right direction. You are using a hit policy "First" (one rule/ row only), so the map decision result property can only be singleEntry (one output column) or singleResult (several output columns).

    After mapping the decision result to a singleResult, you can use the Input/Output tab in the property panel to map the result entries to process variables: enter image description here

    In the text field of the output mapping you can use unified expression language, e.g. ${deptRoureDetail.get('ROUT_TO_DEPT')}

    to access the result variable (in your case deptRoutDetail) of type Map and access the desired fields (ROUT_TO_DEPT, etc) by their keys.

    Full example:

    a) BPMN

    <?xml version="1.0" encoding="UTF-8"?>
    <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_17ij5vv" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.5.0">
      <bpmn:process id="Process_TwoOutputs" name="Two Outputs" isExecutable="true">
        <bpmn:startEvent id="StartEvent_1">
          <bpmn:extensionElements>
            <camunda:formData>
              <camunda:formField id="customer" label="Customer" type="string" defaultValue="Miller" />
            </camunda:formData>
          </bpmn:extensionElements>
          <bpmn:outgoing>SequenceFlow_1uzzene</bpmn:outgoing>
        </bpmn:startEvent>
        <bpmn:sequenceFlow id="SequenceFlow_1uzzene" sourceRef="StartEvent_1" targetRef="Task_EvaluteRules" />
        <bpmn:businessRuleTask id="Task_EvaluteRules" name="Evalute Rules" camunda:resultVariable="result" camunda:decisionRef="Decision_twoOutputs" camunda:mapDecisionResult="singleResult">
          <bpmn:extensionElements>
            <camunda:inputOutput>
              <camunda:outputParameter name="blacklisted">${result.get('blacklistedCustomer')}</camunda:outputParameter>
              <camunda:outputParameter name="pep">${result.get('pepCustomer')}</camunda:outputParameter>
            </camunda:inputOutput>
          </bpmn:extensionElements>
          <bpmn:incoming>SequenceFlow_1uzzene</bpmn:incoming>
          <bpmn:outgoing>SequenceFlow_10pcdah</bpmn:outgoing>
        </bpmn:businessRuleTask>
        <bpmn:sequenceFlow id="SequenceFlow_10pcdah" sourceRef="Task_EvaluteRules" targetRef="Task_00rrqy1" />
        <bpmn:endEvent id="EndEvent_0f61xh5">
          <bpmn:incoming>SequenceFlow_1fsnixe</bpmn:incoming>
        </bpmn:endEvent>
        <bpmn:sequenceFlow id="SequenceFlow_1fsnixe" sourceRef="Task_00rrqy1" targetRef="EndEvent_0f61xh5" />
        <bpmn:scriptTask id="Task_00rrqy1" name="Print both variables" scriptFormat="javascript">
          <bpmn:incoming>SequenceFlow_10pcdah</bpmn:incoming>
          <bpmn:outgoing>SequenceFlow_1fsnixe</bpmn:outgoing>
          <bpmn:script>print("blacklisted: " + blacklisted);
    print("pep: " + pep);</bpmn:script>
        </bpmn:scriptTask>
      </bpmn:process>
      <bpmndi:BPMNDiagram id="BPMNDiagram_1">
        <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_TwoOutputs">
          <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
            <dc:Bounds x="179" y="99" width="36" height="36" />
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge id="SequenceFlow_1uzzene_di" bpmnElement="SequenceFlow_1uzzene">
            <di:waypoint x="215" y="117" />
            <di:waypoint x="270" y="117" />
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNShape id="BusinessRuleTask_1oc25xp_di" bpmnElement="Task_EvaluteRules">
            <dc:Bounds x="270" y="77" width="100" height="80" />
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge id="SequenceFlow_10pcdah_di" bpmnElement="SequenceFlow_10pcdah">
            <di:waypoint x="370" y="117" />
            <di:waypoint x="430" y="117" />
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNShape id="EndEvent_0f61xh5_di" bpmnElement="EndEvent_0f61xh5">
            <dc:Bounds x="592" y="99" width="36" height="36" />
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge id="SequenceFlow_1fsnixe_di" bpmnElement="SequenceFlow_1fsnixe">
            <di:waypoint x="530" y="117" />
            <di:waypoint x="592" y="117" />
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNShape id="ScriptTask_1xt3142_di" bpmnElement="Task_00rrqy1">
            <dc:Bounds x="430" y="77" width="100" height="80" />
          </bpmndi:BPMNShape>
        </bpmndi:BPMNPlane>
      </bpmndi:BPMNDiagram>
    </bpmn:definitions>
    

    b) DMN

    <?xml version="1.0" encoding="UTF-8"?>
    <definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_0cib9be" name="DRD" namespace="http://camunda.org/schema/1.0/dmn" exporter="Camunda Modeler" exporterVersion="3.5.0">
      <decision id="Decision_twoOutputs" name="Two Outputs">
        <extensionElements>
          <biodi:bounds x="150" y="150" width="180" height="80" />
        </extensionElements>
        <decisionTable id="decisionTable_1">
          <input id="input_1" label="Customer Name">
            <inputExpression id="inputExpression_1" typeRef="string">
              <text>customer</text>
            </inputExpression>
          </input>
          <output id="output_1" label="blacklisted" name="blacklistedCustomer" typeRef="string" />
          <output id="OutputClause_18xxjii" label="Politically Exposed Person" name="pepCustomer" typeRef="boolean" />
          <rule id="DecisionRule_0qg0ni4">
            <inputEntry id="UnaryTests_1i6rkew">
              <text>"Miller"</text>
            </inputEntry>
            <outputEntry id="LiteralExpression_12xbrsq">
              <text>"clear"</text>
            </outputEntry>
            <outputEntry id="LiteralExpression_1obxdmm">
              <text>false</text>
            </outputEntry>
          </rule>
          <rule id="DecisionRule_06aolv9">
            <inputEntry id="UnaryTests_0oeomwy">
              <text>"Smith"</text>
            </inputEntry>
            <outputEntry id="LiteralExpression_1xobooq">
              <text>"clear"</text>
            </outputEntry>
            <outputEntry id="LiteralExpression_0sok0z4">
              <text>true</text>
            </outputEntry>
          </rule>
          <rule id="DecisionRule_0ki09vh">
            <inputEntry id="UnaryTests_096b0z2">
              <text>"Jones"</text>
            </inputEntry>
            <outputEntry id="LiteralExpression_11x7v5h">
              <text>"blacklisted"</text>
            </outputEntry>
            <outputEntry id="LiteralExpression_1nit6ye">
              <text>false</text>
            </outputEntry>
          </rule>
          <rule id="DecisionRule_0tifgq8">
            <inputEntry id="UnaryTests_0fqbez3">
              <text>"Doe"</text>
            </inputEntry>
            <outputEntry id="LiteralExpression_0yghulu">
              <text>"blacklisted"</text>
            </outputEntry>
            <outputEntry id="LiteralExpression_1j2jmlj">
              <text>true</text>
            </outputEntry>
          </rule>
        </decisionTable>
      </decision>
    </definitions>
    

    c) jUnit Test

    import org.camunda.bpm.dmn.engine.DmnDecisionTableResult;
    import org.camunda.bpm.engine.runtime.ProcessInstance;
    import org.camunda.bpm.engine.test.Deployment;
    import org.camunda.bpm.engine.test.ProcessEngineRule;
    import org.camunda.bpm.engine.variable.Variables;
    import org.junit.Before;
    import org.junit.Rule;
    import org.junit.Test;
    
    import java.util.Map;
    
    import static org.assertj.core.api.Assertions.assertThat;
    import static org.assertj.core.api.Assertions.entry;
    import static org.camunda.bpm.engine.test.assertions.ProcessEngineTests.init;
    import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.decisionService;
    
    public class DMNUnitTest {
    
        @Rule
        public ProcessEngineRule rule = new ProcessEngineRule();
    
        @Before
        public void setup() {
            init(rule.getProcessEngine());
        }
    
        @Test
        @Deployment(resources = {"twoOutputs.dmn"})
        public void testNoFlags() {
            Map<String, Object> variables = Variables.createVariables().putValue("customer", "Miller");
            DmnDecisionTableResult results = decisionService().evaluateDecisionTableByKey("Decision_twoOutputs", variables);
            assertThat(results).hasSize(1);
            assertThat(results.getSingleResult())
                    .contains(entry("blacklistedCustomer", "clear"))
                    .contains(entry("pepCustomer", false));
        }
    
        @Test
        @Deployment(resources = {"twoOutputs.dmn", "twoOutputs.bpmn"})
        public void testProcessWithtwoDecisionOutputs() {
            Map<String, Object> variables = Variables.createVariables().putValue("customer", "Miller");
            ProcessInstance pi =  rule.getRuntimeService().startProcessInstanceByKey("Process_TwoOutputs", variables);
            org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.assertThat(pi).hasVariables("blacklisted","pep");
    
        }
    }