EJB/JMS Transaction Example

The example application will invoke an EJB which is deployed within WildFly which will:

  1. start an XA transaction
  2. send a JMS message
  3. update an in-memory database
  4. commit the transaction

The example application will then receive the message sent by the EJB.

WildFly configuration

The example leverages the Arquillian framework to run a WildFly instance and deploy the MDB.

Example step-by-step

download WildFly 8.0.0.Final from here and install.

set the JBOSS_HOME property to point to the WildFly install directory

type mvn verify from the example directory to run

The example code is composed of two main classes:

Example Application

Let's take a look at EJBClientExample first.

  1. First we need to get an initial context so we can look-up the EJB. This initial context will get it's properties from the jboss-ejb-client.properties.
  2.             Properties env = new Properties();
                env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                InitialContext initialContext = new InitialContext();
             
  3. We look up the EJB
  4.             SendMessageService service = (SendMessageService) initialContext.lookup("ejb:/test//SendMessageBean!org.apache.activemq.javaee.example.server.SendMessageService");
             
  5. We create the DB table which will be updated if it does not already exist
  6.             service.createTable();
             
  7. We invoke the EJB's sendAndUpdate method. This method will send a JMS text message (with the text passed in parameter) and insert a row in the database table with the text and the message's JMS Message ID
  8.             service.sendAndUpdate("This is a text message");
             

    We will now consume the JMS message which was sent by the EJB at step 4.

  9. We need to get a new initial context so we can look-up the JMS connection factory and destination objects from JNDI.
  10.             env = new Properties();
                env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
                env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
                initialContext = new InitialContext(env);
             
  11. We look up the JMS connection factory
  12.             ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("jms/RemoteConnectionFactory");
             
  13. We lookup the JMS queue
  14.             Queue queue = (Queue)initialContext.lookup("jms/queues/testQueue");
             
  15. We create a connection, a session and a message consumer for the queue
  16.             connection = cf.createConnection("guest", "password");
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageConsumer consumer = session.createConsumer(queue);
             
  17. We start the JMS connection
  18.             connection.start();
             
  19. We receive a message from the queue. It corresponds to the message sent by the EJB
  20.             TextMessage messageReceived = (TextMessage)consumer.receive(5000);
                System.out.println("Received message: " + messageReceived.getText() + " (" + messageReceived.getJMSMessageID() + ")");
             
  21. And finally, always remember to close your JMS connections and resources after use, in a finally block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
  22.             finally
                {
                   if (initialContext != null)
                   {
                      initialContext.close();
                   }
                   if (connection != null)
                   {
                      connection.close();
                   }
                 }
              

EJB Example

Let's now take a look at the EJB example

  1. First, we create a new initial context
  2.             ic = new InitialContext();
            
  3. We look up the JMS XA Connection Factory (which is bound to java:/JmsXA)
  4.             ConnectionFactory cf = (ConnectionFactory)ic.lookup("java:/JmsXA");
            
  5. We look up the JMS Queue
  6.             Queue queue = (Queue)ic.lookup("queue/testQueue");
            
  7. We create a JMS connection, a session and a message producer for the queue
  8.             jmsConnection = cf.createConnection();
                Session session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer messageProducer = session.createProducer(queue);
            
  9. We create a text message with the text passed in parameter of the EJB method
  10.             TextMessage message = session.createTextMessage(text);
            
  11. We send the message to the queue
  12.             messageProducer.send(message);
                System.out.println("Sent message: " + message.getText() + "(" + message.getJMSMessageID() + ")");
            
  13. We now lookup the JDBC XA DataSource
  14.             DataSource ds = (DataSource)ic.lookup("java:/XADS");
            
  15. We retrieve a JDBC connection
  16.             jdbcConnection  = ds.getConnection();
            
  17. We create a prepared statement to insert the text and message's ID in the DB table
  18.             PreparedStatement pr = jdbcConnection.prepareStatement("INSERT INTO " + TABLE
                            + " (id, text) VALUES ('" + message.getJMSMessageID() + "', '" + text + "');");
            
  19. We execute the prepared statement
  20.             pr.execute();
            
  21. We close the prepared statement
  22.             pr.close();
             
  23. And finally, always remember to close all your connections and resources (for both JMS and JDBC) after use, in a finally block.
  24.             finally
                {
                    if (ic != null)
                    {
                       ic.close();
                    }
                    if (jmsConnection != null)
                    {
                       jmsConnection.close();
                    }
                    if (jdbcConnection != null)
                    {
                       jdbcConnection.close();
                    }
                }