Thursday, December 16, 2010

JMS Question...............


General questions
Q: What is the Java Message Service? 
A: The Java Message Service (JMS) API is an API for accessing enterprise messaging systems. It is part of the Java 2 Platform, Enterprise Edition (J2EE).
The Java Message Service makes it easy to write business applications that asynchronously send and receive critical business data and events.
The Java Message Service defines a common enterprise messaging API that is designed to be easily and efficiently supported by a wide range of enterprise messaging products.
The Java Message Service supports both message queueing and publish-subscribe styles of messaging.
Q: Is the Java Message Service another mail API? 
A: No. The term messaging is broadly defined in computing. It is used for describing various operating system concepts; it is used to describe email and fax systems; and with the JMS API, it is used to describe asynchronous communication between enterprise applications.
JMS messages are asynchronous requests, reports, or events that are consumed by enterprise applications, not humans. They contain vital information needed to coordinate these systems. They contain precisely formatted data that describe specific business actions. Through the exchange of these messages, each application tracks the progress of the enterprise.
Q: Is the Java Message Service a product? 
A: No, the Java Message Service is the specification of a common API for enterprise messaging. A JMS provider supplied by an enterprise messaging vendor is required to use it.
Q: Where can I find the Java Message Service specification? 
A: The Java Message Service 1.0.2 specification is available at http://java.sun.com/products/jms/docs.html. A link to the online JMS API documentation is at the same location.
Q: Who was involved with Sun in the creation of the specification of Java Message Service 1.0.2? 
A: A number of important industry players initially collaborated with Sun to define the first draft of the Java Message Service specification. In addition, many comments were received from other companies, government and educational organizations, and others during the three-month public review period.
Q: What is compelling about the Java Message Service? 
A: The Java Message Service is compelling for these reasons:
  • It is the first enterprise messaging API that has achieved wide industry support.
  • It simplifies the development of enterprise applications by providing standard messaging concepts and conventions that apply across a wide range of enterprise messaging systems.
  • It leverages existing, enterprise-proven messaging systems.
Q: Why should developers use the Java Message Service? 
A: The Java Message Service makes it easy to do the following:
  • Write portable, message-based business applications
  • Extend existing message-based applications by adding new JMS clients that interoperate fully with their existing non-JMS clients
Q: What does a programmer need to learn to use the Java Message Service? 
A: Message-based applications are fundamentally different from remote procedure call based applications. Once a developer understands how best to employ both technologies, the JMS API makes writing message-based applications as easy as learning a few additional interfaces.
Q: What is the relationship between the Java Message Service and Enterprise JavaBeans components? 
A: Since J2EE version 1.2 was released, Enterprise JavaBeans components have been able to use the JMS API to send enterprise messages and receive them synchronously. The Java 2 SDK, Enterprise Edition, version 1.3, now available, provides a new kind of enterprise bean, the message-driven bean, that allows an enterprise application to receive messages asynchronously.
Q: What is the relationship between the Java Message Service and the Java Naming and Directory Interface (JNDI) API? 
A: The JMS API, like the other Java Enterprise APIs, uses the JNDI API for administration. The JMS API defines ConnectionFactories and Destinations as administered objects that are configured and placed in a JNDI naming context. JMS clients then look up and use these preconfigured objects. This insures that JMS applications are easy to deploy and administer.
Q: What is the relationship between the Java Message Service and the Java DataBase Connectivity (JDBC) API? 
A: JMS clients may also use the JDBC API. They may use both the JMS API and the JDBC API in the same transaction. In most cases, they will achieve this automatically by implementing these clients as enterprise beans. They may also use the Java Transaction API.
Q: What is the relationship between the Java Message Service, the Java Transaction API, and the Java Transaction Service? 
A: The Java Transaction API (JTA) provides a client API for delimiting distributed transactions and an API for accessing a resource's ability to participate in a distributed transaction. A JMS client may use JTA to delimit distributed transactions. A JMS provider can optionally support distributed transactions via JTA.
The Java Transaction Service (JTS) can be used with the JMS API to form distributed transactions that combine message sends and receives with database updates and other JTS aware services. These services should be handled automatically when a JMS client is run from within an application server such as a J2EE server; however, it is also possible for JMS clients to program them explicitly.
Q: Where can I find a JMS API discussion group? 
A: You can find a JMS API discussion forum at http://java.sun.com/j2ee/community/forums/index.html. You must be a member of the Java Developer Connection to join this forum.
Q: Why is the JMS API promoted as a technology for providing communication between components within an enterprise, but not for business-to-business (B2B) communication between enterprises over the Internet? What prevents its use over the Internet? 
A: The main issue in providing Internet-based JMS API messaging is that JMS API vendors would have to agree on a common (interoperable) wire format, and the JMS specification would have to specify a router-router API.
B2B messaging is an important area with its own unique requirements. This area is being addressed by emerging standards such as the Electronic Business XML initiative, ebXML (see http://www.ebxml.org/), where Sun is playing an active role. The ebXML initiative currently defines a Messaging Service (see the ebXML Specifications page), which supports XML messaging over the Internet. Current ebXML specifications focus on providing point-to-point asynchronous communication between parties over the Internet using multiple transport protocols such as HTTP, mail, and FTP. Work is also planned in ebXML to provide publish/subscribe XML messaging. Sun and its partners are currently defining a new Java API for XML Messaging, JAXM (see JSR #000067, Java APIs for XML Messaging 1.0), which supports the ebXML Messaging Service specification. An early-access version of JAXM is available via the Java Developer Connection at The M Project 1.0 Early Access.
In summary, the JMS API is intended for use within an enterprise, while XML messaging between independent enterprises over the Internet is being supported by the ebXML initiative and the new Java APIs (including JAXM) that support various ebXML specifications.
Technical questions
Q: What JDK release does the JMS API need? 
A: The JMS API requires JDK/JRE release 1.1.x or higher.
Q: Does the JMS API provide a version of a distributed Java event model? 
A: The JMS API can be used, in general, as a notification service; however, it does not define a distributed version of Java Events. One alternative for implementing distributed Java Events would be as JavaBeans components that transparently, to the event producer and listener beans, distribute the events via the JMS API.
Q: Why are there two separate JMS API domains, point-to-point and publish/subscribe, instead of just one? 
A: Even though there are many similarities, providing separate domains still seems to be important. It means that vendors aren't forced to support facilities out of their domain and that client code can be a bit more portable because products more fully support a domain (as opposed to supporting less defined subsets of a merged domain).
Q: Why doesn't the JMS API specify a set of JavaBeans components? 
A: The JMS API is a low-level API, and like other low-level Java APIs, it doesn't lend itself to direct representation as JavaBeans components.
Q: How is the JMS API aligned with the CORBA Notification Service? 
A: The Notification Service adds filtering, delivery guarantee semantics, durable connections, and the assembly of event networks to the CORBA Event Service. It gets its delivery guarantee semantics from the CORBA Messaging Service (which defines asynchronous CORBA method invocation).
Java technology is well integrated with CORBA. It provides Java IDL and COS Naming. In addition, OMG has recently defined RMI over IIOP.
It is expected that most use of IIOP from Java will be via RMI. It is expected that most use of COS Naming from Java will be via the JNDI API (Java Naming and Directory Service). The JMS API is a Java specific API designed to be layered over a wide range of existing and future Message Oriented Middleware (MOM) systems (just as the JNDI API is layered over existing name and directory services).
Q: Why doesn't the JMS API provide end-to-end synchronous message delivery and notification of delivery? 
A: Some messaging systems provide synchronous delivery to destinations as a mechanism for implementing reliable applications. Some systems provide clients with various forms of delivery notification so that the clients can detect dropped or ignored messages. This is not the model defined by the JMS API.
JMS API messaging provides guaranteed delivery via the once-and-only-once delivery semantics of PERSISTENT messages. In addition, message consumers can insure reliable processing of messages by using either CLIENT_ACKNOWLEDGE mode or transacted sessions. This achieves reliable delivery with minimum synchronization and is the enterprise messaging model most vendors and developers prefer.
The JMS API does not define a schema of systems messages (such as delivery notifications). If an application requires acknowledgment of message receipt, it can define an application-level acknowledgment message.
These issues are more clearly understood when they are examined in the context of publish/subscribe applications. In this context, synchronous delivery and/or system acknowledgment of receipt are not an effective mechanism for implementing reliable applications (because producers by definition are not, and do not want to be, responsible for end-to-end message delivery).
Q: Why doesn't the JMS API provide a send-to-list mechanism? 
A: Currently the JMS API provides a number of message send options; however, messages can only be sent to one Destination at a time.
The benefit of send-to-list is slightly less work for the programmer and the potential for the JMS provider to optimize the fact that several destinations are being sent the same message.
The down side of a send-to-list mechanism is that the list is, in effect, a group that is implemented and maintained by the client. This would complicate the administration of JMS clients.
Instead of the JMS API providing a send-to-list mechanism, it is recommended that providers support configuring destinations that represent a group. This allows a client to reach all consumers with a single send, while insuring that groups are properly administrable.
Q: Why doesn't the JMS API provide subscription notification? If it were possible for a publisher to detect when subscribers for a topic existed, it could inhibit publication on unsubscribed topics. 
A: Although there may be some benefit in providing publishers with a mechanism for inhibiting publication to unsubscribed topics, the complexity this would add to the JMS API and the additional provider overhead it would require are not justified by its potential benefits. Instead, JMS providers should insure that they minimize the overhead for handling messages published to an unsubscribed topic.
Q: Can a message be acknowledged after its message consumer is closed? 
A: Yes. Since message acknowledgment processing is performed at the session level, message acknowledgement is still relevant after a consumer is closed. All messages consumed by the session are acknowledged for the following two examples:
// CLIENT_ACKNOWLEDGE session
Message msg1 = topicSubscriber1.receive();
Message msg2 = topicSubscriber2.receive();
topicSubscriber1.close();
msg2.acknowledge();

// transacted session
Message msg1 = queueReceiver.receive();
queueReceiver.close();
session.commit();

After the session has been closed, however, a call to the Message.acknowledge or Session.commit method throws an IllegalStateException. If closeis called on a transacted session before the transaction in progress is committed, the transaction is rolled back.
Note that in order to prevent duplicate delivery of a message from a durable subscription or queue, a message that can still be acknowledged by a session cannot be redelivered to another message consumer. The message can only be redelivered to another message consumer when it can no longer be acknowledged by the session that initially received the message.
Q: What message distribution policy does the JMS API specify when there are two or more QueueReceivers for the same queue at the same time? 
A: The JMS API does not specify a message distribution policy when two or more QueueReceivers are registered with a destination at the same time. JMS API semantics account for only one QueueReceiver at any point in time. The JMS API does not prohibit multiple QueueReceivers for a queue; it just does not define the behavior for this case.
TopicSession allows the creation of multiple TopicSubscribers per destination, it will deliver each message for a destination to eachTopicSubscriber eligible to receive it. Each copy of the message is treated as a completely separate message. Work done on one copy has no affect on the other; acknowledging one does not acknowledge the other; one message may be delivered immediately while another waits for its consumer to process messages ahead of it.
The Message.acknowledge method is documented to acknowledge the receipt of all messages consumed by the session. Thus, if msgA is delivered to topic subscribers TS1 and TS2 of the same session, and TS1 synchronously receives its copy of msgA and acknowledges it, TS2 will still be able to synchronously receive its copy of the message. However, if TS1 receives its copy of msgA and then TS2 receives its copy of msgA, acknowledging receiving the message fromTS2 will acknowledge both the msgAs received by TS1 and TS2, based on the fact that TS1's copy of msgA was received by the session before TS2's copy ofmsgA was received by the session.
Q: What is the recoverability of messages for closed consumers? 
A: For messages consumed from a queue or durable subscription, a rollback ensures that the messages are not acknowledged and that they will be delivered to the next consumer of these persistent entities. The JMS specification states that messages delivered to non-durable subscribers may be dropped. This statement means that the JMS API does not define the recoverability of messages consumed from a non-durable subscriber.
Q: Why can't I run the JMS API sample programs using the J2EE 1.2.x SDK? 
A: The J2EE 1.2.x Reference Implementation did not include an implementation of the JMS API. It included only the interfaces. The JMS Reference Implementation is available as part of J2EE 1.3 and you can run the sample programs with the J2EE 1.3 server. See the JMS Tutorial for information on running simple JMS client programs with the J2EE 1.3 server.
Please see Java Message Service API Licensees for a list of vendors that provide implementations of the JMS API. Many of these vendors have demonstration copies of their JMS API implementations that you can use to run the JMS API samples that you downloaded from the website.
Q: According to the specification, "Getting a property value for a name which has not been set is handled as if the the property exists with a null value." In the case of getStringProperty, does this mean a null value or a null string? 
A: Either is permissible. The reason for this ambiguity is that some MOM systems do not have the native concept of a null string, so they convert all null-valued strings at send time to empty strings.
Q: I used the Connection.setExceptionListener(ExceptionListener) method to try to handle connection problems, but when I stop the server, noJMSException seems to be triggered; the onException method is not called. Is this a bug? 
A: The JMS specification does not specify exactly what exceptions are delivered to an ExceptionListener or when they are delivered, so providers vary in how they handle connection problems. Check with your JMS provider if you have questions.
Q: According to Section 3.4 of the JMS Specification, a client can effectively set only three of the message header fields. All the others are set either by the JMS provider or by the send or publish method. Why do all the fields have a setter method, when any client setting will be overridden when the message is sent or when the JMS provider delivers it? Wouldn't it make sense to allow only getter methods for most of the fields? 
A: The specification requires setter methods mainly for consistency, so that each message header field has both a getter and setter method. Another reason is to allow a receiving client to change a field after a message is received but before it is passed to some other part of an application for processing. Although most setter methods are used very rarely, they are provided to give programmers flexibility.
Q: Can two different JMS services talk to each other? For instance, if A and B are two different JMS providers, can Provider A send messages directly to Provider B? If not, then can a subscriber to Provider A act as a publisher to Provider B? [new!]
A: The answers are no to the first question and yes to the second. The JMS specification does not require that one JMS provider be able to send messages directly to another provider. However, the specification does require that a JMS client must be able to accept a message created by a different JMS provider, so a message received by a subscriber to Provider A can then be published to Provider B. One caveat is that the publisher to Provider B is not required to handle aJMSReplyTo header that refers to a destination that is specific to Provider A.

JMS : queues on glassfish

Setting up GlassFish for JMS and Working with Message Queues

https://www.packtpub.com/article/setting-glassfish-jms-working-with-message-queues


The Java Messaging API (JMS) provides a mechanism for Java EE applications to send messages to each other. JMS applications do not communicate directly, instead message producers send messages to a destination and message consumers receive the message from the destination.
The message destination is a message queue when the point-to-point (PTP) messaging domain is used, or a message topic when the publish/subscribe (pub/sub) messaging domain is used.
In this article by David Heffelfinger, author of the book Java EE 6 with GlassFish 3 Application Server, we will cover the following topics:
  • Setting up GlassFish for JMS
  • Working with message queues
(For more resources on Java, see here.)

Setting up GlassFish for JMS

Before we start writing code to take advantage of the JMS API, we need to configure some GlassFish resources. Specifically, we need to set up a JMS connection factory, a message queue, and a message topic.

Setting up a JMS connection factory

The easiest way to set up a JMS connection factory is via GlassFish's web console. The web console can be accessed by starting our domain, by entering the following command in the command line:
asadmin start-domain domain1
Then point the browser to http://localhost:4848 and log in:
Setting up GlassFish for JMS and Working with Message Queues
A connection factory can be added by expanding the Resources node in the tree at the left-hand side of the web console, expanding the JMS Resources node and clicking on the Connection Factories node, then clicking on the New... button in the main area of the web console.
Setting up GlassFish for JMS and Working with Message Queues
For our purposes, we can take most of the defaults. The only thing we need to do is enter a Pool Nameand pick a Resource Type for our connection factory.
It is always a good idea to use a Pool Name starting with "jms/" when picking a name for JMS resources. This way JMS resources can be easily identified when browsing a JNDI tree.
In the text field labeled Pool Name, enter jms/GlassFishBookConnectionFactory. Our code examples later in this article will use this JNDI name to obtain a reference to this connection factory.
The Resource Type drop-down menu has three options:
  • javax.jms.TopicConnectionFactory - used to create a connection factory that creates JMS topics for JMS clients using the pub/sub messaging domain
  • javax.jms.QueueConnectionFactory - used to create a connection factory that creates JMS queues for JMS clients using the PTP messaging domain
  • javax.jms.ConnectionFactory - used to create a connection factory that creates either JMS topics or JMS queues
For our example, we will select javax.jms.ConnectionFactory. This way we can use the same connection factory for all our examples, those using the PTP messaging domain and those using the pub/sub messaging domain.
After entering the Pool Name for our connection factory, selecting a connection factory type, and optionally entering a description for our connection factory, we must click on the OK button for the changes to take effect.
Setting up GlassFish for JMS and Working with Message Queues
We should then see our newly created connection factory listed in the main area of the GlassFish web console.

Setting up a JMS message queue

A JMS message queue can be added by expanding the Resources node in the tree at the left-hand side of the web console, expanding the JMS Resources node and clicking on the Destination Resourcesnode, then clicking on the New... button in the main area of the web console.
Setting up GlassFish for JMS and Working with Message Queues
In our example, the JNDI name of the message queue is jms/GlassFishBookQueue. The resource type for message queues must be javax.jms.Queue. Additionally, a Physical Destination Name must be entered. In this example, we use GlassFishBookQueue as the value for this field.
After clicking on the New... button, entering the appropriate information for our message queue, and clicking on the OK button, we should see the newly created queue:
Setting up GlassFish for JMS and Working with Message Queues

Setting up a JMS message topic

Setting up a JMS message topic in GlassFish is very similar to setting up a message queue.
In the GlassFish web console, expand the Resources node in the tree at the left hand side, then expand the JMS Resouces node and click on the Destination Resources node, then click on the New... button in the main area of the web console.
Setting up GlassFish for JMS and Working with Message Queues
Our examples will use a JNDI Name of jms/GlassFishBookTopic. As this is a message topic, Resource Type must be javax.jms.Topic. The Description field is optional. The Physical Destination Name property is required. For our example, we will use GlassFishBookTopic as the value for this property.
After clicking on the OK button, we can see our newly created message topic:
Setting up GlassFish for JMS and Working with Message Queues
Now that we have set up a connection factory, a message queue, and a message topic, we are ready to start writing code using the JMS API.

Message queues

Like we mentioned earlier, message queues are used when our JMS code uses the point-to-point (PTP) messaging domain. For the PTP messaging domain, there is usually one message producer and one message consumer. The message producer and the message consumer don't need to run concurrently in order to communicate. The messages placed in the message queue by the message producer will stay in the message queue until the message consumer executes and requests the messages from the queue.

Sending messages to a message queue

The following example illustrates how to add messages to 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.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

public class MessageSender
{
@Resource(mappedName = "jms/GlassFishBookConnectionFactory")
private static ConnectionFactory connectionFactory;
@Resource(mappedName = "jms/GlassFishBookQueue")
private static Queue queue;

public void produceMessages()
{
MessageProducer messageProducer;
TextMessage textMessage;
try
{
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(queue);
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();
}
}
Before delving into the details of this code, alert readers might have noticed that this class is a standalone Java application as it contains a main method. As this class is standalone, it executes outside the application server. In spite of this, we can see that some resources are injected into it, specifically the connection factory and queue. The reason we can inject resources into this code, even though it runs outside the application server, is because GlassFish includes a utility called appclient.
This utility allows us to "wrap" an executable JAR file and allows it to have access to the application server resources. To execute the previous code, assuming it is packaged in an executable JAR file calledjmsptpproducer.jar, we would type the following command in the command line:
appclient -client jmsptpproducer.jar
We would then see, after some GlassFish log entries, the following output on the console:

Sending the following message: Testing, 1, 2, 3. Can you hear me?
Sending the following message: Do you copy?
Sending the following message: Good bye!

The appclient executable can be found under [GlassFish installation directory]/glassfish/bin. The previous example assumes this directory is in your PATH variable. If it isn't the complete path to the appclientexecutable, it must be typed in the command line.
With that out of the way, we can now explain the code.
The produceMessages() method performs all the necessary steps to send messages to a message queue.
The first thing this method does is obtain a JMS connection by invoking the createConnection() method on the injected instance of javax.jms. ConnectionFactory. Notice that the mappedName attribute of the@Resource annotation decorating the connection factory object matches the JNDI name of the connection factory we set up in the GlassFish web console. Behind the scenes, a JNDI lookup is made using this name to obtain the connection factory object.
After obtaining a connection, the next step is to obtain a JMS session from said connection. This can be accomplished by calling the createSession() method on the Connection object. As can be seen in the previous code, the createSession() method takes two parameters.
The first parameter of the createSession() method is a Boolean indicating if the session is transacted. If this value is true, several messages can be sent as part of a transaction by invoking the commit() method in the session object. Similarly, they can be rolled back by invoking its rollback() method .
The second parameter of the createSession() method indicates how messages are acknowledged by the message receiver. Valid values for this parameter are defined as constants in the javax.jms.Sessioninterface.
  • Session.AUTO_ACKNOWLEDGE: indicates that the session will automatically acknowledge the receipt of a message.
  • Session.CLIENT_ACKNOWLEDGE: indicates that the message receiver must explicitly call the acknowledge() method on the message.
  • Session.DUPS_OK_ACKNOWLEDGE: indicates that the session will lazily acknowledge the receipt of messages. Using this value might result in some messages being delivered more than once.
After obtaining a JMS session, an instance of javax.jms.MessageProducer is obtained by invoking thecreateProducer() method on the session object. The MessageProducer object is the one that will actually send messages to the message queue. The injected Queue instance is passed as a parameter to thecreateProducer() method . Again, the value of the mappedName attribute for the @Resource annotation decorating this object must match the JNDI name we gave our message queue when setting it up in the GlassFish web console.
After obtaining an instance of MessageProducer, the code creates a series of text messages by invoking the createTextMessage() method on the session object. This method returns an instance of a class implementing the javax.jms.TextMessage interface. This interface defines a method called setText() , which is used to set the actual text in the message. After creating each text message and setting its text, they are sent to the queue by invoking the send() method on the MessageProducer object.
After sending the messages, the code disconnects from the JMS queue by invoking the close() method on the MessageProducer object , on the Session object , and on the Connection object.
Although the previous example sends only text messages to the queue, we are not limited to this type of message. The JMS API provides several types of messages that can be sent and received by JMS applications. All message types are defined as interfaces in the javax.jms package.
The following table lists all the available message types:
Message type
Description
BytesMessage
Allows sending an array of bytes as a message.
MapMessage
Allows sending an implementation of java.util.Map as a
message.
ObjectMessage
Allows sending any Java object implementing
java.io.Serializable as a message.
StreamMessage
Allows sending an array of bytes as a message. Differs from BytesMessage in that it stores the type of each primitive type added to the stream.
TextMessage
Allows sending a java.lang.String as a message.
For more information on all of these message types, consult their JavaDoc documentation athttp://java.sun.com/javaee/6/docs/api/.

Retrieving messages from a message queue

There is no point in sending messages from a queue if nothing is going to receive them. The following example illustrates how to retrieve messages from a JMS 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.Queue; import javax.jms.Session; import javax.jms.TextMessage; public class MessageReceiver { @Resource(mappedName = "jms/GlassFishBookConnectionFactory") private static ConnectionFactory connectionFactory; @Resource(mappedName = "jms/GlassFishBookQueue") private static Queue queue; 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(queue); 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(); } }
Just like in the previous example, an instance of javax.jms.ConnectionFactory and an instance ofjavax.jms.Queue are injected by using the @Resource annotation. Getting a connection and a JMS session is exactly the same as in the previous example.
In this example, we obtain an instance of javax.jms.MessageConsumer by calling the createConsumer()method on the JMS session object. When we are ready to start receiving messages from the message queue, we need to invoke the start() method on the JMS connection object.
Code not receiving messages?
A common mistake when writing JMS messages is to fail to call the start() method on the JMS connection object. If our code is not receiving messages it should be receiving, we need to make sure we didn't forget to call this method.
Messages are received by invoking the receive() method on the instance of MessageConsumer obtained from the JMS session. This method returns an instance of a class implementing the javax.jms.Messageinterface. It must be casted to the appropriate type in order to obtain the actual message.
In this particular example, we placed this method call in a while loop, as we are expecting a message that will let us know that no more messages are coming. Specifically, we are looking for a message containing the text "Good bye!". Once we receive said message, we break out of the loop and continue processing. In this particular case, there is no more processing to do. Therefore, all we do is call theclose() method on the message consumer object, on the session object, and on the connection object.
Just like in the previous example, using the appclient utility allows us to inject resources into the code and prevents us from having to add any libraries to the CLASSPATH. After executing the code through theappclient utility, we should see the following output in the command line:
appclient -client target/jmsptpconsumer.jar
Waiting for messages...
Received the following message: Testing, 1, 2, 3. Can you hear me?
Waiting for messages...
Received the following message: Do you copy?
Waiting for messages...
Received the following message: Good bye!
This of course assumes that the previous example was already executed and it placed the messages in the message queue.

Asynchronously receiving messages from a message queue

The MessageConsumer.receive() method has a disadvantage—it blocks execution until a message is received from the queue. We can avoid this disadvantage by receiving messages asynchronously via an implementation of the javax.jms.MessageListener interface.
The javax.jms.MessageListener interface contains a single method called onMessage. It takes an instance of a class implementing the javax.jms.Message interface as its sole parameter. The following example illustrates a typical implementation of this interface:
package net.ensode.glassfishbook; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; public class ExampleMessageListener implements MessageListener { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.print("Received the following message: "); System.out.println(textMessage.getText()); System.out.println(); } catch (JMSException e) { e.printStackTrace(); } } }
In this case, the onMessage() method simply outputs the message text to the console.
Our main code can now delegate message retrieval to our custom MessageListener implementation:
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.Queue; import javax.jms.Session; public class AsynchMessReceiver { @Resource(mappedName = "jms/GlassFishBookConnectionFactory") private static ConnectionFactory connectionFactory; @Resource(mappedName = "jms/GlassFishBookQueue") private static Queue queue; public void getMessages() { Connection connection; MessageConsumer messageConsumer; try { connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); messageConsumer = session.createConsumer(queue); messageConsumer.setMessageListener(new ExampleMessageListener()); connection.start(); System.out.println("The above line wil l allow the " + "MessageListener implementation to " + "receiving and processing messages from the queue."); Thread.sleep(1000); System.out.println("Our code does not have to block " + "while messages are received."); Thread.sleep(1000); System.out.println("It can do other stuff " + "(hopefully something more useful than sending " + "silly output to the console. :)"); Thread.sleep(1000); messageConsumer.close(); session.close(); connection.close(); } catch (JMSException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { new AsynchMessReceiver().getMessages(); } }
The only relevant difference between this example and the one in the previous section is that in this case, we are calling the setMessageListener() method on the instance of javax.jms.MessageConsumerobtained from the JMS session. We pass an instance of our custom implementation ofjavax.jms.MessageListener to this method. Its onMessage() method is automatically called whenever there is a message waiting in the queue. By using this approach, the main code does not block while waiting to receive messages.
Executing the previous example (using of course GlassFish's appclient utility) results in the following output:
appclient -client target/jmsptpasynchconsumer.jar The above line will allow the MessageListener implementation to receiving and processing messages from the queue. Received the following message: Testing, 1, 2, 3. Can you hear me? Received the following message: Do you copy? Received the following message: Good bye! Our code does not have to block while messages are received. It can do other stuff (hopefully something more useful than sending silly output to the console. :)
Notice how the messages were received and processed while the main thread was executing. We can tell this is the case because the output of the onMessage() method of our MessageListener can be seen between calls to System.out.println() in the primary class.

Browsing message queues

JMS provides a way to browse message queues without actually removing the messages from the queue. The following example illustrates how to do this:

package net.ensode.glassfishbook;

import java.util.Enumeration;

import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.jms.TextMessage;

public class MessageQueueBrowser
{
@Resource(mappedName = "jms/GlassFishBookConnectionFactory")
private static ConnectionFactory connectionFactory;
@Resource(mappedName = "jms/GlassFishBookQueue")
private static Queue queue;

public void browseMessages()
{
try
{
Enumeration messageEnumeration;
TextMessage textMessage;
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(queue);
messageEnumeration = browser.getEnumeration();
if (messageEnumeration != null)
{
if (!messageEnumeration.hasMoreElements())
{
System.out.println("There are no messages " + "in the
queue.");
}
else
{
System.out.println("The following messages are in the
queue:");
while (messageEnumeration.hasMoreElements())
{
textMessage =
(TextMessage) messageEnumeration.nextElement();
System.out.println(textMessage.getText());
}
}
}
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageQueueBrowser().browseMessages();
}
}

As we can see, the procedure to browse messages in a message queue is straightforward. We obtain a JMS connection and a JMS session the usual way, then invoke the createBrowser() method on the JMS session object. This method returns an implementation of the javax.jms.QueueBrowser interface. This interface contains a getEnumeration() method that we can invoke to obtain an enumeration containing all messages in the queue. To examine the messages in the queue, we simply traverse this enumeration and obtain the messages one by one. In the previous example, we simply invoke the getText() method of each message in the queue.

Summary

In this article, we saw how to set up JMS connection factories, JMS message queues, and JMS message topics in GlassFish using the GlassFish web console. We also saw how to send and receive messages to and from a message queue.