jdbcjbossjbpmjboss-webredhat-bpm

XA Transaction broken in jBPM+jBoss during Oracle to SQL Server migration


Recently started a migration of a large Java EE application from Oracle 12c to MS SQL Server 2016. Most functionality has been smoke tested to work OK including the Quartz Scheduler, basic JMS functions, Hibernate and EJBs working ok, etc. One weird issue has stalled progress so hoping someone might have a suggestion.

The jBPM console works to be able to log in and start/suspend/stop tasks. There is an situation that always triggers an error. The jBPM task can be signaled from with the console and it starts perfectly, but once the first task is finished and the application code tries to signal the token to move to the next task, the code always crashes with an error.

This code was working of course connected to Oracle with the xa-datasource configured.

The error: (full stacktrace)

2017-10-13 16:03:31,463 [WorkManager(2)-19] DEBUG [org.hibernate.jdbc.ConnectionManager] opening JDBC connection
2017-10-13 16:03:31,464 [WorkManager(2)-19] DEBUG [org.hibernate.util.JDBCExceptionReporter] Cannot open connection [???]
org.jboss.util.NestedSQLException: Transaction is not active: tx=TransactionImple < ac, BasicAction: -71740de1:d47b:59e10d94:f5 status: ActionStatus.ABORT_ONLY >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: -71740de1:d47b:59e10d94:f5 status: ActionStatus.ABORT_ONLY >)
    at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:95)
    at org.hibernate.connection.DatasourceConnectionProvider.getConnection(DatasourceConnectionProvider.java:69)
    at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
    at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:144)
    at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:139)
    at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1547)
    at org.hibernate.loader.Loader.doQuery(Loader.java:673)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:1860)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:48)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:42)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3044)
    at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:395)
    at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:375)
    at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:139)
    at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:195)
    at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:103)
    at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
    at org.hibernate.impl.SessionImpl.get(SessionImpl.java:815)
    at org.hibernate.impl.SessionImpl.get(SessionImpl.java:808)
    at org.jbpm.db.GraphSession.getToken(GraphSession.java:338)
    at org.jbpm.JbpmContext.getToken(JbpmContext.java:286)
    at ca.gnb.medicare.process.handling.ProcessUtilBean.signal(ProcessUtilBean.java:47)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
    at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
    at ca.gnb.medicare.service.interceptors.PeristenceContextInterceptor.intercept(PeristenceContextInterceptor.java:41)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:118)
    at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:79)
    at org.jboss.aspects.tx.TxInterceptor$RequiresNew.invoke(TxInterceptor.java:253)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:95)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
    at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:110)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:240)
    at org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:210)
    at org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalProxy.java:84)
    at com.sun.proxy.$Proxy155.signal(Unknown Source)
    at ca.gnb.medicare.service.util.AbstractServiceActivator.onMessage(AbstractServiceActivator.java:143)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
    at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
    at ca.gnb.medicare.service.interceptors.PeristenceContextInterceptor.intercept(PeristenceContextInterceptor.java:41)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:118)
    at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:126)
    at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:195)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    at org.jboss.ejb3.mdb.MessagingContainer.localInvoke(MessagingContainer.java:249)
    at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.delivery(MessageInflowLocalProxy.java:268)
    at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.invoke(MessageInflowLocalProxy.java:138)
    at com.sun.proxy.$Proxy169.onMessage(Unknown Source)
    at org.jboss.resource.adapter.jms.inflow.JmsServerSession.onMessage(JmsServerSession.java:178)
    at org.jboss.mq.SpyMessageConsumer.sessionConsumerProcessMessage(SpyMessageConsumer.java:906)
    at org.jboss.mq.SpyMessageConsumer.addMessage(SpyMessageConsumer.java:170)
    at org.jboss.mq.SpySession.run(SpySession.java:323)
    at org.jboss.resource.adapter.jms.inflow.JmsServerSession.run(JmsServerSession.java:237)
    at org.jboss.resource.work.WorkWrapper.execute(WorkWrapper.java:204)
    at org.jboss.util.threadpool.BasicTaskWrapper.run(BasicTaskWrapper.java:275)
    at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(PooledExecutor.java:756)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: -71740de1:d47b:59e10d94:f5 status: ActionStatus.ABORT_ONLY >
    at org.jboss.resource.connectionmanager.TxConnectionManager.getManagedConnection(TxConnectionManager.java:319)

I cannot think of how SQL Server affects the transaction.

We also get this error on SQL Server: (full sql dump)

2017-10-11 13:10:53.44 spid61      ***Stack Dump being sent to G:\MedSt\MSSQL13.MEDST\MSSQL\LOG\SQLDump0032.txt
2017-10-11 13:10:53.44 spid61      SqlDumpExceptionHandler: Process 61 generated fatal exception c0000005 EXCEPTION_ACCESS_VIOLATION. SQL Server is terminating this process.
2017-10-11 13:10:54.15 spid61      External dump process return code 0x20000001.
External dump process returned no errors.

2017-10-11 13:10:54.15 spid61      Error: 18002, Severity: 20, State: 1.
2017-10-11 13:10:54.15 spid61      Exception happened when running extended stored procedure 'xp_sqljdbc_xa_start' in the library 'SQLJDBC_XA.dll'. SQL Server is terminating process 61. Exception type: Win32 exception; Exception code: 0xc0000005. 

Code that triggers the error:

@Stateless
public class ProcessUtilBean implements ProcessUtil{

    private static Logger log = Logger.getLogger();
    @EJB DecrementWorkCounter decrementWorkCounter;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void signal(long tokenId){

        JbpmContext context = null;

        try {
            context = getJbpmContext();

            log.info("attempting to get token (" + tokenId + ")");
            Token token;

            token = context.getToken(tokenId);

            token.signal(); // <-- triggers error

        } catch (Exception e) {
            e.printStackTrace();
            log.severe("Error signalling process " + e.getMessage());
        } finally {
            context.close();
        }

    }

There are of course several tons of XML, but I've changed very little. Basically just the datasources have changed, SQL Dialect and copied over the mssql-jdbc2-service.xml from the jboss examples folder.

Here is the jms-ds.xml seeing as the errors somewhat indicate an issue here with JMS:

<?xml version="1.0" encoding="UTF-8"?>
<connection-factories>
  <!-- The JMS provider loader -->
  <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
     name="jboss.mq:service=JMSProviderLoader,name=JMSProvider">
    <attribute name="ProviderName">DefaultJMSProvider</attribute>
    <attribute name="ProviderAdapterClass">
      org.jboss.jms.jndi.JNDIProviderAdapter
    </attribute>
    <!-- The combined connection factory -->
    <attribute name="FactoryRef">java:/XAConnectionFactory</attribute>
    <!-- The queue connection factory -->
    <attribute name="QueueFactoryRef">java:/XAConnectionFactory</attribute>
    <!-- The topic factory -->
    <attribute name="TopicFactoryRef">java:/XAConnectionFactory</attribute>
  </mbean>

  <!-- The server session pool for Message Driven Beans -->
  <mbean code="org.jboss.jms.asf.ServerSessionPoolLoader"
     name="jboss.mq:service=ServerSessionPoolMBean,name=StdJMSPool">
    <depends optional-attribute-name="XidFactory">jboss:service=XidFactory</depends>
    <attribute name="PoolName">StdJMSPool</attribute>
    <attribute name="PoolFactoryClass">
      org.jboss.jms.asf.StdServerSessionPoolFactory
    </attribute>
  </mbean>

  <!-- JMS XA Resource adapter, use this to get transacted JMS in beans -->
  <tx-connection-factory>
    <jndi-name>JmsXA</jndi-name>
    <xa-transaction/>
    <rar-name>jms-ra.rar</rar-name>
    <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
    <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
    <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/DefaultJMSProvider</config-property>
    <security-domain-and-application>JmsXARealm</security-domain-and-application>
    <max-pool-size>20</max-pool-size>
  </tx-connection-factory>

</connection-factories>

Versions:

(I know someone will comment, so yes, these are all schedule to be upgraded)

SQL drivers tried so far:

If I've missed something important, I'll add it.

** edit **

Finally got some more information from sql driver.

2017-10-18 14:03:31,096 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSReader readBytes 
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad) Reading 44 bytes from offset 334
2017-10-18 14:03:31,098 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSParser parse
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad): logon: Processing TDS_ENV_CHG (0xE3)
2017-10-18 14:03:31,098 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSReader mark
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad): Buffering from: com.microsoft.sqlserver.jdbc.TDSReaderMark@6b6611f0
2017-10-18 14:03:31,098 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSReader readBytes
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad) Reading 8 bytes from offset 387
2017-10-18 14:03:31,099 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerConnection processEnvChange
FINER: ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad Network packet size is 8000 bytes
2017-10-18 14:03:31,099 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSReader reset
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad): Resetting to: com.microsoft.sqlserver.jdbc.TDSReaderMark@6b6611f0
2017-10-18 14:03:31,099 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSReader readBytes
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad) Reading 19 bytes from offset 385
2017-10-18 14:03:31,099 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSParser parse
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad): logon: Processing TDS_DONE (0xFD)
2017-10-18 14:03:31,099 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.TDSParser parse
FINEST: TDSReader@370 (ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad): logon: Processing EOF
2017-10-18 14:03:31,100 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerConnection connectInternal
FINER: ConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad End of connect
2017-10-18 14:03:31,100 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerXAConnection <init>
FINER: Created an internal control connectionConnectionID:166 ClientConnectionId: a62ad6a5-19e4-4187-83f5-c60a6bb1aaad for SQLServerXAConnection:81 Physical connection:ConnectionID:165 ClientConnectionId: 78fd8cb2-78ff-44d7-9cae-e20e6256b37e
2017-10-18 14:03:31,100 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerXAConnection <init>
FINER: SQLServerXADataSource:1 user:MEDST3
2017-10-18 14:03:31,100 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerXADataSource getXAConnection
FINER: SQLServerXADataSource:1 user:MEDST3SQLServerXAConnection:81
2017-10-18 14:03:31,100 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerXADataSource getXAConnection
FINER: SQLServerXADataSource:1 Start get physical connection.
2017-10-18 14:03:31,100 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerXADataSource getXAConnection
FINE: SQLServerXADataSource:1 End get physical connection, ConnectionID:165 ClientConnectionId: 78fd8cb2-78ff-44d7-9cae-e20e6256b37e
2017-10-18 14:03:31,100 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerXADataSource:1 getXAConnection
FINER: RETURN SQLServerXAConnection:81
2017-10-18 14:03:31,101 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerPooledConnection getConnection
FINER: SQLServerXAConnection:81 user:(default).
2017-10-18 14:03:31,101 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerPooledConnection getConnection
FINE: SQLServerXAConnection:81 Physical connection, ConnectionID:165 ClientConnectionId: 78fd8cb2-78ff-44d7-9cae-e20e6256b37e
2017-10-18 14:03:31,098 [main] TRACE [org.jboss.web.tomcat.service.WebAppClassLoader] filter name=ca.gnb.medicare.application.claim.manage.SelectServiceProvider$1, exclude=false
2017-10-18 14:03:31,101 [main] DEBUG [org.apache.catalina.loader.WebappClassLoader]   Searching local repositories
2017-10-18 14:03:31,101 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerPooledConnection getConnection
FINE: SQLServerXAConnection:81 proxy  ProxyConnectionID:81 is returned.
2017-10-18 14:03:31,101 [main] TRACE [org.jboss.web.tomcat.service.WebAppClassLoader] findClass(ca.gnb.medicare.application.claim.manage.SelectServiceProvider$1) called
2017-10-18 14:03:31,101 [main] DEBUG [org.apache.catalina.loader.WebappClassLoader]     findClass(ca.gnb.medicare.application.claim.manage.SelectServiceProvider$1)
2017-10-18 14:03:31,101 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerConnection:165 getTransactionIsolation
FINER: ENTRY
2017-10-18 14:03:31,101 [main] TRACE [org.apache.catalina.loader.WebappClassLoader]       findClassInternal(ca.gnb.medicare.application.claim.manage.SelectServiceProvider$1)
2017-10-18 14:03:31,101 [WorkManager(2)-19] INFO  [org.hibernate.impl.SessionFactoryImpl] building session factory
2017-10-18 14:03:31,101 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerConnection:165 getTransactionIsolation
FINER: RETURN 2 (this is = TRANSACTION_READ_COMMITTED) https://docs.oracle.com/javase/7/docs/api/constant-values.html#java.sql
2017-10-18 14:03:31,101 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerConnection:165 isReadOnly
FINER: ENTRY
2017-10-18 14:03:31,101 [WorkManager(2)-19] DEBUG [org.hibernate.impl.SessionFactoryImpl] Session factory constructed with filter configurations : {}
2017-10-18 14:03:31,101 [JCA PoolFiller] ERROR [STDERR] Oct 18, 2017 2:03:31 PM com.microsoft.sqlserver.jdbc.SQLServerConnection:165 isReadOnly
FINER: RETURN false

Solution

  • **EDIT Response from Microsoft:

    Upon checking with my escalation we found that timeout value basically range a integer value which is basically a unsigned short.

    So the maximum XA Timeout value is 65,535.

    ** /EDIT

    So the issue to this specific issue turns out to be an overly high timeout value.

    Either the original devs thought 333.33 hours was needed for batch processing or they just picked the number 1,200,000 seconds by random. Oracle didn't care. SQL Server SQLJDBC_XA.DLL does. I haven't found a documented maximum yet, but lowering the value solves the issue.

    I've reposted the complete example code from here for completeness, but it's the 1,200,000 value here that is the culprit:

    @PoolClass(value=org.jboss.ejb3.StrictMaxPool.class, maxSize=20, timeout=1200000)
    @MessageDriven(
        mappedName=ClaimsBatchInstigatorBean.QUEUE_NAME,
        activationConfig={
            @ActivationConfigProperty(
                propertyName="destination",
                propertyValue=ClaimsBatchInstigatorBean.QUEUE_NAME
            ),
            @ActivationConfigProperty(
                propertyName="destinationType",
                propertyValue="javax.jms.Queue"
            ),
            @ActivationConfigProperty(
                propertyName = "transactionTimeout",
                propertyValue = "1200000"
            ),
            @ActivationConfigProperty(
                    propertyName="maxSession",
                    propertyValue="15"
            )
        }
    )
    

    Minimal code to reproduce:

    package com.******.test;
    
    import java.net.Inet4Address;  
    import java.sql.*;  
    import java.util.Random;
    import javax.transaction.xa.*;  
    import javax.sql.*;  
    import com.microsoft.sqlserver.jdbc.*;  
    
    public class testXA {  
    
       public static void main(String[] args) throws Exception {  
    
          // Create variables for the connection string.  
          String prefix = "jdbc:sqlserver://";  
          String serverName = "******";  
          int portNumber = ******;  
          String databaseName = "******";   
          String user = "******";   
          String password = "******";  
          String connectionUrl = prefix + serverName + ":" + portNumber  
             + ";databaseName=" + databaseName + ";user=" + user + ";password=" + password;  
    
          try {  
             // Establish the connection.  
             Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  
             Connection con = DriverManager.getConnection(connectionUrl);  
    
             // Create a test table.  
             Statement stmt = con.createStatement();  
             try {  
                stmt.executeUpdate("DROP TABLE XAMin");   
             }  
             catch (Exception e) {  
             }  
             stmt.executeUpdate("CREATE TABLE XAMin (f1 int, f2 varchar(max))");  
             stmt.close();  
             con.close();  
    
             // Create the XA data source and XA ready connection.  
             SQLServerXADataSource ds = new SQLServerXADataSource();  
             ds.setUser(user);  
             ds.setPassword(password);  
             ds.setServerName(serverName);  
             ds.setPortNumber(portNumber);  
             ds.setDatabaseName(databaseName);  
             XAConnection xaCon = ds.getXAConnection();  
             con = xaCon.getConnection();  
             con.setAutoCommit(false);
    
             // Get a unique Xid object for testing.  
             XAResource xaRes = null;  
             Xid xid = null;  
             xid =  XidImpl.getUniqueXid(1);
    
             // Get the XAResource object and set the timeout value.  
             xaRes = xaCon.getXAResource();  
    
             //  xaRes.setTransactionTimeout(0);   <-- no error
             //  xaRes.setTransactionTimeout(30000);   <-- no error
             xaRes.setTransactionTimeout(1200000);   //<--- error!
    
    
             // Perform the XA transaction.  
             System.out.println("Write -> xid = " + xid.toString());  
             xaRes.start(xid,XAResource.TMNOFLAGS);  
             PreparedStatement pstmt =   
             con.prepareStatement("INSERT INTO XAMin (f1,f2) VALUES (?, ?)");  
             pstmt.setInt(1,1);  
             pstmt.setString(2,xid.toString());  
             pstmt.executeUpdate();  
    
             // Commit the transaction.  
             xaRes.end(xid,XAResource.TMSUCCESS);  
             xaRes.commit(xid,true);  
    
             // Cleanup.  
             con.close();  
             xaCon.close();  
    
             // Open a new connection and read back the record to verify that it worked.  
             con = DriverManager.getConnection(connectionUrl);  
             ResultSet rs = con.createStatement().executeQuery("SELECT * FROM XAMin");  
             rs.next();  
             System.out.println("Read  -> xid = " + rs.getString(2));  
             rs.close();  
             con.close();  
          }   
    
          // Handle any errors that may have occurred.  
          catch (Exception e) {  
             e.printStackTrace();  
          }  
       }  
    }  
    
    class XidImpl implements Xid {  
    
       public int formatId;  
       public byte[] gtrid;  
       public byte[] bqual;  
       public byte[] getGlobalTransactionId() {return gtrid;}  
       public byte[] getBranchQualifier() {return bqual;}  
       public int getFormatId() {return formatId;}  
    
       XidImpl(int formatId, byte[] gtrid, byte[] bqual) {  
          this.formatId = formatId;  
          this.gtrid = gtrid;  
          this.bqual = bqual;  
       }  
    
       public String toString() {  
          int hexVal;  
          StringBuffer sb = new StringBuffer(512);  
          sb.append("formatId=" + formatId);  
          sb.append(" gtrid(" + gtrid.length + ")={0x");  
          for (int i=0; i<gtrid.length; i++) {  
             hexVal = gtrid[i]&0xFF;  
             if ( hexVal < 0x10 )  
                sb.append("0" + Integer.toHexString(gtrid[i]&0xFF));  
             else  
                sb.append(Integer.toHexString(gtrid[i]&0xFF));  
             }  
             sb.append("} bqual(" + bqual.length + ")={0x");  
             for (int i=0; i<bqual.length; i++) {  
                hexVal = bqual[i]&0xFF;  
                if ( hexVal < 0x10 )  
                   sb.append("0" + Integer.toHexString(bqual[i]&0xFF));  
                else  
                   sb.append(Integer.toHexString(bqual[i]&0xFF));  
             }  
             sb.append("}");  
             return sb.toString();  
          }  
    
          // Returns a globally unique transaction id.  
          static byte [] localIP = null;  
          static int txnUniqueID = 0;  
          static Xid getUniqueXid(int tid) {  
    
          Random rnd = new Random(System.currentTimeMillis());  
          txnUniqueID++;  
          int txnUID = txnUniqueID;  
          int tidID = tid;  
          int randID = rnd.nextInt();  
          byte[] gtrid = new byte[64];  
          byte[] bqual = new byte[64];  
          if ( null == localIP) {  
             try {  
                localIP = Inet4Address.getLocalHost().getAddress();  
             }  
             catch ( Exception ex ) {  
                localIP =  new byte[] { 0x01,0x02,0x03,0x04 };  
             }  
          }  
          System.arraycopy(localIP,0,gtrid,0,4);  
          System.arraycopy(localIP,0,bqual,0,4);  
    
          // Bytes 4 -> 7 - unique transaction id.  
          // Bytes 8 ->11 - thread id.  
          // Bytes 12->15 - random number generated by using seed from current time in milliseconds.  
          for (int i=0; i<=3; i++) {  
             gtrid[i+4] = (byte)(txnUID%0x100);  
             bqual[i+4] = (byte)(txnUID%0x100);  
             txnUID >>= 8;  
             gtrid[i+8] = (byte)(tidID%0x100);  
             bqual[i+8] = (byte)(tidID%0x100);  
             tidID >>= 8;  
             gtrid[i+12] = (byte)(randID%0x100);  
             bqual[i+12] = (byte)(randID%0x100);  
             randID >>= 8;  
          }  
          return new XidImpl(0x20003, gtrid, bqual);  
       }  
    }