OpenJPA
  1. OpenJPA
  2. OPENJPA-2234

EntityManager instance creation needs TX activity

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0.1
    • Fix Version/s: 2.3.0
    • Component/s: None
    • Labels:
      None
    • Environment:
      - JDK 1.5
      - Spring 3.1.1.RELEASE
      - Spring Data JPA 1.1 GA (issue confirmed on version 1.0.3)
      - Atomikos 3.7.0
      - OpenJPA 2.0.1
      - DB2 9.7

      Description

      While working with Spring Data, we came across a potential bug in OpenJPA.

      The bug was provoked by a query lookup module in Spring Data JPA, but it has its roots in AbstractBrokerFactory class, which seems to require transaction existence in order to create EntityManager (which is contrary to JPA spec).

      I have already been in touch with Spring Data JPA author (where I filed a bug against Spring Data JPA) who actually pointed me to file a bug here.

      I have extensively documented my findings on this thread (http://stackoverflow.com/questions/10688040/spring-data-jpa-fails-to-invoke-jtatransactionmanager), so I'll rather post the link, instead of repeating the whole thing here.

      All that being said, I am not entirely sure what actually happened and am no authority whatsoever on JPA spec.

        Activity

        Hide
        Rick Curtis added a comment -

        Erik -

        Thanks for the thorough SO writeup. Unfortunately I think you're assessment of where the problems lies isn't quite correct. If you were to look at the OpenJPA code:

        boolean syncWithManagedTransaction(BrokerImpl broker, boolean begin) {
        Transaction trans;
        try {
        ManagedRuntime mr = broker.getManagedRuntime();
        TransactionManager tm = mr.getTransactionManager();
        trans = tm.getTransaction(); <<< line 720

        you will notice that the NPE is coming from not having a TransactionManager, not that you don't have a transaction.

        I see the following line in your persistence configuration :

        <entry key="openjpa.ManagedRuntime" value="invocation(TransactionManagerMethod=com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager)" />

        We can start out with an easy one, is the getTransactionManager method static? If not, try changing that.

        Thanks,
        Rick

        Show
        Rick Curtis added a comment - Erik - Thanks for the thorough SO writeup. Unfortunately I think you're assessment of where the problems lies isn't quite correct. If you were to look at the OpenJPA code: boolean syncWithManagedTransaction(BrokerImpl broker, boolean begin) { Transaction trans; try { ManagedRuntime mr = broker.getManagedRuntime(); TransactionManager tm = mr.getTransactionManager(); trans = tm.getTransaction(); <<< line 720 you will notice that the NPE is coming from not having a TransactionManager, not that you don't have a transaction. I see the following line in your persistence configuration : <entry key="openjpa.ManagedRuntime" value="invocation(TransactionManagerMethod=com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager)" /> We can start out with an easy one, is the getTransactionManager method static? If not, try changing that. Thanks, Rick
        Hide
        Erik Kis added a comment -

        Hello, Rick, thanks for your quick response.

        Regarding persistence configuration, I've checked - getTransactionManager() method is static.

        Regarding problem assessment - I agree with you; I've actually noticed that Spring doesn't set the TransactionManager (PlatformTransactionManager's setter is not invoked), hence we get NPE@line 720. The problem happens while bootstrapping Spring application context - more specifically, while Spring Data JPA performs query lookup. Now, if you were to check comments in SO writeup, you'll notice that in correspondence with Oliver Gierke (Spring Data JPA project lead), he had stated that OpenJPA is actually not conforming here to JPA specification, since by JPA spec, no tx activity is needed during query creation (i.e. while executing entityManager.createQuery(...)).

        As I said, I am far from understanding every nook and cranny in any of the participating modules (be it OpenJPA, Spring Data JPA or the JPA2 specification itself), however, his arguments do seem convincing, at least to me.

        Is there anything else we could try?

        Show
        Erik Kis added a comment - Hello, Rick, thanks for your quick response. Regarding persistence configuration, I've checked - getTransactionManager() method is static. Regarding problem assessment - I agree with you; I've actually noticed that Spring doesn't set the TransactionManager (PlatformTransactionManager's setter is not invoked), hence we get NPE@line 720. The problem happens while bootstrapping Spring application context - more specifically, while Spring Data JPA performs query lookup. Now, if you were to check comments in SO writeup, you'll notice that in correspondence with Oliver Gierke (Spring Data JPA project lead), he had stated that OpenJPA is actually not conforming here to JPA specification, since by JPA spec, no tx activity is needed during query creation (i.e. while executing entityManager.createQuery(...)). As I said, I am far from understanding every nook and cranny in any of the participating modules (be it OpenJPA, Spring Data JPA or the JPA2 specification itself), however, his arguments do seem convincing, at least to me. Is there anything else we could try?
        Hide
        Rick Curtis added a comment -

        The root issue is that you configured OpenJPA to call com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager() to get a TransactionManager instance and that method returned null.

        The OpenJPA runtime requires that we have a TransactionManager (Not a transaction, just a manager) to function properly. I believe Oliver is incorrect in stating that we're in violation of the spec in this regards.

        > Is there anything else we could try?
        Perhaps Oliver could help you/us understand why you have the configuration you do, and why it is returning a null TransactionManager?

        Thanks,
        Rick

        Show
        Rick Curtis added a comment - The root issue is that you configured OpenJPA to call com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager() to get a TransactionManager instance and that method returned null. The OpenJPA runtime requires that we have a TransactionManager (Not a transaction, just a manager) to function properly. I believe Oliver is incorrect in stating that we're in violation of the spec in this regards. > Is there anything else we could try? Perhaps Oliver could help you/us understand why you have the configuration you do, and why it is returning a null TransactionManager? Thanks, Rick
        Hide
        Oliver Gierke added a comment -

        I didn't suspect OpenJPA to violate the spec. All I was stumbling above was that apparently the EntityManagerFactory bootstrap code tries to access a TransactionManager which effectively can't be in place at that time as usually the Txmanager works with the EntityManagerFactory in turn. At least OpenJPA behaves very different compared to other JPA providers and I wondered why this early TxManager lookup is required.

        Show
        Oliver Gierke added a comment - I didn't suspect OpenJPA to violate the spec. All I was stumbling above was that apparently the EntityManagerFactory bootstrap code tries to access a TransactionManager which effectively can't be in place at that time as usually the Txmanager works with the EntityManagerFactory in turn. At least OpenJPA behaves very different compared to other JPA providers and I wondered why this early TxManager lookup is required.
        Hide
        Rick Curtis added a comment -

        > that apparently the EntityManagerFactory bootstrap code tries to access a TransactionManager which effectively can't be in place at that time as usually the Txmanager works with the EntityManagerFactory in turn.
        I don't follow your comment? The exception occurs at EntityManager creation, not EntityManagerFactory.

        Show
        Rick Curtis added a comment - > that apparently the EntityManagerFactory bootstrap code tries to access a TransactionManager which effectively can't be in place at that time as usually the Txmanager works with the EntityManagerFactory in turn. I don't follow your comment? The exception occurs at EntityManager creation, not EntityManagerFactory.
        Hide
        Rick Curtis added a comment -

        Closing as invalid. Please reopen with additional data if you disagree.

        Show
        Rick Curtis added a comment - Closing as invalid. Please reopen with additional data if you disagree.
        Hide
        Oliver Gierke added a comment -

        How is the TransactionManager expected to be set on the EntityManagerFactory then? I cannot see any API on EntityManagerFactoryImpl which could have been invoked. I'd also argue that the implementation should shield against the transaction manager being null more explicitly if it is mandatory rather than throwing a generic NPE. There seems to be a configuration/setup error by the user and that should be communicated.

        Show
        Oliver Gierke added a comment - How is the TransactionManager expected to be set on the EntityManagerFactory then? I cannot see any API on EntityManagerFactoryImpl which could have been invoked. I'd also argue that the implementation should shield against the transaction manager being null more explicitly if it is mandatory rather than throwing a generic NPE. There seems to be a configuration/setup error by the user and that should be communicated.
        Hide
        Romain Manni-Bucau added a comment -

        Hi Olivier, it is done thanks to the managed runtime

        just configure <entry key="openjpa.ManagedRuntime" value="invocation(TransactionManagerMethod=foo.TxMgrHolder.getTransactionManager)" />

        for spring you can return a proxy which will get the tx mgr from the app ctx - btw then you'll need to deal with spring/openjpa lifecycle

        Show
        Romain Manni-Bucau added a comment - Hi Olivier, it is done thanks to the managed runtime just configure <entry key="openjpa.ManagedRuntime" value="invocation(TransactionManagerMethod=foo.TxMgrHolder.getTransactionManager)" /> for spring you can return a proxy which will get the tx mgr from the app ctx - btw then you'll need to deal with spring/openjpa lifecycle
        Hide
        Rick Curtis added a comment -

        > I'd also argue that the implementation should shield against the transaction manager being null more explicitly if it is mandatory rather than throwing a generic NPE.
        Agreed. I'll add that sometime this morning.

        Show
        Rick Curtis added a comment - > I'd also argue that the implementation should shield against the transaction manager being null more explicitly if it is mandatory rather than throwing a generic NPE. Agreed. I'll add that sometime this morning.
        Hide
        Erik Kis added a comment -

        > Hi Olivier, it is done thanks to the managed runtime....

        Hello, Romain, if you check the StackOverflow link in the problem description, you'll notice that ManagedRuntime property has indeed been set, but had not prevented NPE from being thrown.

        Show
        Erik Kis added a comment - > Hi Olivier, it is done thanks to the managed runtime.... Hello, Romain, if you check the StackOverflow link in the problem description, you'll notice that ManagedRuntime property has indeed been set, but had not prevented NPE from being thrown.
        Hide
        Romain Manni-Bucau added a comment -

        this means spring is not started, just need to be started before

        Show
        Romain Manni-Bucau added a comment - this means spring is not started, just need to be started before
        Hide
        Rick Curtis added a comment -

        Committed revision 1396043 to trunk.

        Now we'll throw the following exception when we encounter a nullTransactionManager.

        <openjpa-2.3.0-SNAPSHOT-r422266:1393779M fatal internal error> org.apache.openjpa.util.InternalException: Received a null javax.transaction.TransactionManager from the openjpa.ManagedRuntime "org.apache.openjpa.ee.TestNullTransactionManagerFromRuntime$ManagedRuntimeNullTransactionManager@64686468".
        at org.apache.openjpa.kernel.AbstractBrokerFactory.syncWithManagedTransaction(AbstractBrokerFactory.java:727)
        at org.apache.openjpa.kernel.BrokerImpl.initialize(BrokerImpl.java:391)
        at org.apache.openjpa.kernel.BrokerImpl.initialize(BrokerImpl.java:325)

        Show
        Rick Curtis added a comment - Committed revision 1396043 to trunk. Now we'll throw the following exception when we encounter a nullTransactionManager. <openjpa-2.3.0-SNAPSHOT-r422266:1393779M fatal internal error> org.apache.openjpa.util.InternalException: Received a null javax.transaction.TransactionManager from the openjpa.ManagedRuntime "org.apache.openjpa.ee.TestNullTransactionManagerFromRuntime$ManagedRuntimeNullTransactionManager@64686468". at org.apache.openjpa.kernel.AbstractBrokerFactory.syncWithManagedTransaction(AbstractBrokerFactory.java:727) at org.apache.openjpa.kernel.BrokerImpl.initialize(BrokerImpl.java:391) at org.apache.openjpa.kernel.BrokerImpl.initialize(BrokerImpl.java:325)
        Hide
        Erik Kis added a comment -

        Thx, Rick for this - I just wonder is there any way to recover from this exception? Also, is there any chance of backporting this to 2.0.x branch?

        Show
        Erik Kis added a comment - Thx, Rick for this - I just wonder is there any way to recover from this exception? Also, is there any chance of backporting this to 2.0.x branch?
        Hide
        Rick Curtis added a comment -

        Erik - Honestly, I'm not aware of any way to recover. I suspect I could log a warning, but other parts of the runtime would blow chunks with a similar NPE due to the missing TM. It seemed safer to detect this condition and fail fast.

        It is unlikely that this change will make it into 2.0.x as that is a WebSphere managed branch... but I'll shoot a note to the branch owner to see what he thinks.

        Show
        Rick Curtis added a comment - Erik - Honestly, I'm not aware of any way to recover. I suspect I could log a warning, but other parts of the runtime would blow chunks with a similar NPE due to the missing TM. It seemed safer to detect this condition and fail fast. It is unlikely that this change will make it into 2.0.x as that is a WebSphere managed branch... but I'll shoot a note to the branch owner to see what he thinks.
        Hide
        Rick Curtis added a comment -

        I talked with the branch owner and he said that to get this change into 2.0.x you'd need to go through WebSphere support and get PMR opened to get the thumbs up to merge this change.

        Show
        Rick Curtis added a comment - I talked with the branch owner and he said that to get this change into 2.0.x you'd need to go through WebSphere support and get PMR opened to get the thumbs up to merge this change.

          People

          • Assignee:
            Rick Curtis
            Reporter:
            Erik Kis
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development