Tutorial: call an EJB in a BPMN 2.0 process using Activiti and Spring

Since its conception, Activiti has always had a great integration with Spring. In this tutorial, I’m going to demonstrate how this integration can be leveraged to call an EJB (the approach works for EJB versions 2 or 3) in a BPMN 2.0 process. Whether you like them or not: the fact is that much business logic has been/is being written in EJB’s, but luckily Activiti makes calling an EJB plain, simple and fun.

The environment for this tutorial is as follows:

  • Activiti 5.1
  • Spring 3.something
  • JBoss 5.1.0

The EJB I’ll use for this tutorial is probably the dullest piece of ‘logic’ you’ve ever seen: it does nothing more than transform the given String parameter to uppercase and return it.

@Stateless
public class ToUpperCaseBean implements ToUpperCaseRemote {

  public String toUpperCase(String s) {
    return s.toUpperCase();
  }

}

This EJB session bean is running on the JBoss server (or any other JEE container).

I’m using the default Activiti-Spring integration, so I’m not going to describe the whole spring config here. Suffice to say I have my ProcessEngine configured as a Spring bean:

<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
  <property name="databaseType" value="h2" />
  <property name="dataSource" ref="dataSource" />
  <property name="transactionManager" ref="transactionManager" />
  <property name="databaseSchemaUpdate" value="true" />
  <property name="jobExecutorActivate" value="false" />
</bean>

<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
  <property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>

...

I’m going to run the BPMN 2.0 example process in standard Java environment, so I need to access the EJB through its remote interface. I’m actually going to let Spring do all the hard work, by defining a Spring bean that’ll wrap all the dirty JNDI stuff for me:

<jee:remote-slsb id="toUpperCaseEjbBean" resource-ref="false"
		 business-interface="be.jorambarrez.ejb.ToUpperCaseRemote"
		 jndi-name="ToUpperCaseBean/remote" />

The BPMN 2.0 process in which I’ll call the EJB is again as simple as possible, to make my point. I’m sure you can imagine more awesome scenario’s for it. Here, the process has a start, a call to the EJB, the output of the call (ie the uppercased String) and that’s it.

In BPMN 2.0 XML, this boils down to the following:

<process id="callEjbExample" name="Call EJB example">

    <startEvent id="theStart" />
    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="callEjb" />

    <serviceTask id="callEjb"
                 activiti:expression="${toUpperCaseEjbBean.toUpperCase(var)}"
                 activiti:resultVariableName="var" />
    <sequenceFlow id="flow2" sourceRef="callEjb" targetRef="outputResult" />

    <scriptTask id="outputResult" scriptFormat="groovy">
    	<script>
    		out:println "uppercased version = " + var
    	</script>
    </scriptTask>
    <sequenceFlow id="flow3" sourceRef="outputResult" targetRef="theEnd" />

    <endEvent id="theEnd" />

  </process>

For this tutorial, the serviceTask definition is the most interesting:

<serviceTask id="callEjb"
     activiti:expression="${toUpperCaseEjbBean.toUpperCase(var)}"
     activiti:resultVariableName="var" />

When process execution arrives at the serviceTask, it will execute the toUpperCaseEjbBean.toUpperCase(var) expression. The toUpperCaseEjbBean is actually our wrapped EJB as a Spring bean (see the Spring config above), on which we here invoke the toUpperCase method. This Activiti-Spring-expression integration is pretty cool, right? On the last line, you can see the result of executing the expression is stored in the var variable.

All that is left to do is execute this process on the Activiti engine:

// setup the Spring container and get the Activiti ProcessEngine bean from it
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
ProcessEngine processEngine = context.getBean(ProcessEngine.class);

// Deploy process
processEngine.getRepositoryService().createDeployment()
  .addClasspathResource("callEjbExampleProcess.bpmn20.xml")
  .deploy();

// Run process
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("var", "Activiti, the rock-solid BPM engine");
processEngine.getRuntimeService().startProcessInstanceByKey("callEjbExample", variables);

Which spits out (of course) following console output:

And that’s all there is to it! If you want to try it for yourself, here are the sources, packaged as two Maven projects: one for the ejb and one for running the process.

Without Spring?

If you’ve taken a look at the sources, you’ll notice that getting the dependencies right isn’t trivial. Hell, 99% of my time went to figuring out which libraries I needed and why the hell asm was three times on my classpath with different versions.

In the next months, we’ll be adding a ‘native’ way of calling EJB’s in a BPMN 2.0 process, without having to go through Spring. That way, you’ll just need Activiti and we’ll take care of everything behind the scenes. However, the approach in this tutorial can be used for many other use cases: JMS, webservice calls, some legacy system, etc. Conclusion of this story: If you can wrap it in a Spring bean, you can use it in your BPMN 2.0 process.

7 Comments

  1. […] be leveraged to call an EJB (the approach works for EJB versions 2 or 3) in a BPMN 2.0 process…. [full post] Joram Barrez Small steps with big feet activitialfrescobpmbpmn 0 0 […]

  2. Thorsten February 19, 2011

    Hi Joram,
    great tutorial!
    Do you need the ejb interface in the process engine classpath?
    Can’t wait for the native EJB task. Will it be in release 5.3?

    Best regards
    Thorsten

  3. Joram February 21, 2011

    @Thorsten: Yes, your EJB interface needs to be on the classpath.

    It will (probably) not be in 5.3. 5.4 will be more likely.

  4. Thorsten February 25, 2011

    Is it possible to bind a spring bean dynamically to the service task at runtime? I have the following use case: I want to execute a “generic” service task within a reusable call activity. Depending on who’s calling I want to execute a different bean.

    Best regards!

  5. Joram February 28, 2011

    @Thorsten: Can’t you then just delegate to a Spring bean, pass your process definition key and in that bean do the if-elses and call the right bean?

  6. Richard Gomes May 7, 2011

    Without Spring

    Thank you for addressing this issue.
    I prefer loading preferencies from Properties or Preferences, instead of XML files.

    I prefer keeping dependencies very well managed, at the bare minimum which is absolutely required.
    Spring is definitely contrary to this best practice.

    Thanks a lot :)

  7. MetalliB January 18, 2012

    Thanks for this useful tutorial. Meanwhile the version 5.8 has been released. Is it now possible to call an EJB without Spring?

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>