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.