Hello; for various mostly pointless reasons and just plain old curiosity I found myself doing some old-fashioned code reading in and around the JPA implementation in Wildfly.
I had a question related very narrowly to the non-transactional parts of the Wildfly transaction-scoped EntityManager implementation.
When a user invokes a method on a transaction-scoped EntityManager while a JTA transaction is not in play, an EntityManager delegate is looked up from a thread local stack of such delegates, indexed under the name of the persistence unit in question. If one isn't found, then one is created and pushed on that stack. You can see an example of that here: https://github.com/wildfly/wildfly/blob/7f80f0150297bbc418a38e7e23da7cf0431f7c28/jpa/subsystem/src/main/java/org/jboss/as/jpa/container/TransactionScopedEntityManager.java#L88-L92
Obviously, if a transaction then comes into play, that non-transactional EntityManager that was created will have to be closed at some point, although it doesn't really truly matter, because by definition you can only do non-transactional work with a non-transactional EntityManager. Nevertheless, the NonTxEmCloser takes care of that: https://github.com/wildfly/wildfly/blob/60aa6cd1e7c31c3d1b7068a97fde027fd108a4a5/jpa/subsystem/src/main/java/org/jboss/as/jpa/container/NonTxEmCloser.java#L58-L75
I definitely understand the high-level of what's going on here.
My question is: NonTxEmCloser has a thread local stack of Maps indexing EntityManagers by persistence unit names. Why?
I understand two out of three things about this structure: I understand why it's thread-local (EntityManagers are by definition not thread-safe). I understand why you need a Map to make sure that a given EntityManager "belongs" to the right persistence unit. But why is there a stack of these maps?
I also understand that the quick answer to this question is, "because the stack tracks the call stack of EJB components (or whatever) that are using these injected EntityManagers", and that's fine, but given that this whole machine is set up to deal with non-transactional EntityManagers, why wouldn't you have a single thread-safe Map, with one non-transactional EntityManager in it per persistence unit, regardless of how deep the Java EE component invocation stack is? Why create extras?