4/14/2010

Message Driven Bean Example with Servlet Client

This is a simple example of JMS Queue message-driven bean (MDB), with a servlet client. MessageServlet sends a text message to the queue that the MDB is bound to, the MDB then consumes the incoming message. This example requires EJB 3.1 and Servlet 3.0, both are in Java EE 6.

First, the MDB class:

package test;

import java.util.logging.Logger;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;

@MessageDriven(mappedName="testQueue2",
activationConfig = { @ActivationConfigProperty(
propertyName="destinationType", propertyValue="javax.jms.Queue")})
public class MessageBean implements MessageListener {
Logger logger = Logger.getLogger("test");

public void onMessage(Message msg) {
try {
String name = msg.getStringProperty("name");
logger.info("Received msg " + msg + ", from " + name);
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
}
The servlet class:
package test;

import java.io.IOException;
import javax.annotation.Resource;
import javax.jms.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet(urlPatterns = "/MessageServlet")
public class MessageServlet extends HttpServlet {
@Resource(mappedName = "testQueue2")
private Queue queue;

@Resource(mappedName = "jms/QueueConnectionFactory")
private QueueConnectionFactory queueConnectionFactory;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
QueueConnection queueConnection = null;
try {
queueConnection = queueConnectionFactory.createQueueConnection();
queueConnection.start();
QueueSession queueSession = queueConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
QueueSender sender = queueSession.createSender(queue);

TextMessage msg = queueSession.createTextMessage();
msg.setText("A message from MessageServlet");
msg.setStringProperty("name", "MessageServlet");

sender.send(msg);
} catch (JMSException e) {
throw new RuntimeException(e);
} finally {
try {
if (queueConnection != null) {
queueConnection.close();
}
} catch (JMSException e) { //ignore
}
}
}
}
After compiling, package the two classes into a WAR file, say, mdb.war:
WEB-INF/classes/test/MessageBean.class
WEB-INF/classes/test/MessageServlet.class
Create the 2 JMS resources (testQueue2 & jms/QueueConnectionFactory) in the target application server. In GlassFish, you can do it in Admin GUI, or via asadmin CLI:
./asadmin create-jms-resource --restype javax.jms.Queue testQueue2
./asadmin create-jms-resource --restype javax.jms.QueueConnectionFactory jms/QueueConnectionFactory
Deploy mdb.war by copying it to server autodeploy directory.

Enter the URL in browser to invoke the servlet:
http://localhost:8080/mdb/MessageServlet

You will see the following log in server.log as a result of MDB processing:
[#|2010-04-14T17:28:49.900-0400|INFO|glassfishv3.0|test|_ThreadID=31;_ThreadName=Thread-1;|Received msg com.sun.messaging.jms.ra.DirectTextPacket@3ce177de, from MessageServlet|#]

6 comments:

toni said...

I tried the example and it worked immediately! Thank you very much!

Anonymous said...

Thank you very much. Really good example!

Mr Muthaks said...

I had to modify the code because for some reason the Injections are not working. I am using WAS 7 and RAD 8

package ServletTutorials;

import java.io.IOException;
import javax.annotation.Resource;
import javax.jms.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.*;
import javax.servlet.http.*;

public class MessageServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

/*
* @Resource(mappedName = "jms/messageListenerQueue") private Queue queue;
*
* @Resource(mappedName = "jms/messageListenerQCF") private
* QueueConnectionFactory queueConnectionFactory;
*/

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
QueueConnection queueConnection = null;
try {

InitialContext ic = new InitialContext();
Queue queue = (Queue) ic.lookup("jms/messageListenerQueue");
QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) ic
.lookup("jms/messageListenerQCF");
System.out.println(queueConnectionFactory);
queueConnection = queueConnectionFactory.createQueueConnection();
queueConnection.start();
QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueSender sender = queueSession.createSender(queue);

TextMessage msg = queueSession.createTextMessage();
msg.setText("A message from MessageServlet");
msg.setStringProperty("name", "MessageServlet");

sender.send(msg);
} catch (JMSException e) {
throw new RuntimeException(e);
} catch (NamingException e) {
System.out.println("Programmer Error: There was a problem getting the resorce from the server using the specified JNDI Name, Ref Stack trace below");
e.printStackTrace();
} finally {
try {
if (queueConnection != null) {
queueConnection.close();
}
} catch (JMSException e) { // ignore
}
}
}
}

javahowto said...

Not sure if WAS supports mappedName. An application server is not required by the Java EE spec to support this attribute. You could also replace mappedName with lookup, which is a new, portable attribute introduced in Java EE 6. Of course, lookup attribute will only work if your application server support Java EE 6.

Anonymous said...

You need WAS 8 to make use of JavaEE 6 features

Anonymous said...

This is the best, quickest, get-up-and-going tutorial on MDB I've found.