How to Configure Java Messaging Service (JMS) in GlassFish 3 Application Server?

September 10, 2010

JMS

«»

Message topics

Message topics are used when our JMS code uses the publish/subscribe (pub/sub)
messaging domain. When using this messaging domain, the same message can be
sent to all subscribers of the topic.


Sending messages to a message topic


The following example illustrates how to send messages to a message topic:



package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
public class MessageSender
{
@Resource(mappedName = “jms/GlassFishBookConnectionFactory”)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = “jms/GlassFishBookTopic”)
private static Topic topic;

public void produceMessages()
{
MessageProducer messageProducer;
TextMessage textMessage;
try
{
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(topic);
textMessage = session.createTextMessage();
textMessage.setText(“Testing, 1, 2, 3. Can you hear me?”);
System.out.println(“Sending the following message: ”
+ textMessage.getText());
messageProducer.send(textMessage);
textMessage.setText(“Do you copy?”);
System.out.println(“Sending the following message: ”
+ textMessage.getText());
messageProducer.send(textMessage);
textMessage.setText(“Good bye!”);
System.out.println(“Sending the following message: ”
+ textMessage.getText());
messageProducer.send(textMessage);
messageProducer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageSender().produceMessages();
}
}


As we can see, this code is nearly identical to the MessageSender class we saw when
we discussed point-to-point messaging. As a matter of fact, the only lines of code
that are different are the ones that are highlighted. The JMS API was designed this
way so that application developers do not have to learn two different APIs for the
PTP and pub/sub domains.


As the code is nearly identical to the corresponding example in the Message queues
section, we will only explain the differences between the two examples. In this
example, instead of declaring an instance of a class implementing javax.jms.
Queue, we declare an instance of a class implementing javax.jms.Topic. Just like
in the previous examples, we use dependency injection to initialize the Topic object.
After obtaining a JMS connection and a JMS session, we pass the Topic object to the
createProducer() method in the Session object. This method returns an instance
of javax.jms.MessageProducer that we can use to send messages to the JMS topic.


Receiving messages from a message topic


Just as sending messages to a message topic is nearly identical to sending messages
to a message queue, receiving messages from a message topic is nearly identical to
receiving messages from a message queue.



package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
public class MessageReceiver
{
@Resource(mappedName = “jms/GlassFishBookConnectionFactory”)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = “jms/GlassFishBookTopic”)
private static Topic topic;

public void getMessages()
{
Connection connection;
MessageConsumer messageConsumer;
TextMessage textMessage;
boolean goodByeReceived = false;
try
{
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageConsumer = session.createConsumer(topic);
connection.start();
while (!goodByeReceived)
{
System.out.println(“Waiting for messages…”);
textMessage = (TextMessage) messageConsumer.receive();
if (textMessage != null)
{
System.out.print(“Received the following message: “);
System.out.println(textMessage.getText());
System.out.println();
}
if (textMessage.getText() != null
&& textMessage.getText().equals(“Good bye!”))
{
goodByeReceived = true;
}
}
messageConsumer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageReceiver().getMessages();
}
}


Once again, the differences between this code and the corresponding code for PTP are
trivial. Instead of declaring an instance of a class implementing javax.jms.Queue, we
declare a class implementing javax.jms.Topic. We use the @Resource annotation
to inject an instance of this class into our code using the JNDI name we used when
creating it in the GlashFish web console. After obtaining a JMS connection and a JMS
session, we pass the Topic object to the createConsumer() method in the Session
object. This method returns an instance of javax.jms.MessageConsumer that we can
use to receive messages from the JMS topic.


Using the pub/sub messaging domain as illustrated in this section has the advantage
that messages can be sent to several message consumers. This can be easily tested by
concurrently executing two instances of the MessageReceiver class we developed in
this section, then executing the MessageSender class we developed in the previous
section. We should see console output for each instance, indicating that both
instances received all messages.


Just like with message queues, messages can be retrieved asynchronously from a
message topic. The procedure to do this is so similar to the message queue version
that we will not show an example. To convert the asynchronous example shown
earlier in this chapter to use a message topic, simply replace the javax.jms.Queue
variable with an instance of javax.jms.Topic and inject the appropriate instance by
using “jms/GlassFishBookTopic” as the value of the mappedName attribute of the
@Resource annotation decorating the instance of javax.jms.Topic.


Creating durable subscribers


The disadvantage of using the pub/sub messaging domain is that message
consumers must be executing when messages are sent to the topic. If the message
consumer is not executing at the time, it will not receive the messages, whereas in
PTP, messages are kept in a queue until the message consumer executes. Fortunately,
the JMS API provides a way to use the pub/sub messaging domain and keep
messages in the topic until all subscribed message consumers execute and receive the
message. This can be accomplished by creating durable subscribers to a JMS topic.


In order to be able to service durable subscribers, we need to set the ClientId
property of our JMS connection factory. Each durable subscriber must have a unique
client id, therefore a unique connection factory must be declared for each potential
durable subscriber.



InvalidClientIdException?
Only one JMS client can connect to a topic for a specific client id. If more
than one JMS client attempts to obtain a JMS connection using the same
connection factory, a JMSException stating that the client id is already in
use will be thrown. The solution is to create a connection factory for each
potential client that will be receiving messages from the durable topic.


Like we mentioned before, the easiest way to add a connection factory is through
the GlashFish web console. Recall that to add a JMS connection factory through the
GlashFish web console, we need to expand the Resources node on the left hand side,
then expand the JMS Resources node, click on the Connection Factories node, and
click on the New… button in the main area of the page. Our next example will use the
settings displayed in the following screenshot:



Before clicking on the OK button, we need to scroll to the bottom of the page, click
on the Add Property button, and enter a new property named ClientId. Our
example will use ExampleId as the value for this property.



Now that we have set up GlashFish to be able to provide durable subscriptions, we
are ready to write some code to take advantage of them:



package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
public class MessageReceiver
{
@Resource(mappedName = “jms/GlassFishBookDurableConnectionFactory”)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = “jms/GlassFishBookTopic”)
private static Topic topic;
public void getMessages()
{
Connection connection;
MessageConsumer messageConsumer;
TextMessage textMessage;
boolean goodByeReceived = false;
try
{
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageConsumer = session.createDurableSubscriber(topic,
“Subscriber1″);

connection.start();
while (!goodByeReceived)
{
System.out.println(“Waiting for messages…”);
textMessage = (TextMessage) messageConsumer.receive();
if (textMessage != null)
{
System.out.print(“Received the following message: “);
System.out.println(textMessage.getText());
System.out.println();
}
if (textMessage.getText() != null
&& textMessage.getText().equals(“Good bye!”))
{
goodByeReceived = true;
}
}
messageConsumer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageReceiver().getMessages();
}
}


As we can see, this code is not much different from the previous examples whose
purpose was to retrieve messages. There are only two differences from the previous
examples: the instance of ConnectionFactory to which we are injecting is the one
we set up earlier in this section to handle durable subscriptions, and instead of
calling the createSubscriber() method on the JMS session object, we are calling
createDurableSubscriber() . The createDurableSubscriber() method takes two
arguments: a JMS Topic object to retrieve messages from and a string designating
a name for this subscription. This second parameter must be unique between all
subscribers to the durable topic.


Summary


In this chapter, we covered how to set up JMS connection factories, JMS message
queues, and JMS message topics in GlashFish using the GlashFish web console.


We also covered how to send messages to a message queue via the
javax.jms.MessageProducer interface.


Additionally, we covered how to receive messages from a message queue via the
javax.jms.MessageConsumer interface. We also covered how to asynchronously
receive messages from a message queue by implementing the javax.jms.


MessageListener interface.


We also saw how to use these interfaces to send and receive messages to and from a
JMS message topic.


We covered how to browse messages in a message queue without removing the
messages from the queue via the javax.jms.QueueBrowser interface.


Finally, we saw how to set up and interact with durable subscriptions to JMS topics.

JMS Articles

email

«»

Comments

comments