JPAContainer + JTA Nested Transactions

Hi,

I am trying to use the JPAContainer 3.1.1 with EclipseLink 2.6.0-M3, Postgresql and Glassfish 4.1. But when I try to commit my first Entity I get this error (I am only showing the important part):

Caused by: java.lang.RuntimeException: javax.transaction.NotSupportedException: Nested transaction not supported.
    at com.vaadin.addon.jpacontainer.provider.jndijta.Util.runInJTATransaction(Util.java:58)
    at com.vaadin.addon.jpacontainer.provider.jndijta.CachingBatchableEntityProvider.runInTransaction(CachingBatchableEntityProvider.java:54)
    at com.vaadin.addon.jpacontainer.provider.MutableLocalEntityProvider.addEntity(MutableLocalEntityProvider.java:137)
    at com.vaadin.addon.jpacontainer.provider.CachingMutableLocalEntityProvider.addEntity(CachingMutableLocalEntityProvider.java:164)
    at com.vaadin.addon.jpacontainer.BufferedContainerDelegate$1.batchUpdate(BufferedContainerDelegate.java:223)
    ... 69 more
Caused by: javax.transaction.NotSupportedException: Nested transaction not supported.
    at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.begin(JavaEETransactionManagerSimplified.java:813)
    at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.begin(JavaEETransactionManagerSimplified.java:801)
    at com.sun.enterprise.transaction.UserTransactionImpl.begin(UserTransactionImpl.java:169)
    at com.vaadin.addon.jpacontainer.provider.jndijta.Util.runInJTATransaction(Util.java:45)

for this stack:

com.vaadin.addon.jpacontainer.provider.jndijta.Util.runInJTATransaction(Util.java:45)
com.vaadin.addon.jpacontainer.provider.jndijta.CachingBatchableEntityProvider.runInTransaction(CachingBatchableEntityProvider.java:54)
com.vaadin.addon.jpacontainer.provider.MutableLocalEntityProvider.addEntity(MutableLocalEntityProvider.java:137)
com.vaadin.addon.jpacontainer.provider.CachingMutableLocalEntityProvider.addEntity(CachingMutableLocalEntityProvider.java:164)
com.vaadin.addon.jpacontainer.BufferedContainerDelegate$1.batchUpdate(BufferedContainerDelegate.java:223)
com.vaadin.addon.jpacontainer.provider.CachingBatchableLocalEntityProvider$1.run(CachingBatchableLocalEntityProvider.java:73)
com.vaadin.addon.jpacontainer.provider.jndijta.Util.runInJTATransaction(Util.java:46)
com.vaadin.addon.jpacontainer.provider.jndijta.CachingBatchableEntityProvider.runInTransaction(CachingBatchableEntityProvider.java:54)
com.vaadin.addon.jpacontainer.provider.CachingBatchableLocalEntityProvider.batchUpdate(CachingBatchableLocalEntityProvider.java:70)
com.vaadin.addon.jpacontainer.BufferedContainerDelegate.commit(BufferedContainerDelegate.java:214)
com.vaadin.addon.jpacontainer.JPAContainer.commit(JPAContainer.java:1272)

Which will span two nested transactions, one for the whole batch and one for adding one entity. The Entity provider javadoc says that only one transaction is used for the whole batch so I dont see what am I doing wrong hereā€¦

Thank you
Bruno

Hi I solved it with the following class:

package pt.app.main;

import com.vaadin.addon.jpacontainer.provider.jndijta.CachingBatchableEntityProvider;
import com.vaadin.addon.jpacontainer.provider.jndijta.JndiAddresses;
import javax.naming.InitialContext;
import javax.transaction.Status;
import javax.transaction.UserTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author brsantos
 * @param <T> entity class
 */
public class CachingBatchableProperEntityProvider<T> extends CachingBatchableEntityProvider<T>
{

    private static final Logger log = LoggerFactory.getLogger(CachingBatchableProperEntityProvider.class);

    public CachingBatchableProperEntityProvider(Class<T> entityClass)
    {
        super(entityClass);
    }

    public CachingBatchableProperEntityProvider(Class<T> entityClass, JndiAddresses addresses)
    {
        super(entityClass, addresses);
    }

    @Override
    protected void runInTransaction(Runnable operation)
    {
        try
        {
            UserTransaction utx = (UserTransaction) (new InitialContext()).lookup(getJndiAddresses().getUserTransactionName());
            try
            {
                if (utx.getStatus() == Status.STATUS_ACTIVE)
                {
                    operation.run();
                }
                else
                {
                    utx.begin();
                    operation.run();
                    utx.commit();
                }
            }
            catch (Exception e)
            {
                try
                {
                    utx.rollback();
                }
                catch (Exception e2)
                {
                    log.warn("Rollback failed", e2);
                }
                throw e;
            }
        }
        catch (Exception ex)
        {
            throw new RuntimeException(ex);
        }
    }

}

Thanx
Bruno