2

My use case is:

I have an existing JTA TransactionManager and a Transaction in-flight. I'd like to enlist Neo4j as an XAResource in this Transaction such that it may prepare/commit in proper 2PC.

I'm not seeing a public XAResource implementation in Neo4j; everything seems to be routed through the NioNeoDbPersistenceSource > NeoStoreXaDataSource > NeoStoreXaConnection.NeoStoreXaResource.

Is there a preferred way to enlist Neo4j in JTA Transactions outside those provided by its own TransactionManager? All the test cases I'm finding enlist mock "FakeXAResource"[1]

Appreciated!

S, ALR

[1] e.g. UseJOTMAsTxManagerIT

ALRubinger
  • 31
  • 3
  • I suspect it may have something to do with TransactionManagerProvider, similarly done here: https://github.com/digitalstain/Neo4j-Spring-Integration/blob/master/txModule/src/main/java/org/neo4j/jta/spring/SpringProvider.java – ALRubinger May 23 '14 at 16:04

1 Answers1

0

OK, I have a solution which I believe is the best that Neo4j can handle, though I'm not thrilled with it. :)

https://gist.github.com/ALRubinger/b584065d0e7da251469a

The idea is this:

1) Implement Neo4j's AbstractTransactionManager

This clunky class is a composite of JTA TransactionManager, Neo4j Lifecycle, and some other methods; it's not completely clear to me what some of these (e.g. "getEventIdentifier()" or "doRecovery()") are supposed to, and the contract feels over-specified. I'm not certain why we'd want lifecycle methods in here for the case where Neo4j is not the authoritative owner of the TransactionManager.

2) Implement Neo4j's TransactionManagerProvider

This will let you create a new instance of your AbstractTransactionManager implementation, but it's bound by the JDK Service SPI, so you must supply a no-arg constructor and find some other intelligent/hacky way of passing contextual information in.

3) Create a META-INF/services/org.neo4j.kernel.impl.transaction.TransactionManagerProvider file, with contents of the FQN of your TransactionManagerProvider impl from step 2)

4) When you create a new GraphDatabaseService, pass in config like:

final GraphDatabaseService graphDatabaseService = new GraphDatabaseFactory().
            newEmbeddedDatabaseBuilder(FILE_NAME_STORAGE).setConfig(
            GraphDatabaseSettings.tx_manager_impl.name(),
            "NAME_OF_YOUR_TXM_PROVIDER")
            .newGraphDatabase();

Then you access the TransactionManager using a deprecated API (GraphDatabaseAPI):

// Get at Neo4j's view of the TransactionManager
final TransactionManager tm = ((GraphDatabaseAPI)   graphDatabaseService).getDependencyResolver().resolveDependency(TransactionManager.class);
tm.begin();
final Transaction tx = tm.getTransaction();

The real problem I have with this approach is that we have to use the TransactionManager implementation from Neo4j, which is wrapping our real TM. What I want to do is use my TM and enlist Neo4j as an XAResource.

So I still haven't found a way to do that, and judging from the Neo4j test suites I don't think it's possible at the moment with any of their supplied XAResource support.

Absolutely willing and hoping to be corrected! :)

But failing the points I mention above, the attached gist works and shows Neo4j using an external TransactionManager (Narayana, from us at JBoss) as the backing implementation.

S, ALR

ALRubinger
  • 31
  • 3