# XA Recovery Example

This example will show how to configure HornetQ 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.

## Example configuration

To run the example, you need to download JBoss AS 5.x and create a configuration for HornetQ.

You also need to configure JBoss Transactions to enable XA Recovery of HornetQ resources

### JBoss AS configuration

Please refer to HornetQ Quickstart guide to install it in JBoss AS 5

### XA Recovery configuration

You need to enable XA Recovery of HornetQ resources.

In the `jta` section of the `$JBOSS_HOME/server/xarecovery-example-profile//conf/jbossts-properties.xml` configuration file, the following property is added:

             <property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.HORNETQ1"
                          value="org.hornetq.jms.server.recovery.HornetQXAResourceRecovery;org.hornetq.core.remoting.impl.invm.InVMConnectorFactory"/>

This informs the Recovery Manager that it can recovers HornetQ XA Resources by connecting to the server using an `InVMConnectorFactory`. Since the Recovery Manager is in the same server than HornetQ, the examples uses intra-vm communication to recover the messaging resources. HornetQ must have configured an invm acceptor to accept this connection (see the "in-vm"`<acceptor>` in `hornetq-configuration.xml`).

The example copies a `jbossts-properties.xml` already configured for HornetQ XA Recovery, so you do not need to manually edit the profile's file.

## Example step-by-step

You need to deploy the example before starting the server, simply type `./build.sh deploy` (or `build.bat deploy` on windows) from this directory
Once the example is deployed in JBoss AS 5, simply type `./build.sh run` (or `build.bat run` on windows) to start the example.
This will crash the server: when informed, simply type `./build.sh restart` (or `build.bat restart` on windows) in the terminal where you deployed the example to restart the server.
Type `./build.sh undeploy` (or `build.bat undeploy` on windows) to undeploy the example from JBoss AS 5.

The example code is composed of 2 main classes:

`XARecoveryExample`
  the client application to invoke the EJB and receive the message
`XARecoveryExampleBean`
  a Stateless EJB

### Example Application

Let's take a look at XARecoveryExample first.

1. First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the jndi.properties

                 InitialContext initialContext = new InitialContext();

2. We look up the EJB

                 XARecoveryExampleService service = (XARecoveryExampleService)initialContext.lookup("mdb-example/XARecoveryExampleBean/remote");

3. We invoke the EJB's `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 `./build.sh restart` (or `build.bat restart` on windows) in the terminal where you typed `./build.sh deploy` (or `build.bat deploy` on windows)

4. We will try to receive a message. Once the server is restarted, the message will be recovered and the consumer will receive it

                   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.

5. And finally, always remember to close your resources after use, in a `finally` block.

                 finally
                 {
                    if (initialContext != null)
                    {
                      initialContext.close();
                    }
                 }

### EJB Example

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.

1. First, we create a new initial context

                 ic = new InitialContext();

2. We look up the Transaction Manager

                 TransactionManager tm = (TransactionManager)ic.lookup("java:/TransactionManager");

3. We look up the JMS XA Connection Factory (which is bound to `java:/JmsXA`)

                 XAConnectionFactory cf = (XAConnectionFactory)ic.lookup("java:/XAConnectionFactory");

4. We look up the JMS Queue

                 Queue queue = (Queue)ic.lookup("queue/testQueue");

5. We create a JMS XA connection, a XA session and a message producer for the queue

                 xaConnection = xacf.createXAConnection();
                 XASession session = xaConnection.createXASession();
                 MessageProducer messageProducer = session.createProducer(queue);

6. We create a text message with the text passed in parameter of the EJB method

                 TextMessage message = session.createTextMessage(text);

7. We create a `FailingXAResource`. For this example purpose, this XAResource implementation will call `Runtime.halt()` from its `commit()` method

                 XAResource failingXAResource = new FailingXAResource();

8. We begin the transaction and retrieve it from the transaction manager

                 tm.begin();
                 Transaction tx = tm.getTransaction();

9. We enlist the failing XAResource

                 tx.enlistResource(failingXAResource);

10. We enlist the JMS XA Resource

                 tx.enlistResource(session.getXAResource());

11. We create a text message with the text passed in parameter of the EJB method and send it

                 TextMessage message = session.createTextMessage(text);
                 messageProducer.send(message);
                 System.out.format("Sent message: %s (%s)\n", message.getText(), message.getJMSMessageID());

12. We delist the failing XAResource

                 tx.delistResource(failingXAResource);

13. We delist the JMS XA Resource

                 tx.delistResource(session.getXAResource());

14. We commit the transaction

                 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, HornetQ resources will be scanned and the prepared transaction will be recovered and committed. It is then possible to consume this message

## More information

- HornetQ installation in JBoss AS 5
- HornetQ XA Recovery configuration in JBoss AS 5
- JBoss Transactions