Hi Dain,
Just got some time to write a JPA/OpenEJB integration test following
your example. Everything works except for one thing. Here is my
sample code:
GeronimoTransactionManagerJTA11 tm = new
GeronimoTransactionManagerJTA11();
System.setProperty(
Context.INITIAL_CONTEXT_FACTORY,
LocalInitialContextFactory.class.getName());
new InitialContext().bind("java:comp/
TransactionSynchronizationRegistry", tm);
EntityManagerFactory factory = ... // init code for Cayenne
JTA EMF
JtaEntityManagerRegistry registry = new
JtaEntityManagerRegistry(tm);
tm.begin();
EntityManager entityManager = new JtaEntityManager(
registry,
factory,
new Properties(),
false);
SimpleEntity e = new SimpleEntity();
e.setProperty1("XXX");
entityManager.persist(e);
tm.commit(); // Nothing is saved to the DB here
Now the problem...
According to the JPA spec, ch. 5.9.2, "When
EntityManagerFactory.createEntityManager is invoked, the provider
must create and return a new entity manager. If a JTA transaction is
active, the provider must register for synchronization notifications
against the JTA transaction."
So that's what Cayenne EMF does [1], [2] via
TransactionSynchronizationRegistry.registerInterposedSynchronization
(..). At a later time OpenEJB JtaEntityManager calls the same method
on the registry to register a its own close operation, kicking out
Cayenne EM callback. The end result is that the EntityManager is not
flushed in "beforeCompletion" and nothing is saved to DB.
I suspect Geronimo TransactionImpl is to blame here. It only allows a
single interposed synchronization. Is it a requirement of the JTA
spec? (if it is, I couldn't find any mention of it). If everyone
agrees with my assessment of the situation, I can submit a patch.
Thoughts?
Andrus
[1] https://svn.apache.org/repos/asf/cayenne/main/trunk/framework/
cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/
JtaEntityManagerFactory.java
[2] https://svn.apache.org/repos/asf/cayenne/main/trunk/framework/
cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/
JtaEntityManager.java
On Jan 11, 2007, at 10:34 PM, Dain Sundstrom wrote:
I just committed the JtaEntityManager and JtaEntityManagerRegistry
to the openejb-persistence module. You can create a
JtaEntityManager with the following code:
JtaEntityManagerRegistry registry = new JtaEntityManagerRegistry
(transactionSynchronizationRegistry);
EntityManager entityManager = new JtaEntityManager(registry,
entityManagerFactory,
properties,
extended);
That's it. The under the covers of the JtaEntityManager a new
EntityManager instance is created using the EMF for each transaction.
A single instance of the JtaEntityManagerRegistry should be shared
by all JtaEntityManagers. TransactionSynchronization registry is a
new interface in JTA 1.1. The Geronimo JTA 1.1 transaction manager
implements this interface directly, but if you are not using that
transaction manager just wrap your transaction manager with the
openejb SimpleTransactionSynchronizationRegistry.
If you want to test extended entity managers (only used by stateful
session beans), you will need to simulate stateful session bean
construction, entrance, exit and starting of user transactions by
call in the appropriate method on the JtaEntityManagerRegistry.
If you run into problems, don't hesitate to ask.
-dain