Tuesday, July 27, 2010

Deploying JBPM Enterprise in OC4J, part 1: not yet OC4J specific

I just can't get away from this OC4J and JBPM. After I have solved the problem with JMS transactions the team asked me to do another "small" thing: include jbpm-enterprise.jar in the project instead of copy-pasted code. The idea is nice and sound of course: after all, the only reason for that copy-pasted code was desire to get the project going in a short amount of time and to avoid that JMS transaction problem... Well, let's say I believed them.

After spending quite some time on it, first with another colleague and then on my own, I came to the conclusion: forget it, it is just not worth the trouble. (This is applicable to JBPM 3.3.1 and OC4J 10.1.3; the situation might be better with newer versions.)

This post is a bit more practical than the previous one because there might be somebody else out there trying to get it working in some other app server. Other than JBoss that is.

Here is the list of things I came across trying to make that work. Some of them are generic and some are OC4J specific, and the advice "forget it" is applicable to OC4J. Other app servers might be a bit easier as targets.

1. Of course, the first thing was to get rid of copy-paste code, add jbpm-enterprise.jar as a maven dependency, change jbpm.cfg.xml to point to relevant classes from jbpm-enterprise, and fire 'mvn clean install'. Well, that was easy. It compiles? Wow, we are almost there... Or not, because unit tests fail. Openejb does not like jbpm-enterprise, namely, its MDBs (there are two of them, JobListenerBean that extends CommandListenerBean). The error message is pretty clear:

When annotating a bean class as @MessageDriven without declaring messageListenerInterface, the bean must implement exactly one interface, no more and no less. beanClass=org.jbpm.ejb.impl. JobListenerBean

Yeah, sure, 'CommandListenerBean implements MessageListener' and 'JobListenerBean extends CommandListenerBean'. Except that the beans do not use any annotations. jbpm-enterprise uses a deployment descriptor instead. Annoying... the error message could have been better. Apparently, openejb does not distinguish (at least here) between annotations and deployment descriptor because changing the descriptor was enough to fix the problem (adding javax.jms.MessageListener to both beans). But this means that jbpm-enterprise can't be used as is and has to be repackaged. Not a big problem: we would need to repackage it anyway because it needs an OC4J specific deployment descriptor. The "right" solution is ... would be ... found later, we are just not in the mood for all this maven stuff now, let alone licensing. For now: repackage it manually, and place it back into the local maven repository. At least we can continue.

2. Tests still fail, except this time with javax.naming.NamingException. All the joys of server independent code, configuration in deployment descriptors, etc, etc, and so on were destroyed with one line:

String connectionFactoryJndiName = "java:JmsXA";
Nice, is it not? JBoss specific JNDI names, hardcoded in java code. Those guys know a thing or two about portable applications, don't they? OK, changing a deployment descriptor is one thing, but changing the code is too far. Fortunately those factories in JBPM are pluggable, so we just have to implement our own. Done in no time, subclass JmsMessageServiceFactory, override public ConnectionFactory getConnectionFactory(), except that... what JNDI name should we use? No so difficult to answer thought we, the deployment descriptor uses jms/JbpmConnectionFactory, so we use it as well.

3. I spare you... res-ref-names, openejb specific names, attempts to define openejb connection factories, ... nothing worked. I think that we would have been able to debug the problem eventually, but pure by chance we found it. All that fuss just because of a one letter! Meet the hero: ejb-jar.xml, line 79, javax.jms.ConnnectionFactory

4. Repackage, compile, test. Well, I should have guessed. java:JmsXA was not the only one. Queue names in JmsMessageServiceFactory.java are also JBoss specific. Let's call it a day for today.

Anyway, as of that moment I continued to work on the problem alone.

Sime time later:

5. Using res-ref-names and message-destination-ref-name from the deployment descriptor in my subclass of JmsMessageServiceFactory did not work. I had to use openejb specific JNDI names, and I did not like it at all. Well, at least most of unit tests are green. Only one is still failing.

6. I decided to get rid of the server specific JNDI names first. There were several possibilities, but most of them would require specifying some additional things in the deployment descriptor for each enterprise bean that ends up invoking JmsMessageServiceFactory, including any bean that would be added later. I did not like that, so I just created a single SLSB with the correct @Resource annotations and then used it from my JmsMessageServiceFactory implementation. At least I have to configure one bean correctly and never worry about any other beans. Test again, and the same test as before is failing, with the same message. It is a good sign. Really.

7. So what is interesting about that test? It is the only test so far that not only uses JBPM functionality to send JMS messages but also depends on it. There are some tests that have the necessary jbpm woo-doo to send JMS messages, but those tests never check results of JMS operations. There are other tests relying on JMS, but they are in another, dependent, maven project, and I am not yet that far. Some more logging-debugging, and the result: openejb uses different queues in SLSB and in MDBs (I should have realize it sooner). OK, some more changes to the deployment descriptor of jbpm-enterprise, package (aren't that tiring?), copy, compile, test... Success, everything is green.

Conclusion: if you need to deploy jbpm-enterprise in openejb (-derived) server, it can be done if you are prepared to edit the deployment descriptor and add couple of java classes.

But I need to deploy it in OC4J. To be continued...

No comments:

Post a Comment