Activiti out-of-the-box supports Mule tasks. When Activiti encounters a Mule task, it launches the configured Mule flow. This integration is exactly why my new project uses Mule in the first place. But Activiti also supports execution and task listeners: code that runs in response to an Activiti event. How can I cause Activiti to launch a Mule flow in response to such events?
The short answer is: write a generic Spring bean to launch a Mule flow; then use Activiti’s expression language to call this bean. Example snippet from an Activiti XML configuration file:
<sequenceFlow id='flow1' sourceRef='theStart' targetRef='writeReportTask'> <extensionElements> <activiti:executionListener expression="${cmMuleActivitiListener.sendMessage('vm://activiti-flow', 'Allman Bros. Band', 'bandResults', execution)}"/> </extensionElements> </sequenceFlow>
This snippet causes Activiti to launch the vm://activiti-flow Mule flow when the Activiti workflow transitions from theStart to writeReportTask.Allman Bros. Band is the message payload, and the Mule flow results are placed in the bandResults Activiti flow variable. execution is a reference to the currently executing flow, and allows the Spring beancmMuleActivitiListener to give the Mule flow access to the Activiti flow variables.
The Spring configuration file is very simple:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <description> This Spring configuration file must be loaded into an application context which includes a bean named "cm-mule-client". This cm-mule-client bean must be an org.mule.module.client.MuleClient. </description> <!-- NOTE: bean ids to be used in Activiti expression language must be proper Java identifiers --> <bean id="cmMuleActivitiListener" class="com.armedia.acm.activiti.ActivitiMuleListener"> <property name="realMuleClient" ref="cm-mule-client"/> </bean> </beans>
Please note the description. The project must provide a Spring bean named cm-mule-client.
Finally, the primary method in the Spring Java class is also pretty straightforward:
private void sendMessage(MuleClient mc, String url, Object payload, String resultVariable, DelegateExecution de) throws MuleException { Map<String, Object> messageProps = new HashMap<String, Object>(); setPropertyUnlessNull(messageProps, "activityId", de.getCurrentActivityId()); setPropertyUnlessNull(messageProps, "activityName", de.getCurrentActivityName()); setPropertyUnlessNull(messageProps, "eventName", de.getEventName()); setPropertyUnlessNull(messageProps, "id", de.getId()); setPropertyUnlessNull(messageProps, "parentId", de.getParentId()); setPropertyUnlessNull(messageProps, "processBusinessKey", de.getProcessBusinessKey()); setPropertyUnlessNull(messageProps, "processDefinitionId", de.getProcessDefinitionId()); setPropertyUnlessNull(messageProps, "processVariablesMap", de.getVariables()); setPropertyUnlessNull(messageProps, "processInstanceId", de.getProcessInstanceId()); MuleMessage mm = mc.send(url, payload, messageProps); log.debug("Mule sent back: " + mm.getPayload()); if ( resultVariable != null ) { de.setVariable(resultVariable, mm.getPayload()); } } private void setPropertyUnlessNull( Map<String, Object> map, String key, Object value) { if ( value != null ) { map.put(key, value); } }
This code sends the Mule message and waits for Mule to reply (since we call the Mule client send method). To post the message asynchronously we just need a corresponding method to call the Mule client dispatchmethod.
This small module allows me to configure Activiti to invoke Mule flows in response to Activiti events. And Activiti ships with the ability to invoke Mule flows as automated tasks. So now I have pervasive Mule support in Activiti: wherever Activiti supports executable code, it can call Mule. So happy together!
0 Comments