Strange behaviour running in WIldfly 10 with EmulatedXAResource


Andy
 
Edited

You are using a JEE connection pool but are setting the resource type as "local" hence DN will try to commit the connection (since it commits local things). Your connection (JBoss JCA) then throws an exception because it wants to commit things, maybe?. Use a local connection if using local ? But then I don't use JEE containers ...

You also have "datanucleus.connectionPoolingType" yet have already specified "connectionFactoryName" to be from JBoss. Either DataNucleus creates the connections to the datastore or JBoss does, but you can't have both, clearly.


ebenzacar@...
 

I'm encountering a strange behaviour for which I have not been able to pinpoint the cause and was hoping that someone could help point me in the right direction.

I have an application running under  JBoss EAP 7.0 (Wildfly 10), but only having the datasource specified at the container level.  I am trying to fully manage the JDOPersistenceFactory from within the JEE (EJB) application.

My persistence.xml is configured as follows (located in my EJB jar in the META-INF/ folder:
<persistence-unit name="cache" transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>java:jboss/datasources/DS</non-jta-data-source>
<mapping-file>package.jdo</mapping-file>
<exclude-unlisted-classes/>
<properties>
<property name="datanucleus.connection.resourceType" value="RESOURCE_LOCAL"/>
<property name="datanucleus.transaction.type" value="RESOURCE_LOCAL"/>
<property name="datanucleus.storeManagerType" value="rdbms"/>
<property name="datanucleus.schema.autoCreateAll" value="false"/>
<property name="datanucleus.ConnectionFactoryName" value="java:jboss/datasources/DS"/>

<property name="datanucleus.connectionPoolingType" value="dbcp2-builtin"/>
</properties>
</persistence-unit>

I have instantiated my connection factory statically as follows:
public class DataNucleusPersistenceManagerFactory {

// hack to provide access to the pmfs from a static context
private static Map<PersistenceUnit, PersistenceManagerFactory> pmf = new ConcurrentHashMap<>();

static{
PersistenceManagerFactory persistenceManagerFactory = JDOHelper.getPersistenceManagerFactory("cache");
pmf.put(PersistenceUnit.CACHE, persistenceManagerFactory);
}

/**
* Retrieve PersistenceManagerFactory from legacy code
* @param type
* @return
*/
public static PersistenceManagerFactory getPersistenceManagerFactory( PersistenceUnit type){
return pmf.get(type);
}


All my Stateless EJBs are defined as BeanManagedTransactions by extending a base class with the following interceptor defined:
@TransactionManagement(TransactionManagementType.BEAN)
public class BaseManagerBean implements BaseManager {

PersistenceManager pm;

@AroundInvoke
public Object log(InvocationContext inv) throws Exception {
pm =
DataNucleusPersistenceManagerFactory.getPersistenceManagerFactory( CACHE );
pm.begin();

Object ret = inv.proceed();
pm.commit();

}

}

This allows for the logic for my bean method to simply use the pm within its logic without needing to worry about transaction boundaries/etc.  I have simplified the interceptor for illustration purposes.

My issue that I am encountering is when I have nested EJBs (ie: one EJB which calls another).  In this context, I end up with nested transactions, since each EJB method call will create a new PM and manage its own transaction.

When this happens, the inner transaction completes successfully, but the outer one throws and exception that:

Caused by: java.sql.SQLException: IJ031019: You cannot commit during a managed transaction
        at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:1063)
        at org.jboss.jca.adapters.jdbc.WrappedConnection.commit(WrappedConnection.java:834)
        at org.datanucleus.store.rdbms.ConnectionFactoryImpl$EmulatedXAResource.commit(ConnectionFactoryImpl.java:734)
        at org.datanucleus.transaction.ResourcedTransaction.commit(ResourcedTransaction.java:348)
        at org.datanucleus.transaction.ResourcedTransactionManager.commit(ResourcedTransactionManager.java:64)
        at org.datanucleus.TransactionImpl.internalCommit(TransactionImpl.java:417)
        at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:288)
        at org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:99)
        ... 128 more
 


Stepping through the code, falling into the IronJacamar libraries, I see that the ConnectionWrappers are treating this as an XA transaction.  I also see that from the `org.datanucleus.store.rdbms.ConnectionFactoryImpl$EmulatedXAResource` resource which the DN CF creates.

This is where I get confused.  I'm not sure why this is happening, nor if this is "normal"/expected behaviour.  I have tried to reproduce this in a small test application by embedding 2 txs, with the same PU defined, but it works properly there.  I have not yet tried embedding two EJBs in a test application.

I can only suspect that I have an errant configuration somewhere which is causing this, but cannot identify what.  My Datasource is configured the same for my test application.  Just for reference:

<datasource jndi-name="java:jboss/datasources/DS" pool-name="DS" enabled="true">
<
connection-url>jdbc:sqlserver://${db.tx.host};databaseName=${adams.db.tx.name}</connection-url>
<
driver>sqlserver</driver>
<
pool>
<
min-pool-size>5</min-pool-size>
<
max-pool-size>2000</max-pool-size>
</
pool>
<
security>
<
user-name>${adams.db.tx.username}</user-name>
<
password>${adams.db.tx.password}</password>
</
security>
<
validation>
<
check-valid-connection-sql>select getdate()</check-valid-connection-sql>
</
validation>
</
datasource>
<drivers> <driver name="sqlserver" module="com.microsoft.sqlserver"> <xa-datasource-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</xa-datasource-class> </driver> </drivers>


What am I missing, doing wrong?  Do I have a incorrect or missing configuration?  What is  DN / WF seeing this as an XA transaction?  Or is this expected behaviour when working with nested EJBs due to the inherent stateless / pooling behaviour of EJBs?  If the latter, am I forced to move to Container Managed Transactions such that no bean commits its own transaction?  If not, how would I know which transaction is the outer transaction?

Thanks for any insights.

Eric