Search code examples
javajpaopenjpajtafuseesb

OpenJPA - Transaction management is not available... (Fuse ESB)


I'm having trouble with RESOURCE_LOCAL transaction type for JPA in Fuse ESB.

I also don't have a complete understanding of whether JTA or RESOURCE_LOCAL is better for me.

My persistence.xml :

<persistence-unit name="invoicePersistence" transaction-type="RESOURCE_LOCAL">

    <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
    <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/invDataSource)</jta-data-source>
    <non-jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/invDataSource)</non-jta-data-source>
    <class>com.company.service.Invoice</class>
    <!-- etc... -->

</persistence-unit>

My beans in blueprint.xml :

<reference id="invDataSource" interface="javax.sql.DataSource" filter="(datasource.name=invDataSource)"/>

<bean id="invoiceDao" class="com.company.project.InvoiceDao">
    <jpa:context unitname="invoicePersistence" property="entityManager"/>
    <tx:transaction method="*" value="Required" />
</bean>

And my code :

    entityManager.getTransaction().begin();

    entityManager.persist(a);
    entityManager.persist(b);

    entityManager.getTransaction().commit();

And the exception, using transaction-type RESOURCE_LOCAL in my persistence.xml:

java.lang.IllegalStateException: Transaction management is not available for container managed EntityManagers.

I also tried using transaction-type JTA in my persistence.xml but then I received OptimisticLockException.

I'm not sure which approach is better (RESOURCE_LOCAL or JTA) but the main thing is that in my code object a and b need to be persisted in a transaction (all or nothing).

I'm running in Fuse ESB (camel, cxf, etc).

Thanks for any tips or help.


Solution

  • Ok, here is the answer.

    Firstly, 2 nice links on JPA Concepts and the Aries JPA Container

    RESOURCE_LOCAL

    transaction-type="RESOURCE_LOCAL" is indeed self-managed persistence, and the code should be like this:

    EntityManager entityManager = entityManagerFactory.createEntityManager();
    
    ...
    
    entityManager.getTransaction().begin();
    entityManager.persist(a);
    entityManager.persist(b);
    entityManager.getTransaction().commit();
    

    Using entityManager.getTransaction() and entityManager.flush() both caused exceptions, because I had specified <jpa:context>.

    The correct way to do it is with <jpa:unit> and EntityManagerFactory.

    <bean id="invoiceDao" class="com.company.project.InvoiceDao">
        <jpa:unit unitname="invoicePersistence" property="entityManagerFactory"/>
    </bean>
    

    JTA

    On the other hand transaction-type="JTA" is 'container-managed' persistence:

    entityManager.persist(a);
    entityManager.persist(b);
    

    and it should be configured in blueprint with <jpa:context> and an EntityManager.