Default listener for all tasks (CMMN)

Hi

I was wondering if it’s possible to get flowable to have a generic/default listener for all tasks, without having to wire it in for every single task in the XML configuration - in other words, configuring flowable to fire a listener that can be re-used everywhere but without having to write it in anywhere.

The idea would be to be able to fire off messages to other external services automatically saying “Task X has completed” - being able to do this generically for everything, means we wouldn’t need to be rely on developers to remember

Cheers
Chris

Hi Chris.

Use the same mechanism as is used for processes:
https://www.flowable.org/docs/userguide/index.html#advanced_parseHandlers

You can configure parse handlers in cmmn engine configuration.

Regards
Martin

Hi @martin.grofcik , I’m a colleague of Chris and I was trying to implement this.

By stepping through code, I can see that the configuration is modified by adding my taskParseHandler to the postCmmnParseHandler collection, but the parse() method is never called. Therefore, my listener is not being added.
I’m I doing something wrong, or is there a bug somewhere?

@Configuration
@AutoConfigureAfter(CmmnEngineAutoConfiguration.class)
class FlowableConfigurationConfigurer {

    private static final Logger LOGGER = LoggerFactory.getLogger(FlowableConfigurationConfigurer.class);

    @Autowired
    private TaskListener taskListener;

    @Bean
    @ConditionalOnClass(SpringCmmnEngineConfiguration.class)
    public EngineConfigurationConfigurer<SpringCmmnEngineConfiguration> customizeSpringProcessEngineConfiguration() {
        return processEngineConfiguration -> {
            LOGGER.info("Overriding process engine configuration");

            List<CmmnParseHandler> postCmmnParseHandlers = processEngineConfiguration.getPostCmmnParseHandlers();
            if (Objects.isNull(postCmmnParseHandlers)) {
                postCmmnParseHandlers = new ArrayList<>();
            }
            postCmmnParseHandlers.add(new TaskParseHandler() {
                @Override
                public void parse(CmmnParser cmmnParser, CmmnParseResult cmmnParseResult, BaseElement element) {
                    List<ExtensionElement> extensionElements = element.getExtensionElements().get("taskListener");
                    ExtensionAttribute eventAttribute = new ExtensionAttribute();
                    eventAttribute.setName("event");
                    eventAttribute.setValue("complete");
                    ExtensionAttribute delegateAttribute = new ExtensionAttribute();
                    delegateAttribute.setName("delegateExpression");
                    delegateAttribute.setValue("${basicTaskListener}");

                    ExtensionElement extensionElement = new ExtensionElement();
                    extensionElement.setName("taskListener");
                    extensionElement.addAttribute(delegateAttribute);
                    extensionElement.addAttribute(eventAttribute);
                    extensionElements.add(extensionElement);
                    super.parse(cmmnParser, cmmnParseResult, element);
                }
            });
        };
    }


    private Map<String, List<FlowableEventListener>> addEngineEventListeners() {
        Map<String, List<FlowableEventListener>> typedEventListeners = new HashMap<>();
        typedEventListeners.put(FlowableEngineEventType.TASK_CREATED.name(), List.of(taskListener));
        return typedEventListeners;
    }
}

Thanks.

It looks like you’re only adding a process task parse handler to the engine (also, you’re not setting the list on the engineConfig when it’s null). For CMMN, you’d need a different implementation, injected into the cmmn engine configuration. You can add these through the #setCustomCmmnParseHandlers method.