In the spirit of following my own advice, I am writing up the blog post I wished I could have found today to help me with a nasty, obscure problem I encountered working on the day job.
The original error that was reported and that I was asked to investigate was this:
java.lang.RuntimeException: Cannot export transaction having non-XA resource: 2-phase commit not possible.
The code in our application that raised this exception was trying to do a remote JNDI lookup and a call to the remote Session bean reference returned from that lookup. We do this in the cluster to centralize a few critical operations to a single node in the cluster. Otherwise, everything in a JEE cluster, especially in Glassfish 2.1, basically just occurs either locally or in a random node. This is not acceptable for managing external resources like a Lucene search index.
A bit of digging hinted that the problem was that our JDBC DataSource was not an XA capable one. We are using PostgreSQL 8.3 and the 603 build of the JDBC 3 drivers for that database. I tried just changing the Datasource Classname for our connection pool in Glassfish’s console to “org.postgresql.xa.PGXADAtaSource” but on restarted and re-deploying got the following error:
I had no idea what this meant. Looking up Sun’s API docs for AbstractMethodError, it claims this should be caught at compilation, it refers to a call to a purely virtual, or abstract, method. It’s one of those “this should never happen” errors. I suspected it was a difference in the interfaces bundled in Glassfish 2.1’s database support and the actual concrete classes from the PostgreSQL JDBC driver jar.
I first tried upgrading that jar to build 604, still using the JDBC 3 drivers. Same error occurred at deployment. On a whim, I tried upgrading the driver to JDBC 4. When I did so, bounced the cluster, and re-deployed our application, then the error did not occur.
Nowhere did I find a simple bit of documentation that suggested if you are trying to use XA, or distributed transactions, in a Glassfish 2.1 cluster that you need to use JDBC 4 capable drivers. Seems like a pretty basic requirement. I also could not find any simple documentation that made it clear that making a remote call from one node to another physical node in a cluster requires XA transactions to use transactions at all. That latter point is pretty self evident in retrospect but it is the kind of rule that can stand being repeated and clarified at every opportunity.
Hopefully this is a clear enough description of this weird little problem with enough specifics to save the next person encountering this problem the hassle I had to go through to get it working without error.