Question

I currently have Jackrabbit 2.6.4 deployed in Glassfish 4 using the JCA rar.

I am using MySql and have configured a datasource in Glassfish to access the database. I use the same datasource in the Jackrabbit repository.xml when configuring the RepositoryManager.

If I inject a repository via the @Resource annotation into a container managed bean that does not automatically start a transaction everything works as expected.

If I inject a repository via the @Resource annotation into a EJB (which results in a container managed transaction) I get the following stack trace when I attempt to use the repository:

javax.resource.spi.LocalTransactionException: Can't call commit when autocommit=true at com.sun.gjc.spi.LocalTransactionImpl.commit(LocalTransactionImpl.java:112) at com.sun.enterprise.resource.ConnectorXAResource.commit(ConnectorXAResource.java:124) ... Caused by: java.sql.SQLException: Can't call commit when autocommit=true at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:924) at com.mysql.jdbc.ConnectionImpl.commit(ConnectionImpl.java:1724) at com.sun.gjc.spi.LocalTransactionImpl.commit(LocalTransactionImpl.java:106) ... 72 more ]] [2013-10-28T14:49:29.646-0700] [glassfish 4.0] [WARNING] [jts.unexpected_error_occurred_twopc_commit] [javax.enterprise.system.core.transaction.com.sun.jts.jtsxa] [tid: _ThreadID=33 _ThreadName=http-listener-1(3)] [timeMillis: 1382996969646] [levelValue: 900] [[ JTS5067: Unexpected error occurred in commit javax.transaction.xa.XAException: javax.resource.spi.LocalTransactionException: Can't call commit when autocommit=true at com.sun.enterprise.resource.ConnectorXAResource.handleResourceException(ConnectorXAResource.java:115) at com.sun.enterprise.resource.ConnectorXAResource.commit(ConnectorXAResource.java:126) ... ]]

Looking at the Jackrabbit documentation is states:

If you use a database persistence manager, the configured database connection must not be under the control of an external transaction manager. Jackrabbit implements distributed XA transaction support on a higher level, and expects to be in full control of the underlying database connection.

Given this how do/can I configure Jackrabbit and Glassfish to allow both container managed transactions and Jackrabbit managed transactions to participate together in the same global transaction?

I have tried setting both the Jackrabbit JCA adapter and the Datasource Connection Pool to use XA Transactions. I have also set the Jackrabbit JCA property bindSessionToTransaction to true. Neither of these worked.

Was it helpful?

Solution

After some trial and error I have come up with the following approach:

  1. Create a JDBC Connection pool in glassfish that is used to access the Jackrabbit Repository tables.
  2. Set the resource type to javax.sql.DataSource and enable 'Non Transactional Connections'
  3. Create a JDBC resource that can be used to access to the Jackrabbit JDBC Connection Pool. Use the JNDI name defined in this resource in the Jackrabbit repository.xml to configure the persistence manager etc.
  4. Create a Connector connection pools using the Jackrabbit-jca resource adapter
  5. Set Transaction Support to XATransaction
  6. Add the property 'bindSessionToTransaction' and set it to true
  7. Create a Connector Resource that can be used to inject the Repository into a EJB

I have tested this with a stateless EJB and it works without error.

I also created a second JDBC Connection pool of type javax.sql.DataSource and a JDBC resource that points to a separate database that maintains the applications other tables and created a persistence.xml that uses the datasource.

I then modified both the repo and the tables in the applications database (using JPA) and confirmed that if the transaction is rolled back both the changes on the repo and application tables are rolled back correctly.

I believe this is the correct approach as it allows Jackrabbit to be in full control of it's database connection but still participate in the container managed transaction as an XA Resource.

I did test the second datasource both as a XADataSource and a non-XA DataSource and both approaches worked. I assume it does not need to be a XADataSource as the are no other non-XA DataSources in the transaction and it participates in the global transaction via LLR (Logging Last Resource).

Update 1:

It turns out you can also get this to work by bypassing the repo datasource and configuring the JDBC URL directly in the repository xml. One benefit of this is when clustering the repo you do not need to create a datasource in each Glassfish instance, instead you can just copy the repository.xml and change the cluster node id.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top