Enterprise Java

Apache TomEE + JMS. It has never been so easy.

I remember old days of J2EE (1.3 and 1.4) that it was incredibly hard to start a project using JMS. You needed to install a JMS broker, create topics or queues and finally start your own battle with server configuration files and JNDI.

Thanks of JavaEE 6 and beyond using JMS is really easy and simple. But with Apache TomEE is even more simpler to get started. In this post we are going to see how to create and test a simple application which sends and receives message to/from a JMS queue with Apache TomEE.

Apache TomEE uses Apache Active MQ as a JMS provider. In this examples you won’t need to download or install anything because all elements will be provided as Maven dependency, but if you plan (and you should)  use Apache TomEE server you will need to download Apache TomEE plus or Apache TomEE plume. You can read more about Apache TomEE flavors in http://tomee.apache.org/comparison.html.

Dependencies

The first thing to do is add javaee-api as provided dependency, and junit and openejb-core as test dependency. Note that openejb-core dependency is added to have a runtime to execute tests, we are going to see it deeply in test section.

<dependencies>
  <dependency>
    <groupId>org.apache.openejb</groupId>
    <artifactId>javaee-api</artifactId>
    <version>6.0-6</version>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.openejb</groupId>
    <artifactId>openejb-core</artifactId>
    <version>4.7.1</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Business Code

Next step is creating the business code responsible for sending messages and receiving messages from JMS queue. Also it contains a method to receive messages fromqueue. For this example we are going to use a stateless EJB.

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

@Stateless
public class Messages {

  //Standard @Resource annotation is used to inject the ConnectionFactory. 
  //If no name is provided using lookup or name attribute, 
  //the fully qualified name of the class with an slash (/) and the name of the attribute is used. 
  //In this example: java:comp/env/org.superbiz.jms.Messages/connectionFactory.
  @Resource 
  private ConnectionFactory connectionFactory;

  //Standard @Resource annotation is used to inject the Queue. 
  //If no name is provided using lookup or name attribute, 
  //the fully qualified name of the class with an slash (/) and the name of the attribute is used. 
  //In this example: java:comp/env/org.superbiz.injection.jms.Messages/chatQueue.
  @Resource 
  private Queue chatQueue;


  public void sendMessage(String text) throws JMSException {

      Connection connection = null;
      Session session = null;

      try {
          connection = connectionFactory.createConnection();
          //Connection is get from ConnectionFactory instance and it is started.
          connection.start(); 

          //Creates a session to created connection.
          session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 

          //Creates a MessageProducer from Session to the Queue.
          MessageProducer producer = session.createProducer(chatQueue);
          producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); 

          TextMessage message = session.createTextMessage(text);

          //Tells the producer to send the message
          producer.send(message); 
      } finally {
          if (session != null) session.close(); 
          if (connection != null) connection.close();
      }
  }

  public String receiveMessage() throws JMSException {

      Connection connection = null;
      Session session = null;
      MessageConsumer consumer = null;

      try {
          connection = connectionFactory.createConnection();
          connection.start();

          session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

          consumer = session.createConsumer(chatQueue); 

          //Waits for a message with timeout. Note that because a TextMessage is sent, the receive method expects a TextMessage too.
          TextMessage message = (TextMessage) consumer.receive(1000); 

          return message.getText(); 
      } finally {
          if (consumer != null) consumer.close();
          if (session != null) session.close();
          if (connection != null) connection.close();
      }
  }
}

The most important part of Messages class is to note how easy is to inject ConnectionFactory and
Queue instances inside code. You only need to use @Resource annotation and container will do the rest for you. Finally note that because we have not used name or lookup attributes to set a name, the name of the field is used as resource name.

Test

And finally we can write a test that asserts that messages are sent and received using JMS queue. We could use for example Arquilian to write a test but for this case and because of simplicity, we are going to use an embedded OpenEJB instance to deploy the JMS example and run the tests.

public class MessagesTest {

  //Messages EJB is injected.
  @EJB
  private Messages messages;

  @Before
  public void setUp() throws Exception {
    Properties p = new Properties();
    //Embedded OpenEJB container is started.
    //And current test added inside created container
    //So we can use javaee annotations inside
    EJBContainer.createEJBContainer(p).getContext().bind("inject", this); 
  }

  @Test
  public void shouldSendAndReceiveMessages() throws Exception {

    //Three messages are sent.
    messages.sendMessage("Hello World!"); 
    messages.sendMessage("How are you?");
    messages.sendMessage("Still spinning?");

    //Three messages are received.
    assertThat(messages.receiveMessage(), is("Hello World!")); 
    assertThat(messages.receiveMessage(), is("How are you?"));
    assertThat(messages.receiveMessage(), is("Still spinning?"));
  }

}

Note that that test is really simple and concise, you only need to start programmatically an EJB container and bind the current test inside it so we can use JavaEE annotations inside test. The rest is a simple JUnit test.

And if you run the test you will receive a green bullet. But wait, probably you are wondering where is the JMSbroker and its configuration? Where is the definition of ConnectionFactory and JMS queue? And this is where OpenEJB (and Apache TomEE) comes into to play.

In this case OpenEJB (and Apache TomEE) will use Apache Active MQ in embedded mode, so you don’t need to install Apache Active MQ in your computer to run the tests.  Moreover Apache TomEE will create all required resources for you.  For example it will create a ConnectionFactory and a Queue for you with default parameters and expected names (org.superbiz.Messages/connectionFactory for ConnectionFactory and org.superbiz.Messages/chatQueue for the Queue), so you don’t need to worry to configure JMS during test phase. Apache TomEE is smart enough to create and configure them for you.

You can inspect console output the realize that resources are auto-created by reading next log message: INFO: Auto-creating a Resource.

Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig processResourceRef
INFO: Auto-linking resource-ref 'java:comp/env/org.superbiz.Messages/connectionFactory' in bean Messages to Resource(id=Default JMS Connection Factory)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.ConfigurationFactory configureService
INFO: Configuring Service(id=org.superbiz.Messages/chatQueue, type=Resource, provider-id=Default Queue)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig logAutoCreateResource
INFO: Auto-creating a Resource with id 'org.superbiz.Messages/chatQueue' of type 'javax.jms.Queue for 'Messages'.
Jan 10, 2015 10:32:48 AM org.apache.openejb.assembler.classic.Assembler createRecipe
INFO: Creating Resource(id=org.superbiz.Messages/chatQueue)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig processResourceEnvRef
INFO: Auto-linking resource-env-ref 'java:comp/env/org.superbiz.Messages/chatQueue' in bean Messages to Resource(id=org.superbiz.Messages/chatQueue)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.ConfigurationFactory configureService
INFO: Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig createContainer
INFO: Auto-creating a container for bean javaee.MessagesTest: Container(type=MANAGED, id=Default Managed Container)

And that’s all, really simple and easy to get started with JMS thanks of Java EE and TomEE. In next post we are going to see how to do the same but using a Message Driven Beans (MDB).

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button