Activiti is an open source BPM and workflow system. The first GA release is expected to be out next month i.e. Dec 2010. The roadmap of activiti looks very promising and also involvement of companies like SpringSource and MuleSoft can make it even more interesting. There are couple of good articles and tutorials available on the wiki to help you get started with activiti. To get a feel of the framework, instead of developing a simple hello world app, I thought of integrating activiti with Spring Integration. SpringSource team is working on this integration module and once that is in place some of the boilerplate code from my prototype would be cleaned up. The following blog post demonstrates the use of spring integration mail module with activiti.
Business Process:
For the sake of prototype, I created a defect tracking application. Users can send their complaints to a specific email address e.g. helpdesk@xyz.com. The application polls on helpdesk’s mailbox using spring integration mail module. Once email is received, a defect is created and workflow is initiated to handle this defect.
Running the Demo:
The source code for the prototype is available at google code and github. Checkout the sources. Modify the database and mail configurations in activiti.properties. Run the app using embedded jetty server with mvn jetty:run. Run data.sql to create test users. Send a mail to the address configured in activiti.properties {gmail.username}. All defects are assigned by default to manager user. Login to the app using manager/password. You would see the defect in your task list for review. You can click on the review link, see the details of the defect and assign it to a different user (e.g. developer). Once you assign the defect to a different user, your task list would be empty :-). Now login as developer/password to resolve the defect.
Understanding the Code:
Maven Dependencies:
<!-- ACTIVITI DEPENDENCIES --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-engine</artifactId> <version>${activiti.version}</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring</artifactId> <version>${activiti.version}</version> </dependency>
Wiring it up with Spring:
<!-- Activiti Beans --> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean" p:databaseType="${database}" p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" p:dbSchemaStrategy="${db.schema.strategy}" p:jpaEntityManagerFactory-ref="entityManagerFactory" p:jpaCloseEntityManager="true" p:jpaHandleTransaction="true" /> <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" /> <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" /> <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" /> <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" /> <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
If you take a look at my previous blog post about jBPM, you would clearly see the simplicity in configurations with activiti.
Spring Integration Configurations:
<!-- ========================================================= --> <!-- ===== Spring Integration Setup for Receiving Email Messages ===== --> <!-- ========================================================= --> <util:properties id="javaMailProperties"> <prop key="mail.imap.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop> <prop key="mail.imap.socketFactory.fallback">false</prop> <prop key="mail.store.protocol">imaps</prop> <prop key="mail.debug">false</prop> </util:properties> <int-mail:imap-idle-channel-adapter id="gmailAdapter" store-uri="imaps://${gmail.username}:${gmail.password}@imap.gmail.com:993/inbox" channel="gmailChannel" auto-startup="true" should-delete-messages="false" java-mail-properties="javaMailProperties" /> <int:channel id="gmailChannel" /> <int:service-activator id="messageActivator" input-channel="gmailChannel" ref="gmailMessageActivator" method="process"> </int:service-activator>
Understanding Service Activator and DefectService:
The GmailMessageActivator bean receives the mime message. It extracts the information from the message and calls the DefectService to create the defect. In the current prototype, the process kick off is done in the DefectService. DefectService uses the activiti query API for dealing with tasks and process instances.
@Component("gmailMessageActivator") public class GmailMessageActivator { @Autowired DefectService defectService; @Transactional(readOnly = false) public void process(MimeMessage mimeMessage) throws Exception { try { String[] fromHeaders = mimeMessage.getHeader("From"); String from = ""; if (fromHeaders != null && fromHeaders.length > 0) { from = fromHeaders[0]; } Defect defect = new Defect(); defect.setDescription(mimeMessage.getSubject()); defect.setCreatedBy(from); defect.setAssignedTo("manager"); defectService.createDefect(defect); } catch (MessagingException e) { throw new Exception("Exception occurred during message receiption ", e); } } }
//Note: checkout project for entire source @Autowired private DefectRepository defectRepository; @Autowired private RuntimeService runtimeService; @Autowired private RepositoryService repositoryService; @Autowired private TaskService taskService; @PostConstruct public void setupProcessDefinitions() { try { for (String processDefinition : processDefinitions) { repositoryService.createDeployment() .addInputStream(processDefinition, new ClassPathResource(processDefinition).getInputStream()) .deploy(); } } catch (Exception e) { throw new RuntimeException("An error occured while trying to deploy a process definition", e); } } @Override @Transactional(readOnly = false) public Defect createDefect(Defect defect) { defect.setCreatedDate(new LocalDate()); defect.setStatus(DefectStatus.NEW); Defect newDefect = defectRepository.save(defect); Map<String, Object> vars = new HashMap<String, Object>(); vars.put("defectId", newDefect.getId()); vars.put("assignee", defect.getAssignedTo()); runtimeService.startProcessInstanceByKey(DEFECT_TRACKING_PROCESS_KEY, newDefect.getId().toString(), vars); return defect; }
Understanding BPMN2.0 constructs:
A user task is used to model work that is to be done by human. When process execution arrives at this point in the flow, a new task is created in the user’s task list.
<userTask name="reviewDefect" id="reviewDefect"> <documentation> The assignee will review the defect. </documentation> <humanPerformer> <resourceAssignmentExpression> <formalExpression>#{assignee}</formalExpression> </resourceAssignmentExpression> </humanPerformer> </userTask>
A service task is used to execute some business logic when process execution arrives at a particular point.
<serviceTask id="findAssignee" activiti:class="net.arunoday.activiti.demo.handler.CheckAssignee" />
Conclusion:
In the above blog post, I demonstrated how to setup activiti and use it along with spring integration mail module. The configurations required to setup activiti are pretty simple. To get better understanding of the framework, its wise to quickly read the sources from activiti-engine module. Also, while you run the demo app, check the data in the activiti configuration tables and see how data flows from current tables to history tables after successful execution of the process. This data can be used to generate reports.
It would be interesting to see activiti getting feature rich and then answers to questions like “whether existing jBPM apps should continue with it or consider migrating to activiti?”, “whether new developments should be done with activiti or jBPM?” would come with ease :-)!!
November 23, 2010 at 9:43 am
Wrote a blog post #Activiti 5 with Spring Integration 2.0 Mail Adapter http://blog.aparnachaudhary.net/2010/11/… DZone Link: http://www.dzone.com/links/activiti_5_wi… #bpmn2
November 23, 2010 at 2:53 pm
@aparnachaudhary great post as always. Thanks for share :)
November 23, 2010 at 11:27 pm
hai
this is arun. i want to integrate webservices in spring (jax-ws),jwsdp pack
if u know pls send me a related example how to webservice integrate spring and how to access it.
pls send as soon as possible
November 25, 2010 at 4:58 am
Hi Arun,
You can check Spring-Integration samples available at http://git.springsource.org/spring-integration/samples/trees/master
Aparna
February 8, 2011 at 9:02 pm
Nice blog, very helpful to get started on Activiti. Do we need to create all our application users in activiti database schema?
Lets say we have 1000 users in existing application and we want to use activiti in one of the module to define a workflow. Is it good idea to run the Activiti database in seperate schema or do we need to create activiti schema also in the same application schema.
February 11, 2011 at 10:25 am
@Kris
No. Its not mandatory to create application users in activiti schema. That would be required if you use the IdentityService.
About maintaining a different schema, well its a matter of taste. If your relational model is big, then I personally prefer maintaining a separate schema for application specific objects. But again, its not mandatory, you can also maintain a single schema for application objects and activiti related objects.
March 15, 2011 at 8:38 am
Hey Aparna all the way from NZ!
Thought I’d note that you can also load BPMN XML with your context.xml, instead of programatically in the :
March 15, 2011 at 8:39 am
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"></property>
<property name="transactionManager" ref="transactionManager" />
<property name="databaseSchemaUpdate" value="true" />
<property name="jobExecutorActivate" value="false" />
<property name="deploymentResources" value="classpath*:/bpmn/*.bpmn20.xml" />
</bean>
March 15, 2011 at 9:30 am
@Toolman, Nice to hear from you after a long time. Yes, the resources can be loaded directly in the configurations. Thanks for your comment.
May 13, 2011 at 9:56 pm
Thanks a ton. this is exactly what I was looking for..
May 30, 2011 at 9:08 pm
Thanks. This is was a good post unleasing the dual force of Activity and Spring Integration
June 7, 2011 at 9:26 am
Wow! What a great post! I’m sorry I didn’t see this earlier :-) You’ve done a lot of great things here, and the combination of Spring Integration and Activiti is very formidable. If you have a second, perhaps you could look at the Spring Integration Activiti adapter (in the git.springsource.org/spring-integration sandbox) which is specifically meant to solve some of the problems you’ve solved here. This adapter will be in Spring Integration 2.1. Keep up the great work and be sure to feedback on JIRA or the forums if there’s anything you feel is not being addressed. ;-)
October 19, 2011 at 10:17 pm
Many thanks to Aparna for such a nice post. Josh, Any idea when will Activity adapter make it to 2.1? I dont find it in 2.1.M2. @Josh Long
March 24, 2012 at 4:51 pm
nice and good post, but i try to add a form in start event using activiti:formKey, but the form does not appear
July 10, 2012 at 9:43 am
Hi Aparana
Im Not able to download the source from google code . can you plz help me out.
Thanks
Surender
July 10, 2012 at 2:23 pm
@Surender: The sources are also available on github.
https://github.com/aparnachaudhary/activiti-si-demo
August 6, 2012 at 2:15 pm
Hi all, I have an issue I want to integrate Activiti 5.9 with Servicemix 4.3.0 I found some examples on the internet but I am facing some problems to understand how did they manage to create a new Camel component with is being used to route message to activiti. Could you help?
August 11, 2013 at 5:03 am
Hi Aparna,
Nice post, can you suggest step by step documentation of Activiti, i am already using inhouse workflow engine, but looking at future it would be better to learn such a greate tool.
Dev Pandey
February 21, 2014 at 1:15 pm
Not able to run the application because of invalid pom.xml…
can you please provide the new updated pom.xml
Thanks in advance
August 26, 2015 at 9:51 am
i am new to activiti BPMN Process
can u share step by step instruction, how to integrate with Spring MVC with sample application