Hello all. I am trying to get XAResource recovery to work with JBoss JTA and ActiveMQ, with no success so far. The core of the problem seems to be this:
I cannot get the ActiveMQ JCA resource adaptor to bind an XAConnectionFactory instance to JNDI - no matter how I configure the resource adaptor, it always binds an instance of ActiveMQConnectionFactory, instead of ActiveMQXAConnectionFactory. It appears that many other users have raised this issue also, yet no-one seems to have provided a solution: http://www.nabble.com/XAConnectionFactory-td8445158.html http://www.nabble.com/JBoss-and-XAConnectionFactory-td16961291.html http://www.nabble.com/Using-JNDI-to-lookup-an-XAConnectionFactory-td10348154.html http://www.nabble.com/JNDI-activeMQ-and-XA-td16961307.html Perhaps if I explain why I think the XAConnectionFactory is required, someone might be able to show me how to get this binding? Alternatively, it would be great if someone could explain why it is not needed, or provide some other solution to getting full recoverable XA support with ActiveMQ and JBoss! Here is the backgound on where I am at and my workings so far. I apologise if this is a little long, but I want to be complete so other people can follow (and correct me if necessary!): 1. In order to support periodic recovery of aborted XA transactions, JBoss JTA (arjuna) requires a "recovery module" to be provided for each recoverable XA resource (e.g. datasources, JMS providers, etc) 2. To do this, I have edited the jboss/server/all/conf/jboss-jta-properties.xml file to include the following addtional line for ActiveMQ (in addition to the JBoss Messaging and datasource recovery modules, which I also need): <properties depends="arjuna" name="jta"> <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.AMQ" value="org.jboss.jms.server.recovery.MessagingXAResourceRecovery;java:/AMQProvider"/> <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.JBMESSAGING1" value="org.jboss.jms.server.recovery.MessagingXAResourceRecovery;java:/DefaultJMSProvider"/> <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.JDBC" value="com.arjuna.ats.internal.jbossatx.jta.AppServerJDBCXARecovery;DefaultDS"/> ... </properties> 3. This requires a corresponding JMSProviderLoader instance bound to java:/AMQProvider in JNDI. To do this, I have deployed the following mbean in the jboss/server/all/deploy/activemq-jms-ds.xml file: <!-- The JMS provider loader for ActiveMQ --> <mbean code="org.jboss.jms.jndi.JMSProviderLoader" name="jboss.jms:service=JMSProviderLoader,name=AMQProvider"> <attribute name="ProviderName">AMQProvider</attribute> <attribute name="ProviderAdapterClass"> org.jboss.jms.jndi.JNDIProviderAdapter </attribute> <!-- The combined connection factory --> <attribute name="FactoryRef">activemq/XAConnectionFactory</attribute> <!-- The queue connection factory --> <attribute name="QueueFactoryRef">activemq/XAConnectionFactory</attribute> <!-- The topic factory --> <attribute name="TopicFactoryRef">activemq/XAConnectionFactory</attribute> <!-- Access JMS via HAJNDI --> <attribute name="Properties"> java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=${jboss.bind.address:localhost}:1100 jnp.disableDiscovery=true jnp.partitionName=${jboss.partition.name:DefaultPartition} jnp.maxRetries=1 </attribute> </mbean> 4. This file also contains the connection factory deployment descriptor, which binds (or is supposed to!) the XAConnectionFactory instance to JNDI: <tx-connection-factory> <jndi-name>activemq/XAConnectionFactory</jndi-name> <use-java-context>false</use-java-context> <xa-transaction/> <track-connection-by-tx/> <rar-name>activemq-ra.rar</rar-name> <connection-definition>javax.jms.XAConnectionFactory</connection-definition> <min-pool-size>1</min-pool-size> <max-pool-size>200</max-pool-size> <blocking-timeout-millis>30000</blocking-timeout-millis> <idle-timeout-minutes>3</idle-timeout-minutes> <security-domain-and-application>JmsXARealm</security-domain-and-application> </tx-connection-factory> 5. In addition to the activemq-jms-ds.xml deployment descriptor, I also have the ActiveMQ JCA resource adaptor deployed as jboss/server/all/deploy/activemq-ra.rar in exploded form so I can edit the files. 6. I have modified jboss/server/all/deploy/activemq-ra.rar/META-INF/ra.xml to include the following additional lines in the <outbound-resourceadapter> section: <connection-definition> <managedconnectionfactory-class>org.apache.activemq.ra.ActiveMQManagedConnectionFactory</managedconnectionfactor y-class> <connectionfactory-interface>javax.jms.XAConnectionFactory</connectionfactory-interface> <connectionfactory-impl-class>org.apache.activemq.ra.ActiveMQXAConnectionFactory</connectionfactory-impl-class> <connection-interface>javax.jms.XAConnection</connection-interface> <connection-impl-class>org.apache.activemq.ra.ManagedConnectionProxy</connection-impl-class> </connection-definition> If my understanding is correct, this is all I should need to do to get an org.apache.activemq.ra.ActiveMQXAConnectionFactory instance bound in JNDI as activemq/XAConnectionFactory - yet for some reason I get a non-XA org.apache.activemq.ra.ActiveMQConnectionFactory instance instead! This is confirmed by the following exception, which occurs when JBoss JTA attempts to perform its periodic recovery: 08-12 17:40:36.250 DEBUG [ats.txoj.logging.txojLoggerI18N] (Thread-6:) [com.arjuna.ats.internal.txoj.recovery.TORecoveryModule_6] - TORecoveryModule - second pass 08-12 17:40:36.250 DEBUG [ats.jta.logging.loggerI18N] (Thread-6:) [com.arjuna.ats.internal.jta.recovery.info.secondpass] Local XARecoveryModule - second pass 08-12 17:40:36.250 ERROR [jms.server.recovery.MessagingXAResourceWrapper] (Thread-6:) ********************************Failed to connect to server java.lang.ClassCastException: Object at 'activemq/XAConnectionFactory' in context {java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.provider.url=192.168. 100.33:1100, jnp.disableDiscovery=true, jnp.partitionName=DefaultPartition, jnp.maxRetries=1, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces:org.jboss.naming:org.jnp.i nterfaces, hostKey=192.168.100.33:1100} is not an instance of [class=javax.jms.XAConnectionFactory classloader=org.jboss.mx.loading.unifiedclassload...@17ba38f{ url=null ,addedOrder=2} interfaces={}] object class is [class=org.apache.activemq.ra.ActiveMQConnectionFactory classloader=org.jboss.mx.loading.unifiedclassload...@16181be{ url=file:/C:/projects/ccs/jboss-eap- 4.3.0.GA/server/all/deploy/activemq-ra.rar/ ,addedOrder=29} interfaces={interface=javax.jms.ConnectionFactory classloader=org.jboss.mx.loading.unifiedclassload...@17ba38f{ url=null ,add edOrder=2}, interface=javax.jms.QueueConnectionFactory classloader=org.jboss.mx.loading.unifiedclassload...@17ba38f{ url=null ,addedOrder=2}, interface=javax.jms.TopicConnectionFactory classloader=org.jboss.mx.loading.unifiedclassload...@17ba38f{ url=null ,addedOrder=2}, interface=javax.resource.Referenceable classloader=org.jboss.mx.loading.unifiedclassload...@17ba38 f{ url=null ,addedOrder=2}, interface=java.io.Serializable classloader=null}] at org.jboss.util.naming.Util.checkObject(Util.java:329) at org.jboss.util.naming.Util.lookup(Util.java:216) at org.jboss.jms.server.recovery.MessagingXAResourceWrapper.getConnectionFactory(MessagingXAResourceWrapper.java:392) at org.jboss.jms.server.recovery.MessagingXAResourceWrapper.connect(MessagingXAResourceWrapper.java:338) at org.jboss.jms.server.recovery.MessagingXAResourceWrapper.getDelegate(MessagingXAResourceWrapper.java:260) at org.jboss.jms.server.recovery.MessagingXAResourceWrapper.recover(MessagingXAResourceWrapper.java:108) at com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule.xaRecovery(XARecoveryModule.java:746) at com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule.resourceInitiatedRecovery(XARecoveryModule.java:685) at com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule.periodicWorkSecondPass(XARecoveryModule.java:179) at com.arjuna.ats.internal.arjuna.recovery.PeriodicRecovery.doWork(PeriodicRecovery.java:237) at com.arjuna.ats.internal.arjuna.recovery.PeriodicRecovery.run(PeriodicRecovery.java:163) 08-12 17:40:36.250 WARN [ats.jta.logging.loggerI18N] (Thread-6:) [com.arjuna.ats.internal.jta.recovery.xarecovery1] Local XARecoveryModule.xaRecovery got XA exception javax.transactio n.xa.XAException: Error trying to connect to provider java:/AMQProvider, XAException.XAER_RMERR Notice this is a ClassCastException - the factory instance bound to activemq/XAConnectionFactory does not support the XAConnectionFactory interface, despite my <tx-connection-factory> deployment descriptor requesting it, and the <outbound-resourceadapter> defining one! I can confirm this by using the JMX console "JNDIView" to get a view of the JNDI tree. Here you can clearly see the wrong concrete class instance is bound: +- activemq (class: org.jnp.interfaces.NamingContext) | +- XAConnectionFactory (class: org.apache.activemq.ra.ActiveMQConnectionFactory) >From what I can tell, this behaviour is incorrect and is actually a bug in the ActiveMQ JCA resource adaptor - it does not seem to honour the <connectionfactory-impl-class> setting in the ra.xml file. (this is confirmed when I set the classname to a bogus value and no error was raised!). Alternatively, perhaps I am missing something? Is there some other way to get ActiveMQ to participate in JBoss JTA XAResource recovery? FYI, I have spent a couple of days on this problem now and am stumped! I can confirm the exact same behaviour exists with both ActiveMQ 4.1.1 and 5.2.0. Can anyone help me here? Many thanks! Scott