Archive

Archive for April, 2012

JPA 2 with Drools and jBPM

3 April 2012 3 comments

At the moment, I’m finishing off making Drools/jBPM ready to be able use JPA 2 and Hibernate 4.x. This post is in some sense a draft for the official documentation, but again, see about for why I write blog posts.

 


Using jBPM with JPA 2

 

If you’re reading this, it’ll be because you want to use Drools or jBPM with JPA 2 and maybe even with a different ORM framework. Awesome! That means you’re using jBPM and that you’re using jBPM the way you want to and are not being forced by the software to make choices you don’t want to. I heartily approve of both.

First off, if you’re using JPA 2 with drools and JBPM, you’ll need to change the all the instances of "1.0" and ..._1_0.xsd to "2.0" and ..._2_0.xsd. Don’t forget those schemaLocation values that are off beyond the right edge of your screen.

Second off, you’ll have to modify your persistence.xml and change the mapping for the ProcessInstanceInfo class. In your persistence.xml, you’ll have to remove the following line:

  <mapping-file>META-INF/ProcessInstanceInfo.hbm.xml</mapping-file>

Once that’s done, you’ll have to add a JPA2 mapping for that class to your persistence unit. If you want to, you can just change the following line in your persistence.xml:

  <mapping-file>META-INF/JBPMorm.xml</mapping-file>

to

  <mapping-file>META-INF/JBPMorm-JPA2.xml</mapping-file>

The JBPMorm-JPA2.xml file is included with the jbpm-persistence-jpa jar: if you’re curious about the entity mapping, you can find it there.

Lastly, depending on your setup, you might have to change the TransactionManagerLookup class that you’re using. This line:

<property name=”hibernate.transaction.manager_lookup_class” value=”org.hibernate.transaction.BTMTransactionManagerLookup” />

needs to be changed to:

<property name=”hibernate.transaction.jta.platform” value=”org.hibernate.service.jta.platform.internal.BitronixJtaPlatform” />

And that’s it!


Developer bits and ranting

 

The following is mostly explaining how I got to the solution that I did get to. :)

In any case, regarding enabling and testing the JPA 2 functionality in Drools/jBPM and to start with: there are XML metadata overrides. I’ve known about XML overrides for persistence annotation data for a while, but while I’ve almost used them to solve a some problems, it never really happened. Part of this has to do with the fact that the configuration for jBPM is still evolving.

In the past year, the persistence.xml in jBPM has been extracted from the jars so that users can specify their own persistence units. ThisĀ  means it’s also how users will be able to specify JPA 1.0 or 2.0 in their persistence units.

Another hurdle here has been the fact that Drools/jBPM is stuck with Hibernate 3.3.x and 3.4.x jars at the moment — and those versions do not support JPA 2. This means futzing around with dependencies and maven profiles. It’s not that big of a deal but also not that elegant — but I challenge anyone who says programming that gets things done should always be elegant. It’s a goal, not a requirement.

Also, the largest Hibernate 3.3/3.4 compatibility issue is by far the @CollectionOfElements annotation: ahead of it’s time, but it’s unfortunate that Hibernate didn’t elect to stay backwards compatible by translating @CollectionOfElements to @ElementCollection underwater once Hibernate became JPA 2 compliant.

So, what I’ve done is the following:

  • I’ve created a hibernate-4 profile in the relevant projects that use persistence (drools-persistence-jpa, jbpm-persistence-jpa, and jbpm-bam, to start with).
  • This hibernate-4 profile replaces the hibernate 3.x dependencies with hibernate 4.x dependencies, and since some hibernate jars changed names between versions, it adds the correct 4.x jars to replace the 3.x jars.
    • This means that, for example, the hibernate-annotations 3.x jar will be there when it’s not needed, but that’s not that big a deal. (It looks like hibernate-annotations disappeared as soon hibernate started supporting JPA 2.0).
    • Part of what I’m doing is also making sure that no hibernate jars are actually needed in the code — we want jBPM (and Drools) to be ORM framework independent and hard-baking hibernate dependencies in won’t help that.
  • This hibernate-4 profile also uses the maven-replacer-plugin to fix all kinds of things in the persistence.xml and orm.xml files.

Lastly, before I get to the meat of this post (using JPA 2 with Drools/jBPM), I have one more fact (or rant..). Why is the order of attribute types defined in entity-mappings? WHY?!? To give you an illustration, the following mapping is incorrect:

<entity class="forest.bee.hive">
  <element-collection name="honey" target-class="double" />
  <basic name="worker" />
  <version name="queen">
  <basic name="pupa" />
</entity class>

It’s invalid because all <basic> elements must come before all <version> elements which must come before all <element-collection> elements. WTF? I once had to mediate a ridiculously overheated discussion about XSD standards — and I do realize that it’s a complicated if arcane topic — but stil, wasn’t it possible to decouple the order? Okay, maybe it was impractical in terms of the parsing modifications then necessary.

In any case, if you’re writing your own JPA 2 XML entity-mappings, stop, and do it using annotations. Otherwise, if you really must know, the order (as specified in the xsd) is:

  1. description
  2. idorembedded-id
  3. basic
  4. version
  5. many-to-one
  6. one-to-many
  7. one-to-one
  8. many-to-many
  9. element-collection
  10. embedded
  11. transient

What was also interesting were the precise semantics of that metadata-complete attribute present in the <entity> element. If you do a websearch on “metatdata-complete jpa”, you’ll quickly learn that metadata-complete=true means that the annotation information for the class is ignored in this case and that the container/persistence-context will only use the XML information.

However, I wanted to do as little work as possible and was curious as to what would happen if metadata-complete=false. And the web was silent.. until I found this little sentence on a sun blog/technical post about JEE 6:

As is the case for web fragments, you use the <metadata-complete> element in the web.xml file to instruct the web container whether to look for annotations. If you set <metadata-complete> to false or do not specify the <metadata-complete> element in your file, then during deployment, the container must scan annotations as well as web fragments to build the effective metadata for the web application. However, if you set <metadata-complete> to true, the deployment descriptors provide all the configuration information for the web application. In this case, the web container does not search for annotations and web fragments.

This quote is from Introducing the JEE 6 Platform: Part 3 and the bold lettering has been added by me to emphasize my point: if metadata-complete=false then the container will use both the annotation data and the XML data. That means that if you want to override an annotation with XML information, you must use metadata-complete=true to ensure that the container does not use the annotation metadata. This must be partially why we can get away with using the ProcessInstanceInfo.hbm.xml mapping file and leaving a @PreUpdate annotation in the file.

Lastly, I’d also like to add that I’ve had to do some minor hacking to get all of this done. The problem, in short, is the following:

  1. The main problem is that jBPM 5 contained a class that used the Hibernate 3.x exclusive @CollectionOfElements annotation.
  2. Leaving this in the code meant that we could not compile the code with Hibernate 4 (since 4 doesn’t contain that class).
  3. Which means that using a ProcessInstanceInfo.hbm.xml file — a hibernate mapping file — to configure the ProcessInstanceInfo class. Because the mapping is now in the xml, the code will compile with Hibernate 4.
  4. However, this means we have to map all fields of ProcessInstanceInfo in the ProcessInstanceInfo.hbm.xml file: Hibernate will otherwise unfortunately complain about duplicate (hibernate) mappings if we use both (JPA or Hibernate) annotations and a Hibernate mapping file.
  5. Luckily, we can leave the @PreUpdate annotation in ProcessInstanceInfo, since Hibernate 3.x doesn’t have a simple annotation that is equivalent.
  6. But Hibernate 3.3/3.4 doesn’t support byte array blob objects. This means writing a BlobUserType class that extends the Hibernate UserType in order to be able to do this: we don’t want users to have to change their schema’s. Most annoyingly (and in slight contradiction to the quote from sun above), Hibernate will complain if we use JPA (field) annotations and a hbm.xml file on/for the same class.
  7. When users use JPA 2 (possibly with Hibernate 4), they then need to make sure not to use the ProcessInstanceInfo.hbm.xml and instead to include a JPA 2 entity mapping for the ProcessInstanceInfo class — which is currently commented out in the JBPMorm.xml file.

And that’s what has happened.

 

Advertisements
Categories: jBPM, Persistence