This post is part 6 in a 9-part series on Envers, Spring, and JTA. The next post is An answer, and the previous post is The versioning isn’t happening, part 4a: phone a friend.
I’m just getting back to the envers-JTA-hooks-not-getting-called thing — the following is from work I did last Wednesday —
A post to the Spring Data Access forum had this interesting line:
DEBUG [org.springframework.transaction.jta.JtaTransactionManager] Triggering beforeCompletion synchronization
Hey! Just when I was beginning to worry that Spring’s JtaTransactionManager had never heard of beforeCompletion and didn’t intend to call that callback. So… where is that line of code, and who calls it?
Where It Is, and Who Calls It
Back at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(TransactionStatus), this calls its own internal processCommit() method, which — why did we not notice this before? — does these things (among others):
prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status);
TriggerBeforeCompletion() ?! Firing up the ol’ debugger, I do make it in there. So it *is* trying to run the beforeCompletion Synchronizations, methinks. Perhaps they aren’t being registered?
triggerBeforeCompletion() calls TransactionSynchronizationUtils.triggerBeforeCompletion(), which calls org.springframework.transaction.support.TransactionSynchronizationManager.getSynchronizations(). (The TransactionSynchronizationManager is also the class that has a registerSynchronization(TransactionSynchronization) method — but instead of taking a javax.transaction.Synchronization, it takes a org.springframework.transaction.support.TransactionSynchronization.)
The only TransactionSynchronization that’s in there currently is a org.springframework.orm.hibernate3.SpringSessionSynchronization.
Envers’ org.jboss.envers.synchronization.VersionsSyncManager.get(EventSource session) calls session.getTransaction().registerSynchronization(). The getTransaction() call returns an org.hibernate.transaction.JDBCTransaction.
Next step: Can we get at that JDBCTransaction from JtaTransactionManager’s doCommit()? Or alternatively, can the thing passed as an EventSource to VersionsSyncManager.get() be something that wraps a JDBCTransaction and also registers with the Spring TransactionSynchronizationManager?