Lessons learned from integrating jBPM 4 with Spring
When I was tasked with integrating a process engine into one of my projects, I quickly decided in favor of Activiti. Activiti is the next version of jBPM 4, is compatible with BPMN 2.0, is well documented and has an out-of-the-box module to integrate with Spring. Unfortunately, in a cruel stroke of fate, I was overruled by my hierarchy (because of some petty reason I dare not write here) and I had to use jBPM. This articles tries to list all lessons I learned in this rather epic journey.
Lesson 1: jBPM documentation is not enough
Although jBPM 4 has plenty of available documentation, when you’re faced with the task of starting from scratch, it’s not enough, especially when compared to Activiti’s own documentation. For example, there’s no hint on how to bootstrap jBPM in a Spring context.
Lession 2: it’s not because there’s no documentation that it’s not there
jBPM 4 wraps all needed components to bootstrap jBPM through Spring, even though it stays strangely silent on how to do so. Google is no helper here since everybody seems to have infered its own solution.For the curious, here’s how I finally ended doing it:
For example, here’s how I found some declared the jBPM configuration bean:
<bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.processengine.SpringHelper"> <property name="jbpmCfg"> <value>jbpm.cfg.xml</value> </property> </bean>
At first, I was afraid to use a class in a package which contained the dreaded “internal” word but it seems the only way to do so…
Lesson 3: Google is not really your friend here
… Was it? In fact, I also found this configuration snippet:
<bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration"> <constructor-arg value="jbpm.cfg.xml" /> </bean>
And I think if you search long enough, you’ll find many other ways to achieve engine configuration. That’s the problem when documentation is lacking: we developers are smart people, so we’ll find a way to make it work, no matter what.
Lesson 4: don’t forget to configure the logging framework
This one is not jBPM specific, but it’s important nonetheless. I lost much (really much) time because I foolishly ignored the message warning me about Log4J not finding its configuration file. After having created the damned thing, I finally could read an important piece of information I receveid when programmatically deploying a new jPDL file:
WARNING: no objects were deployed! Check if you have configured a correct deployer in your jbpm.cfg.xml file for the type of deployment you want to do.
Lesson 5: the truth is in the code
This lesson is a direct consequences of the previous one: since I already had double-checked my file had the jbpm.xml extension and that the jBPM deployer was correctly set in my configuration, I had to understand what the code really did. In the end, this meant I had to get the sources and debug in my IDE to watch what happened under the cover. The culprit was the following line:
repositoryService.createDeployment().addResourceFromInputStream("test", new FileInputStream(file));
Since I used a stream on the file, and not the stream itself, I had to supply a fictitious resource name (“test”). The latter was checked for a jpdl.xml file extension and of course, failed miserably. This was however not readily apparent by reading the error message… The fix was the following:
Of course, the referenced file had the correct jbpm.xml extension and it worked like a charm.
Lesson 6: don’t reinvent the wheel
Tightly coupled with lesson 2 and 3, I found many snippets fully describing the jbpm.cfg.xml configuration file. Albeit working (well, I hope so since I didn’t test it), it’s overkill, error-prone and a perhaps sign of too much Google use (vs brain use). For example, the jbpm4-spring-demo project published on Google Code provides a full-fledged configuration file. With a lenghty trial-and-error process, I managed to achieve success with a much shorter configuration file that reused existing configuration snippets:
<?xml version="1.0" encoding="UTF-8"?> <jbpm-configuration xmlns="http://jbpm.org/xsd/cfg"> <import resource="jbpm.default.cfg.xml" /><!-- Default configuration --> <import resource="jbpm.tx.spring.cfg.xml" /><!-- Use Spring transaction management --> <import resource="jbpm.jpdl.cfg.xml" /><!-- Can deploy jPDL files --> </jbpm-configuration>
Lesson 7: jPBM can access the Spring context
jBPM offers the
java activity to call some arbitrary Java code: it can be EJB but we can also wire the Spring context to jBPM so as to make the former accessible by the latter. It’s easily done by modifying the former configuration:
<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg"> <import resource="jbpm.default.cfg.xml" /> <import resource="jbpm.tx.spring.cfg.xml" /> <import resource="jbpm.jpdl.cfg.xml" /> <process-engine-context> <script-manager default-expression-language="juel" default-script-language="juel" read-contexts="execution, environment, process-engine, spring" write-context=""> <script-language name="juel" factory="org.jbpm.pvm.internal.script.JuelScriptEngineFactory" /> </script-manager> </process-engine-context> </jbpm-configuration>
Note that I haven’t found an already existing snippet for this one, feedback welcome.
Lesson 8: use the JTA transaction manager if needed
You’ll probably end having a business database along your jBPM database. In most companies, you’ll be gently asked to put them in different schemas by the DBAs. In this case, don’t forget to use a JTA transaction manager along some XA datasources to use 2-phase commit. In your tests, you’d better use the same schema and a simple transaction manager based on the data source will be enough.
For those of you that need yet another way to configure their jBPM/Spring integration, here are the sources I used in Maven/Eclipse format. I hope my approach is a lot more pragmatic. In all cases, remember I’m a newbie in this product.