Integrating jBPM3 with Spring (Part 1)

A common requirement I hear a lot is on how to integrate jBPM and Spring. This marriage of jBPM and Spring seems only natural, since both are Pojo-loving frameworks and both are often used in combination with Hibernate.

So, it’s very sad to see that currently there is no library available that allows to easiliy integrate jBPM and Spring. I do know that there exists something such as Springmodules, but using it (unknowingly) in the past has taught me the hard way that it is not usable anymore (it’s based on jBPM 3.1.x, which introduces very difficult and subtle bugs when used with a more recent version).

In this article I’m going to show you how easy it is to integrate jBPM with Spring. I’m going to focus only on jBPM version 3 here (version 3.2.x and 3.3.0 atm), since many people will still (have to) use it for a while until and after jBPM version 4 is released. Luckily, for jBPM 4, Spring integration will be provided out-of-the-box, leveraging the work the work that is done by my good friend Andries Inzé.

The goal of this Spring integration can be split into 3 sections:

  • Interacting with the jBPM engine through the Command service facade
  • Let Spring manage the transactions
  • Using Spring beans in jBPM process definitions (ie injected with other dependencies defined in the Spring container
  • Managing the asynchrounous component of jBPM (ie the JobExecutor) from within the Spring container

Using the CommandService

Traditionally, a call to the jBPM engine follows a fixed pattern:

Jbpmcontext ctx = JbpmConfiguration.openContext();

try {

…. // jBPM code

} catch (JbpmExecption e) {

… //exception handling

} finally {

ctx.close();

}

Since this is cumbersome, the jBPM developers have introduced the CommandService which simply takes a Command (interface) which looks like this:

public interface CommandService {

public Object execute(Command command);

}

The reason why we specifically want to use this service in Spring is that tor Spring-users, this pattern (template – callback) is nothing new if you think about the TransationTemplate, JdbcTemplate, HibernateTemplate, etc.

Let Spring handle the transactions

By default, every call to the jBPM engine (or every Command given to the CommandService in our case) is done in a seperate transaction. This is not how typically Spring transactions work (ie where services are transactional). Since we propably want to pack a couple of jBPM calls into one transaction, we need to do two things.

First, we need to disable the jBPM transactions and use the Hibernate session which is currently bound to the thread. In the jBPM config file (jbpm.cfg.xml) we do following adjustments:

<service name="persistence">
    <factory>
        <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
            <field name="isTransactionEnabled"><false /></field>
            <field name="isCurrentSessionEnabled"><true /></field>
        </bean>
    </factory>
</service>

Secondly, we need to inject the Sessionfactory, which is defined in the Spring container, into the jBPM engine:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
jbpmContext.setSessionFactory(sessionFactory);
jbpmContext.close();

Putting it all together

We can now create the necessary classes to implement the steps as required above:

<bean id="jbpmConfiguration" class="be.jorambarrez.jbpm3_spring_integration.JbpmConfigurationFactoryBean">
    <property name="sessionFactory" ref="sessionFactory" />
    <property name="startJobExecutor" value="false" />
    <property name="springJbpmObjectFactory" ref="springJbpmObjectFactory" />
</bean>

<bean id="springJbpmObjectFactory" class="be.jorambarrez.jbpm3_spring_integration.SpringObjectFactory.java">
    <constructor-arg value="jbpm.cfg.xml" />
</bean>

<bean id="jbpmCommandService" class="org.jbpm.command.impl.CommandServiceImpl">
    <constructor-arg ref="jbpmConfiguration" />
</bean>

Note that we only need 3 classes. The SpringObjectFactory is an implementation of the jBPM ObjectFactory interface. Through this interface, jBPM will retrieve beans that it needs to function. Our implementation implements the ApplicationContextAwara interface to have access to the Spring container. When the jBPM engine needs a specific bean, the Spring container is first consulted, before delegating to the default jBPM object factory. This means that we can define beans used by jBPM in Spring now. The default jBPM object factory uses the jBPM config file to built itself.

The  JbpmConfigurationFactoryBean is a factory bean that produces a singleton JbpmConfiguration (shareable and threadsafe). If you would inspect the source code, you can see that the injected sessionFactory is used to inject the Spring SessionFactory into the jBPM engine. The same is done with the SpringObjectFactory, to replace the default one.
Note that this bean also allows to start up the Job Executor. We will explain in detail the Job executor in the next part of this article, since there are a few complications regarding transactions.

Using Spring beans in a process definition

Since all beans containing business logic are defined in the Spring container, it is only natural to be able to call Spring beans from a JPDL process definition. We have implemented the SpringDelegation class to do this:

<node name="myNode">
    <action class="be.jorambarrez.jbpm3_spring_integration_.SpringDelegation" config-type="bean">
        <beanName>mySpringBeanName</beanName>
    </action>
</node>

In short, you simply need to define the name of the Spring bean you want to use. The SpringDelegation class can be used for any typical jBPM delegation: ActionHandler, DecisionHandler, AssignmentHandler, etc. The SpringDelegations acts as a proxy object by implementing all these jBPM interfaces and delegates to the Spring object when an operation is invoked on the proxy.

Implementation note: I’m not 100% happy with the implementation of the SpringDelegation proxy. It caches the ApplcationContext statically after injection by being ApplicationContextAware. If anyone should know a cleaner solution, please let me know. The downside of this solution is that you must define a bean in Spring, which isn’t injected nowhere (ie the applicationContext must be injected in the static field):

<bean id="springDelegation" class="be.jorambarrez.jbpm3_spring_integration_.SpringDelegation" />

Downloading the sweetness

You can download a jar with the classes described above here.

You can download the source code here. This is a regular Maven project, so contributors don’t hold back.

And please don’t peak too much inside the source code… there is already stuff in there for the next part of this article ;-).
In the second part I will discuss how the jobs and timers integrate into Spring. We’ll see that some special attention is required reagarding the transactions.
In the final part of this article, I will demonstrate how these few classes can be used together with Spring and jBPM3 to build a real-life application. So stay tuned (and subscribe to my rss 😉

UPDATE (25/08): Be sure to also read the excellent posts by MrMagoo on the jBPM forum: http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4250508#4250508

21 Comments

  1. […] – 9:15 am – Joram has started his series on Spring Integration in jBPM3. Be sure to check it out! I’m sure it’ll be the best write-up on the topic and a must read for all who is facing […]

  2. FoX April 21, 2009

    Interesting article! When can we expect part 2?

  3. Joram Barrez April 21, 2009

    I hope to post the second part somewhere at the end of this week. If you can’t wait until then, you can already check out the source which contains already some hints on the job executor…

  4. Stefan April 23, 2009

    Hi Joram,

    I think I’ve found 2 small problems.
    1. The JbpmConfigurationFactoryBean class should have a setSessionFactory method instead of setSessionfactory. (Uppercase F) or the name of the property sessionFactory should be changed.

    2. Now you are using the setObjectFactory method but I think this should be setSpringJbpmObjectFactory

    Is this correct?

  5. Joram Barrez April 23, 2009

    Stefan,

    You’re right, I seem to have forgotten the spring conventions there. I’ll fix it asap.

    But it should compile anyways, you just need to pay attention when injecting.

    Thanks for letting me know!

  6. Peter Pringle May 26, 2009

    Nice to see a clean workaround the shortcomings of the Spring Modules jBPM integration – previously I had been running with a patched up JBPM and Spring Modules solution.

    When’s part II coming along? I’ve had a play with the SpringJobExecutor but am having problems with long lived transactions holding locks on the jBPM JOB table.

  7. shahzad bhatti June 26, 2009

    I have tried follow your directions, but I have been getting
    [junit] java.lang.RuntimeException: org.hibernate.HibernateException: No CurrentSessionContext configured!
    [junit] at com.amazon.jasper.workflow.manager.impl.DefinitionManagerImpl.deployProcessDefinition(DefinitionManagerImpl.java:213)
    [junit] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
    [junit] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
    [junit] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
    [junit] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
    [junit] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    [junit] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    [junit] at $Proxy16.deployProcessDefinition(Unknown Source)
    [junit] at com.amazon.jasper.workflow.manager.impl.DefinitionManagerImplTest.deployProcessDefinition(DefinitionManagerImplTest.java:213)
    [junit] at com.amazon.jasper.workflow.manager.impl.DefinitionManagerImplTest.testCrudOperations(DefinitionManagerImplTest.java:119)
    [junit] at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)
    [junit] Caused by: org.hibernate.HibernateException: No CurrentSessionContext configured!
    [junit] at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:542)
    [junit] at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:105)
    [junit] at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:355)
    [junit] at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:639)
    [junit] at com.amazon.jasper.workflow.manager.impl.DefinitionManagerImpl.deployProcessDefinition(DefinitionManagerImpl.java:208)
    [junit]

    My transaction manager looks like

    true

    and my manager class is defined as

    PROPAGATION_REQUIRED

    Any ideas?

  8. Joram Barrez June 29, 2009

    Can you post you Hibernate TransactionManager config + jBPM config?

    For example did you set: thread

  9. Samuel Sichalles August 12, 2009

    Joram,

    Great post! I’ve been looking everywhere for information on how to integrate jBPM 3.3 with Spring since I’ve run into a lot of issues with jBPM 4 with Spring on Tomcat.

    I can’t wait to try this out.

    In the post, you mention we could expect a follow-up showing how to use the job executor. Are you planning on doing this still or has life gotten in the way?

    I’m very interested in part 2 if you get the time!

  10. Joram Barrez August 13, 2009

    @Samuel: Life and the new job has gotten in the way (ie my time is spent on jBPM4 for the moment).

    What are your issues with jBPM4 and Spring? It’s much easier to use Spring with jBPM4. Have you tried the user forum?

  11. Mr Magoo August 20, 2009

    I have used this as a base in my own project. It was exceptionally helpful, thanks! 🙂
    However I found a few bugs and improved things a bit. (IMO anyway!) Also made the spring config explicit because there are some subtle issues that need to be made explicit to implement this properly.
    http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4250517#4250517

  12. Mr Magoo August 20, 2009

    PS: I tied jbpm4. I loved the new architecture and method. Awesome.

    Unfortunately it did not work. Transaction problems up the waazoo no matter what I tried in the config. (and I tried EVERYTHING) So disappointed because I was always so close.

    From memory it was a case of the job executor requiring one type of transaction config and the core jbpm system requiring another.

    I really think the whole !!MUST HAVE OUR XML FILE OR YOU FAIL!! mentality is letting the project down. The config in general is not that well explained, hard to penetrate and what caused me to waste my time trying to integrate it all.

    I could not penetrate the config to manually set the “command-service”(sp?) config for the executor. It just kept getting its config from the core. Also the docs on spring integration are very brief and not nearly enough.
    Similar to jbpm3 to be honest. Project = awesome. Config = pain. 🙂

  13. Joram Barrez August 20, 2009

    @Mr Magoo: Great to hear that you love the new architecture 🙂

    But I’m sad to hear it doesn’t work for you. Am I right that you are using jBPM4 witg Spring?
    Did you take a look at the example project of Andries Inzé? He has a complete application built with the spring integration:

    see http://code.google.com/p/jbpm4-spring-demo/

  14. Mr Magoo August 20, 2009

    Hi there.

    Yes I did. It always failed when processing timers and other asynchronous jobs. I also tried many variations on it also. (e.g. specifying a separate set of interceptors for the executor)
    Basically the closest I came was having processes start up successfully, but the executor fail to start a JTA transaction on jobs.
    I even debugged the code and followed the execution. It had the spring interceptor and was entering the transaction code, but of course failed to start a new transaction. I think it was around the concept of REQUIRED vs MANDATORY.
    What I wanted was REQUIRED, so it would start one when there was not one but not start a new one otherwise. At one stage I even wrote my own interceptor and injected it manually, but that did not work either.
    After about a week I just had to call it and move on.

  15. Unsavory August 25, 2009

    I’ve had the exact same problems as Mr Magoo. You don’t mention what application server you were using, but I’m guessing it was Tomcat, as am I.

    The problem is with the way the JTA transaction manager is retrieved. jBPM 4 assumes you are running in a J2EE environment such as JBoss and that the transaction manager is bound to a certain jndi name.

    In Tomcat/Spring the transaction manager is looked up via Spring’s transaction manager. NOT via JNDI.

    The solution I came up with was to modify the jBPM source code’s JtaTransaction class. I make the class @Configurable and inject the spring transaction manager into it.

    And then in the 2 methods inside the JtaTransaction class that attempt to retrieve the transaction manager and user transaction from jndi, I use Spring’s transaction manager to do so instead of jndi.

    It works, but I wish there was another way.

  16. Joram Barrez August 25, 2009

    @Sam: My config was tested standalone and on JBoss.

    Do note that jBPM4 is not designed to run on a J2EE container! It is designed as a standalone library, which is embeddable in any application, including a J2EE application.

    Take for example a look at the demo of Andries Inzé: http://www.inze.be/andries/2009/05/16/demo-on-spring-integration-with-jbpm4/
    Here is nowhere a JTA TM used that is bound to JNDI.

    The only place where there is a dependency on JNDI is when using the jBPM console built using the demo.setup task.

  17. Mr Magoo August 26, 2009

    I was actually running on Jboss 5. 🙂

    This is strictly a middleware issue though. As long as you are using spring JTA transactions (J2EE container or 3rd party provided) you will be in the same boat as me.

    I really think the crux of the problem is the different transaction requirements between the executor and the core.

    That is most likely why your solution (a good one BTW) works in that you can inject the correct transaction boundary (propagation=REQUIRE most likely?) and override the default one for JBPM.

    I honestly cannot see how his solution works as I tried that variant and got the same problem I described. He just uses the default executor, but that simply did not work for me.
    Maybe because he uses HSQL? Maybe his test workflows are simpler?

    Cannot say.

  18. Unsavory August 28, 2009

    @Joram: Mr Magoo is correct. jBPM 4 will NOT work with Spring if a JTA transaction manager is used without modifying the way jBPM retrieves the transaction manager.

    IE: Injecting the spring transaction manager into jBPM as I’ve posted above.

    It’s right there in the source. Just by looking at the JtaTransaction class you can see why. =)

  19. Walter Seymore November 17, 2009

    I had the same issue as you guys (Mr. Magoo and Unsavory). I’m running completely standalone (no JBoss or Tomcat). Specifically, this is the error I got:

    org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:339)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:124)
    at org.jbpm.pvm.internal.tx.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:77)
    at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.executeInNewEnvironment(EnvironmentInterceptor.java:53)
    at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)
    at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:55)
    at org.jbpm.pvm.internal.jobexecutor.DispatcherThread.acquireJobs(DispatcherThread.java:126)
    at org.jbpm.pvm.internal.jobexecutor.DispatcherThread.run(DispatcherThread.java:67)

    I fixed it by adding the following to my config:

    <command-service name=”txRequiredCommandService”>
    <retry-interceptor />
    <environment-interceptor />
    <spring-transaction-interceptor />
    </command-service>

    Good luck!

  20. zam0th December 15, 2009

    i’ve also run into the same problem with transactions using jBPM 4.2 with weblogic 10.3…

    we want to use weblogic’s JTA transaction manager (but managed by Spring), so we declare

    jbpm.cfg.xml:

    <spring-transaction-interceptor current=”true” />

    and in spring context:

    <bean id=”workflowTxManager” class=”org.springframework.transaction.jta.WebLogicJtaTransactionManager”>
    <property name=”transactionManagerName” value=”javax.transaction.TransactionManager”/>
    </bean>

    and when i try to deploy the workflow, it tries to run ProcessEngineImpl.checkDb(), which apparently fails with “No existing transaction found for transaction marked with propagation ‘mandatory'”…

    @Unsavory: is there a way to _configure_ jBPM to use a custom transaction interceptor? so that instead of spring-managed one i’d overwrite the existing JtaTransactionInterceptor to look for our specific transaction manager and then reference it somehow in jbpm.cfg.xml… that would be the least painful way to do it i guess…

  21. Blogjam.name March 8, 2014

    If you plan to be a book heroine, this means that you must eat all the time,
    except when you’re not eating, and then you should be thinking about
    eating. “Arsenio was a big hit way back when, he exited prematurely, and aren’t we
    all just plain tired with Jay Leno and Letterman.
    After you do all this, you are ready to start performing in front of
    people for money.

Leave a Reply

Your email address will not be published. Required fields are marked *