EJB3 Message Driven Bean

In this example, we are going to create an MDB which consumes the message sent to the Queue Destination and a JMS Application Client which sends the message to the Queue using JMS API.
The client sends two types of messages – TextMessage and ObjectMessage. For ObjectMessage we create a Transfer Object ‘Employee’ with some basic fields as follows.

This example uses JBoss 7.1 as application server.

Transfer Object Class

We create a simple ‘Employee’ class and use it to create an object which will be sent to the destination by the client as an ObjectMessage.

package com.theopentutorials.mdb.to;
import java.io.Serializable;
public class Employee implements Serializable{
private int id;
	private String name;
	private String designation;
	private double salary;
	public Employee() {	}
	public Employee(int id, String name, String designation, 
				double salary) {
		this.id = id;
		this.name = name;
		this.designation = designation;
		this.salary = salary;
	}
	//Getters and Setters
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", designation="
				+ designation + ", salary=" + salary + "]";
	}
}

JMS Application Client – Message Producer

We create a Java application which uses JMS API to send messages to the queue. This application client sends a text message and an employee object message and hence is the message producer.
The client needs to get the JMS Administered Objects – ConnectionFactory and the Destination objects by using JNDI lookup.

First, we need to get the Context object to lookup the JBoss’s JNDI namespace. We can use the following context properties to get the context object.

Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,
	org.jboss.naming.remote.client.InitialContextFactory.class.getName());
env.put(Context.PROVIDER_URL, "remote://localhost:4447");
env.put(Context.SECURITY_PRINCIPAL, "username");
env.put(Context.SECURITY_CREDENTIALS, "password");
Context remoteContext = new InitialContext(env);

JBoss JNDI is protected by ApplicationRealm. So you need to provide username and password or create a new one by using the add user script available in ‘bin’ folder of JBoss.

Using the context object we can lookup the JMS administered objects and retrieve the connection factory and destination objects. Since the client is outside the JBoss container (normal java application), we need to use RemoteConnectionFactory.

ConnectionFactory factory = 
(ConnectionFactory)remoteContext.lookup("jms/RemoteConnectionFactory");
Queue queue = (Queue) remoteContext.lookup("jms/queue/MyQueue");

Next, we can use the connection factory to create a connection to the JMS provider which in turn can be used to create a session.
Using the session object, we can create the message and message producer which sends the message to the queue using the send() method.
The complete code is as follows.

package com.theopentutorials.client;

import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.theopentutorials.mdb.to.Employee;

public class JMSApplicationClient1 {
	public static void main(String[] args) {
		Connection connection;
		try {
			final Properties env = new Properties();
			env.put(Context.INITIAL_CONTEXT_FACTORY,
			org.jboss.naming.remote.client.InitialContextFactory.class.getName());
			env.put(Context.PROVIDER_URL, "remote://localhost:4447");
			env.put(Context.SECURITY_PRINCIPAL, "user1");
			env.put(Context.SECURITY_CREDENTIALS, "pass1");
			Context remoteContext = new InitialContext(env);
			
			ConnectionFactory factory = 						
				(ConnectionFactory)remoteContext.
						lookup("jms/RemoteConnectionFactory");
			Queue queue = (Queue) remoteContext.
					lookup("jms/queue/MyQueue");
			connection = factory.createConnection();
			Session session = connection.createSession(false, 
					QueueSession.AUTO_ACKNOWLEDGE);
			
			MessageProducer producer = session.createProducer(queue);
			
			//1. Sending TextMessage to the Queue 
			TextMessage message = session.createTextMessage();
			message.setText("Hello EJB3 MDB Queue!!!");
			producer.send(message);
			System.out.println("1. Sent TextMessage to the Queue");
			
			//2. Sending ObjectMessage to the Queue
			ObjectMessage objMsg = session.createObjectMessage();
			Employee employee = new Employee();
			employee.setId(2163);
			employee.setName("Kumar");
			employee.setDesignation("CTO");
			employee.setSalary(100000);
			objMsg.setObject(employee);						
			producer.send(objMsg);
			System.out.println("2. Sent ObjectMessage to the Queue");
			
			session.close();
		} catch (JMSException e) {
			e.printStackTrace();
		} catch (NamingException e) {
			e.printStackTrace();
		}				
	}
}

Message-Driven Bean – Message Consumer

Lastly, we need to create an MDB which will receive the message from the destination. While creating the MDB, we specify the destination type and destination JNDI in @ActivationConfigProperty annonation of @MessageDriven.

The MDB should implement the javax.jms.MessageListener interface and provide the onMessage() method implementation. Inside that method we retrieve the message and cast it to the appropriate message type (TextMessage or ObjectMessage). For TextMessage we can use the getText() method to get the message and for ObjectMessage, getObject() method returns the object sent to the destination by the producer.
The code is as follows.

package com.theopentutorials.mdb;
import java.util.Date;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import com.theopentutorials.mdb.to.Employee;
@MessageDriven(
	activationConfig = 
	{
		@ActivationConfigProperty(propertyName = "destinationType", 
					propertyValue = "javax.jms.Queue"),
		@ActivationConfigProperty(propertyName = "destination", 
					propertyValue = "queue/MyQueue") 
	})
public class QueueListenerMDB implements MessageListener {
	public QueueListenerMDB() {
	}
	public final void onMessage(Message message){
		try {
			if (message instanceof TextMessage) {
				System.out.println("Queue: I received a TextMessage at " + 
								new Date());
				TextMessage msg = (TextMessage) message;
				System.out.println("Message is : " + msg.getText());
			} else if (message instanceof ObjectMessage) {
				System.out.println("Queue: I received an ObjectMessage " +
							" at " + new Date());
				ObjectMessage msg = (ObjectMessage) message;
				Employee employee = (Employee) msg.getObject();
				System.out.println("Employee Details: ");
				System.out.println(employee.getId());
				System.out.println(employee.getName());
				System.out.println(employee.getDesignation());
				System.out.println(employee.getSalary());
			} else {
				System.out.println("Not valid message for this Queue MDB");
			}
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
}

Deploy the MDB and start the JBoss server. Run the application client which sends the message and verify that the MDB consumes it.

Leave a Comment