Point-To-Point messaging with JMS 2.0 API
The following blog post describes how to set up a minimal Java Messaging Service (JMS) example while using new features of the JMS API (Version 2.0) in a JavaEE 7 environment.
In order to successfully rebuild this example on your own I recommend you have the following software installed:
- Eclipse
- Java 7 or higher
- Glassfish
Prerequisites
I won’t show up how to configure your project and set up your application server. This blog post just focuses on understanding some of the JMS API features and how to use them. So make sure that you have your project and application server already configured before you start.
Understanding the JMS 2.0 API Programming Model
As mentioned in the title of the blog post, I would like to show up how to send and receive messages using the JMS 2.0 API. This is what the JMS 2.0 API Programming Model looks like:
The big difference to the previous JMS API is located in the center of the picture. There now is an interface called ‘JMSContext’ which comes with a bunch of convenient features and bundles the ‘Connection’ and the ‘Session’ interfaces. One of these features is the AutoClosable functionality, which means that you do not have to close the connection by yourself (this often lead to errors). That said it is a more elegant and slenderized way of coding as the following piece of code demonstrates:
// JMS 2.0 and above
1 2 3 |
public void sendMessage(String message) { context.createProducer().send(myQueue, message); } |
// before JMS 2.0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public void sendMessageOldStyle(String message) { Connection connection = null; Session session = null; try { connection = connectionFactory.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(myQueue); TextMessage messageToSend = session.createTextMessage(message); producer.send(messageToSend); } catch (JMSException e) { // do sth. } finally { if (connection != null) { try { connection.close(); } catch (JMSException e) { // do sth. } } } } |
Another improvement of the new API is that the JMSContext handles exceptions of connections and sessions internally. So there has been removed a lot of boilerplate code. The JMSContext also can be used to create both, message consumer and message producer, which are responsible for sending and receiving messages.
Point-To-Point domain model and JMS Resources
As the goal is to build a Point-To-Point JMS application, let’s first take a look at the respectively domain model:
So it is necessary to have a queue where all messages are sent to and from where you can receive those messages. That’s where a JMS Resources comes into play. A JMS Resource can be one of the following:
- Admin Object Resource
- Queue
- Topic
- Connector Resource
- QueueConnectionFactory
- TopicConnectionFactory
- ConnectionFactory
How all this fits together we will see later. First let’s do some coding!
Create the Message Producer
As a first step create a java class, which will send the messages to the queue. Let’s call it Message Producer. The MessageProducer class contains the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import javax.annotation.Resource; import javax.ejb.Stateless; import javax.inject.Inject; import javax.jms.JMSContext; import javax.jms.Queue; @Stateless public class MessageProducer { @Inject private JMSContext context; @Resource(mappedName = "java:app/jms/myTestQueue") private Queue myQueue; public void sendMessage(String messageToSend) { context.createProducer().send(myQueue, messageToSend); System.out.println("SEND MESSAGE: " + messageToSend); } } |
The MessageProducer is a stateless EJB which has two necessary fields:
- JMSContext
- Queue
Using Context and Dependency Injection (CDI) on the JMSContext allows you to focus on your main purpose – creating and sending messages. So we use the JMSContext to create a producer and send the message to the queue.
The @Resource annotation gives you the possibility to map the field to the queue where all messages will be sent.
Create the Message Consumer
Now that the code is able to send messages to the queue you need another class that is able to receive those messages. Let’s call that class MessageConsumer. The MessageConsumer class contains the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import javax.annotation.Resource; import javax.ejb.Stateless; import javax.inject.Inject; import javax.jms.JMSContext; import javax.jms.Queue; @Stateless public class MessageConsumer { @Inject private JMSContext context; @Resource(mappedName = "java:app/jms/myTestQueue") private Queue myQueue; public String receiveMessage() { String message = context.createConsumer(myQueue).receiveBody(String.class, 1000); if (message == null) { message = "NOTHING TO RECEIVE"; } return message; } } |
The MessageConsumer looks very similar to the MessageProducer. It is a stateless EJB and uses the JMSContext and the queue with the appropriated annotations as well. It has one method, which is used to receive the messages that were sent to the queue. In order to receive them, it creates a consumer by using the JMSContext and uses the queue as its destination.
Make things work
As both classes inject the JMSContext we must enable CDI. In order to do this, just create a file called ‘beans.xml’ (depends on your CDI version). This file has to be located in ‘Java Resources/src/main/webapp/META-INF/’ and can be empty. Furthermore you need some kind of code that links all that stuff you did before. It could be look as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import java.io.IOException; import java.io.Serializable; import javax.ejb.EJB; import javax.jms.JMSDestinationDefinition; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @JMSDestinationDefinition(interfaceName = "javax.jms.Queue", name = "java:app/jms/myTestQueue", destinationName = "myTestQueue") @WebServlet(urlPatterns = { "/TestServlet" }) public class TestServlet extends HttpServlet implements Serializable { private static final long serialVersionUID = 1L; @EJB private MessageProducer producer; @EJB private MessageConsumer consumer; public TestServlet() { super(); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String message = "Hello There!"; producer.sendMessage(message); System.out.println("RECEIVED MESSAGE: " + consumer.receiveMessage()); } } |
There are several things we are doing here:
- Define a JMS Destination
- Create a URI where the logic can be called (/TestServlet)
- Use the MessageProducer and MessageConsumer as EJBs
- Call the code
The interfaceName specified belongs to one of the possible Admin Object Resource mentioned earlier (here: queue). The name attribute contains besides the portable Java Naming and Directory Interface (JNDI) (java:app) a simple name for the resource. The destinationName is self-explanatory.
Using the @WebServlet annotation allows you to map every incoming request on ‘/TestServlet’ to this servlet.
As you annotated the MessageProducer and the MessageConsumer with @Stateless it is possible to get an EJB instance of the classes with the @EJB annotation so you don’t have to create those instances on your own.
The ‘doGet’ method is called on every ‘GET’ request of a client. When called, the message producer sends a message to the queue which is than received by the message consumer. The received message is printed to the console afterwards.
Run the application
As a last step you just have to deploy your application to the application server, start it and call the ‘TestServlet’ URI. Then you should see the result in the console of your IDE:
Recent posts






Comment article