|
|
|
|||||
|
|
JMS – Quick and dirty.
Up and running in
20 minutes, or less! The Java Messaging System presents a very interesting
model for Asynchronous messaging. In essence, it provides the plumbing for
sending a messages (or serializable objects) from disparate systems to a
central listener which monitors the queue. Once a message is received, by the
listener, it can then take some action on it. You can think of it as e-mail
or Instant Messaging for applications. The listener will receive the messages
in the order they were received by the Queue. NOTE: This tutorial is for Non-AsyncFW users. While this is a good introduction for all,
AsyncFW users should click
here, and read the tutorial. Configure Glassfish:
Start Glassfish and open the Admin Console: http://localhost:4848/
To
use JMS, you first need to configure a ‘Connection Factory’ and a
‘Destination Resource’. Select
the ‘Connection Factories’ menu tree option, and click ‘New’.
Next, fill out the connection factory information as
shown.
…and click the ‘Save’ button. NOTE: It is good practice to actually name your
JNDI resources something like the following “jms/AsyncFWFactory”, but for
now, the above is fine. Select the ‘Destination Resources’ menu tree item, and
click the ‘New’ button.
Enter the information below;
…and click the Save button. NOTE: It is good practice to actually name your JNDI
resources something like the following “jms/AsyncFWQ”, but for now, the above
is fine. That’s it! You have just completed the configuration of a
JMS Queue in Glassfish. Configuring the new resources in your project
Before your application can use the JNDI reference to the queue,
you will need to configure it in your web.xml. Please add the following; <resource-ref> <description>Default QueueFactory</description> <res-ref-name>AsyncFWQFactory</res-ref-name> <res-type>javax.jms.QueueConnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref> <resource-ref> <description>Default Queue</description> <res-ref-name>AsyncFWQ</res-ref-name> <res-type>javax.jms.Queue</res-type> <res-auth>Container</res-auth> </resource-ref> Let’s write some code. Coding For The JMS Queue
The JMS messaging model requires that you have at least a
two party conversation. Someone must talk, and someone must listenJ.
You may have many talkers, and as a matter of course, only one listener. So when we start coding we need to keep in mind both sides
of the conversation, and the type of data that is going to be passed. To
begin, we will assume that we are going to send a simple TextMessage. “Talking to yourself is stupid!” – Setting up the listener:
import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; public class SampleListener implements MessageListener{ @Override public void onMessage(Message message) { try { System.out.println("\nText Message:" + ((TextMessage)
message).getText()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } To create a
listener, you must implement the MessageListener
interface, and implement its onMessage
method. Initialize the Queue:
Consider the following design: Create a single class that
will initialize the queue and the listener - as well as provide the methods
to send messages. This is not required, but it makes messaging rather simple
to setup. import java.io.Serializable; import javax.jms.JMSException; import
javax.jms.MessageConsumer; import
javax.jms.MessageListener; import
javax.jms.MessageProducer; import javax.jms.ObjectMessage; import javax.jms.Queue; import
javax.jms.QueueConnection; import
javax.jms.QueueConnectionFactory; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.Context; import
javax.naming.InitialContext; import
javax.naming.NamingException; public class SampleQueue
{ private MessageListener Listener = null; private QueueConnectionFactory qFactory; private Queue queue; private Context env; public SampleQueue() throws NamingException,
JMSException{ env =(Context) new
InitialContext().lookup("java:comp/env"); initQueue(); } public void postObjectMessage(Serializable
msgObj) throws JMSException{ Session session = null; javax.jms.Connection conn =
(QueueConnection)qFactory.createQueueConnection(); session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageProducer producer =
session.createProducer(queue); ObjectMessage msg =
session.createObjectMessage(msgObj); producer.send(msg); producer.close(); session.close(); conn.close(); } public void postTextMessage(String msg) throws
JMSException{ Session session = null; javax.jms.Connection conn =
(QueueConnection)qFactory.createQueueConnection(); session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageProducer producer =
session.createProducer(queue); TextMessage message = session.createTextMessage(); message.setText(msg); producer.send(message); producer.close(); session.close(); conn.close(); } private void initQueue() throws NamingException,
JMSException { qFactory =
(QueueConnectionFactory)env.lookup("AsyncFWQFactory"); queue =
(Queue)env.lookup("AsyncFWQ"); Listener = new SampleListener(); javax.jms.Connection conn =
(QueueConnection)qFactory.createQueueConnection(); Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer =
session.createConsumer(queue); consumer.setMessageListener(Listener); conn.start(); } } In the above code, the SampleQueue class takes care of
everything for us. Once the class is created, the listener is in place, and
ready to receive Messages. This class
would be much improved as a singleton… . . private static SampleQueue
SQ = null; private SampleQueue() throws
NamingException, JMSException{ env =(Context) new
InitialContext().lookup("java:comp/env"); initQueue(); } public static SampleQueue
getInstance() throws NamingException,
JMSException{ if(null == SQ) SQ = new SampleQueue(); return SQ; } . . While the above code has been developed to be easy to
understand, it does lack in the area of error handling, and object clean up.
I would suggest doing a bit of hardening before deploying to a non-test
environment. That’s it – Now you can create an instance of the class
(or better yet, get an Instance), and perform a “postTestMessage()” and see
the results displayed in the console as the listener process the request. Trouble Shooting:
If you are running Glassfish and using JMS (e.g. a
Message Driven Bean), you probably saw already the following error in the log
files: DirectConsumer:Caught
Exception delivering messagecom.sun.messaging.jmq.io.Packet cannot be cast to
com.sun.messaging.jms.ra.DirectPacket. The error is caused by directly embedding the JMS-Host
into Glassfish v2 - it can be easily fixed in the admin console: Open the admin console:
http://localhost:4848
|
|||||
|
|
Copyright 2009. All rights reserved by S. Chappell |