How to access matching rule details in Camunda DMN in a Spring Boot project?

608 Views Asked by At

My Spring Boot app connects to the Camunda BPMN & DMN. When a user clicks on Approve/Reject button in UI screen, a REST call triggers one BPMN workflow (in Camunda Spring Boot app) which internally triggers a DMN to find the output based on some business rules mapped in DMN input columns. We need to find the exact matching rules details like list of matching rules - input values, output values, matching rule ID, etc.

There are no inbuilt methods present in process engine and dmn engine and hence need to know if there is a way to manually configure such capabilities to the default process engine that comes as part of Spring Boot auto-configuration.

Camunda version: 7.13.0

1

There are 1 best solutions below

0
On

In a Spring Boot app, if we have these dependencies in pom.xml - camunda-bpm-spring-boot-starter, camunda-bpm-spring-boot-starter-webapp, camunda-bpm-spring-boot-starter-rest, a default Process Engine will be auto-configured during the startup of the Spring Boot app. But this Process Engine does not by default enable the Rule details. So we configure a custom Process Engine plugin which will be applied on top of the default Process Engine in order to get the matching rule details every time DMN is hit.

import org.camunda.bpm.spring.boot.starter.annotation.EnableProcessApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableProcessApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

Customize Process Engine:

import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin;
import org.camunda.bpm.spring.boot.starter.configuration.Ordering;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

@Configuration
public class CamundaConfig {

    @Bean
    @Order(Ordering.DEFAULT_ORDER + 1)
    public static ProcessEnginePlugin customProcessEnginePluginConfig() {
        return new CustomProcessEnginePlugin();
    }   
}

Our CustomProcessEnginePlugin will extend AbstractCamundaConfiguration and override postInit() method. This postInit() method adds a DmnDecisionTableEvaluationListener. This listner triggers an event everytime DMN is hit with matching rule and has notify() method with event details which contains all the DMN details like dmnID and matching rules detail.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.camunda.bpm.dmn.engine.delegate.DmnDecisionTableEvaluationEvent;
import org.camunda.bpm.dmn.engine.delegate.DmnDecisionTableEvaluationListener;
import org.camunda.bpm.dmn.engine.delegate.DmnEvaluatedDecisionRule;
import org.camunda.bpm.dmn.engine.delegate.DmnEvaluatedInput;
import org.camunda.bpm.dmn.engine.impl.DefaultDmnEngineConfiguration;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.variable.value.TypedValue;
import org.camunda.bpm.spring.boot.starter.configuration.Ordering;
import org.camunda.bpm.spring.boot.starter.configuration.impl.AbstractCamundaConfiguration;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@Order(Ordering.DEFAULT_ORDER + 1)
public class CustomProcessEnginePlugin extends AbstractCamundaConfiguration {
    @Override
    public void postInit(ProcessEngineConfigurationImpl processEngineConfig) {
        DefaultDmnEngineConfiguration dmnEngineConfig = processEngineConfig.getDmnEngineConfiguration();
        dmnEngineConfig.customPostDecisionTableEvaluationListeners(Collections.singletonList(new DmnDecisionTableEvaluationListener(){

            @Override
            public void notify(DmnDecisionTableEvaluationEvent event) {
                String dmnID = event.getDecisionTable().getKey();
                Map<String, TypedValue> dmnInput = event.getInputs().stream().collect(Collectors.toMap(DmnEvaluatedInput::getName, DmnEvaluatedInput::getValue));
                List<DmnEvaluatedDecisionRule> matchingRuleList = new ArrayList<>();
                matchingRuleList = event.getMatchingRules();
                log.info("DMN ID = {}", dmnID);
                log.info("DMN Input = {}", dmnInput);

                if(null != matchingRuleList) {
                    log.info("DMN Matched Rules = {}", matchingRuleList.size());
                    if(!matchingRuleList.isEmpty()) {
                        for(DmnEvaluatedDecisionRule rule : matchingRuleList) {
                            log.info("DMN Matching Rule ID = {}", rule.getId());
                            log.info("DMN Output = {}", rule.getOutputEntries());
                        }
                    }
                    else {
                        log.info("DMN Output = No matching rule found");
                    }
                }
                log.info("************************************************************************************************");
            }
        }));
        dmnEngineConfig.buildEngine();
        processEngineConfig.setDmnEngineConfiguration(dmnEngineConfig);
    }
}

There is another way to get the matching rule details - by implementing ProcessEnginePlugin and overriding postProcessEngineBuild() and preInit() methods instead of extending AbstractCamundaConfiguration and overriding postInit() method as above.