This example will show how to configure JBoss Messaging XA recovery in JBoss AS (Application Server).
The example application will invoke an EJB which will send a JMS message in a transaction.
The server will crash while the transaction has not been committed (it is in the prepared state).
On server restart, the transaction will be recovered and the JMS message will finally be sent.
The example application will then receive the message.
To run the example, you need to download JBoss AS 5.x and create a configuration for JBoss Messaging.
You also need to configure JBoss Transactions to enable XA Recovery of JBoss Messaging resources
Please refer to JBoss Messaging Quickstart guide to install it in JBoss AS 5
You need to enable XA Recovery of JBoss Messaging resources.
In the jta
section of the $JBOSS_HOME/server/default-with-jbm2/conf/jbossts-properties.xml
configuration file, the following property
is added:
<property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.JBMESSAGING1"
value="org.jboss.messaging.jms.server.recovery.MessagingXAResourceRecovery;java:/XAConnectionFactory"/>
This informs the Recovery Manager that it can recovers JBoss Messaging XA Resources using the XAConnectionFactory
bound to java:/XAConnectionFactory
in JNDI
(as it is configured in jbm-jms.xml which will be deployed to $JBOSS_HOME/server/default-with-jbm2/deploy/messaging.sar/
).
The example copies a jbossts-properties.xml
already configured for JBoss Messaging XA Recovery, so you
do not need to manually edit the profile's file.
You need to deploy the example before starting the server, type ant deploy
from this directory
Once the example is deployed in JBoss AS 5, type ant run
to start the example.
This will crash the server: when informed, type ant restart
in the terminal where you deployed the example
to restart the server.
Type ant undeploy
to undeploy the example from JBoss AS 5.
XARecoveryExample
XARecoveryExampleBean
Let's take a look at XARecoveryExample first.
InitialContext initialContext = new InitialContext();
XARecoveryExampleService service = (XARecoveryExampleService)initialContext.lookup("mdb-example/XARecoveryExampleBean/remote");
send
method. This method will send a JMS text message (with the text passed in parameter)
and crash the server when committing the transaction
String message = "This is a text message sent at " + new Date();
System.out.println("invoking the EJB service with text: " + message);
try
{
service.send(message);
}
catch (Exception e)
{
System.out.println("#########################");
System.out.println("The server crashed: " + e.getMessage());
System.out.println("#########################");
}
At that time, the server is crashed and must be restarted by typing ant restart
in the terminal where you typed ant deploy
boolean received = false;
while (!received)
{
try
{
Thread.sleep(15000);
receiveMessage();
received = true;
}
catch (Exception e)
{
System.out.println(".");
}
}
The receiveMessage()
method contains code to receive a text message from the
JMS Queue and display it.
finally
block.
finally
{
if (initialContext != null)
{
initialContext.close();
}
}
Let's now take a look at the EJB example
In order to crash the server while a transaction is prepared, we will use a failing XAResource
which will crash the server (calling Runtime.halt()
) in its commit phase.
We will manage ourselves the transaction and its resources enlistment/delistment to be sure that the failing XAResource will crash the server after the JMS XA resources is prepared but before it is committed.
ic = new InitialContext();
TransactionManager tm = (TransactionManager)ic.lookup("java:/TransactionManager");
java:/JmsXA
)
XAConnectionFactory cf = (XAConnectionFactory)ic.lookup("java:/XAConnectionFactory");
Queue queue = (Queue)ic.lookup("queue/testQueue");
xaConnection = xacf.createXAConnection();
XASession session = xaConnection.createXASession();
MessageProducer messageProducer = session.createProducer(queue);
TextMessage message = session.createTextMessage(text);
FailingXAResource
. For this example purpose, this XAResource implementation will
call Runtime.halt()
from its commit()
method
XAResource failingXAResource = new FailingXAResource();
tm.begin();
Transaction tx = tm.getTransaction();
tx.enlistResource(failingXAResource);
tx.enlistResource(session.getXAResource());
TextMessage message = session.createTextMessage(text);
messageProducer.send(message);
System.out.format("Sent message: %s (%s)\n", message.getText(), message.getJMSMessageID());
tx.delistResource(failingXAResource);
tx.delistResource(session.getXAResource());
System.out.println("committing the tx");
tx.commit();
When the transaction is committed, it will prepare both XAResources and then commit them.
The failing resources will crash the server leaving the JMS XA Resource prepared but not committed
You now need to restart the JBoss AS instance.
When it is restarted, it will automatically trigger a recovery phase. During that phase, JBoss Messaging resources will be
scanned and the prepared transaction will be recovered and committed. It is then possible to consume this message