Jakarta Messaging Examples

We are working on a fresh, updated Jakarta EE Tutorial. This section hasn’t yet been updated.

This chapter provides examples that show how to use Jakarta Messaging in various kinds of Jakarta EE applications.

Building and Running Jakarta Messaging Examples

The examples are in the jakartaee-examples/tutorial/jms/ directory.

To build and run each example:

  1. Use NetBeans IDE or Maven to compile, package, and in some cases deploy the example.

  2. Use NetBeans IDE, Maven, or the appclient command to run the application client, or use the browser to run the web application examples.

Before you deploy or run the examples, you need to create resources for them. Some examples have a glassfish-resources.xml file that is used to create resources for that example and others. You can use the asadmin command to create the resources.

To use the asadmin and appclient commands, you need to put the GlassFish Server bin directories in your command path, as described in GlassFish Server Installation Tips.

Overview of the Jakarta Messaging Examples

The following tables list the examples used in this chapter, describe what they do, and link to the section that describes them fully. The example directory for each example is relative to the jakartaee-examples/tutorial/jms/ directory.

Jakarta Messaging Examples That Show the Use of Jakarta EE Application Clients
Example Directory Description

simple/producer

Using an application client to send messages; see Sending Messages

simple/synchconsumer

Using an application client to receive messages synchronously; see Receiving Messages Synchronously

simple/asynchconsumer

Using an application client to receive messages asynchronously; see Using a Message Listener for Asynchronous Message Delivery

simple/messagebrowser

Using an application client to use a QueueBrowser to browse a queue; see Browsing Messages on a Queue

simple/clientackconsumer

Using an application client to acknowledge messages received synchronously; see Acknowledging Messages

durablesubscriptionexample

Using an application client to create a durable subscription on a topic; see Using Durable Subscriptions

transactedexample

Using an application client to send and receive messages in local transactions (also uses request-reply messaging); see Using Local Transactions

shared/sharedconsumer

Using an application client to create shared nondurable topic subscriptions; see Using Shared Nondurable Subscriptions

shared/shareddurableconsumer

Using an application client to create shared durable topic subscriptions; see Using Shared Durable Subscriptions

Jakarta Messaging Examples That Show the Use of Jakarta EE Web and Enterprise Bean Components
Example Directory Description

websimplemessage

Using managed beans to send messages and to receive messages synchronously; see Sending and Receiving Messages Using a Simple Web Application

simplemessage

Using an application client to send messages, and using a message-driven bean to receive messages asynchronously; see Receiving Messages Asynchronously Using a Message-Driven Bean

clientsessionmdb

Using a session bean to send messages, and using a message-driven bean to receive messages; see Sending Messages from a Session Bean to an MDB

clientmdbentity

Using an application client, two message-driven beans, and JPA persistence to create a simple HR application; see Using an Entity to Join Messages from Two MDBs

Writing Simple Jakarta Messaging Applications

This section shows how to create, package, and run simple Messaging clients that are packaged as application clients.

Overview of Writing Simple Jakarta Messaging Application

The clients demonstrate the basic tasks a Jakarta Messaging application must perform:

  • Creating a JMSContext

  • Creating message producers and consumers

  • Sending and receiving messages

Each example uses two clients: one that sends messages and one that receives them. You can run the clients in two terminal windows.

When you write a Messaging client to run in an enterprise bean application, you use many of the same methods in much the same sequence as for an application client. However, there are some significant differences. Using Jakarta Messaging in Jakarta EE Applications describes these differences, and this chapter provides examples that illustrate them.

The examples for this section are in the jakartaee-examples/tutorial/jms/simple/ directory, under the following subdirectories:

producer/
synchconsumer/
asynchconsumer/
messagebrowser/
clientackconsumer/

Before running the examples, you need to start GlassFish Server and create administered objects.

Starting the Jakarta Messaging Provider

When you use GlassFish Server, your Messaging provider is GlassFish Server. Start the server as described in Starting and Stopping GlassFish Server.

Creating Jakarta Messaging Administered Objects

This example uses the following Jakarta Messaging administered objects:

  • A connection factory

  • Two destination resources: a topic and a queue

Before you run the applications, you can use the asadmin add-resources command to create needed Messaging resources, specifying as the argument a file named glassfish-resources.xml. This file can be created in any project using NetBeans IDE, although you can also create it by hand. A file for the needed resources is present in the jms/simple/producer/src/main/setup/ directory.

The Jakarta Messaging examples use a connection factory with the logical JNDI lookup name java:comp/DefaultJMSConnectionFactory, which is preconfigured in GlassFish Server.

You can also use the asadmin create-jms-resource command to create resources, the asadmin list-jms-resources command to display their names, and the asadmin delete-jms-resource command to remove them.

To Create Resources for the Simple Examples

A glassfish-resources.xml file in one of the Maven projects can create all the resources needed for the simple examples.

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. In a command window, go to the Producer example.

    cd jakartaee-examples/tutorial/jms/simple/producer
  3. Create the resources using the asadmin add-resources command:

    asadmin add-resources src/main/setup/glassfish-resources.xml
  4. Verify the creation of the resources:

    asadmin list-jms-resources

    The command lists the two destinations and connection factory specified in the glassfish-resources.xml file in addition to the platform default connection factory:

    jms/MyQueue
    jms/MyTopic
    jms/__defaultConnectionFactory
    Command list-jms-resources executed successfully.

    In GlassFish Server, the Jakarta EE java:comp/DefaultJMSConnectionFactory resource is mapped to a connection factory named jms/__defaultConnectionFactory.

Building All the Simple Examples

To run the simple examples using GlassFish Server, package each example in an application client JAR file. The application client JAR file requires a manifest file, located in the src/main/java/META-INF/ directory for each example, along with the .class file.

The pom.xml file for each example specifies a plugin that creates an application client JAR file. You can build the examples using either NetBeans IDE or Maven.

To Build All the Simple Examples Using NetBeans IDE

  1. From the File menu, choose Open Project.

  2. In the Open Project dialog box, navigate to:

    jakartaee-examples/tutorial/jms
  3. Expand the jms node and select the simple folder.

  4. Click Open Project to open all the simple examples.

  5. In the Projects tab, right-click the simple project and select Build to build all the examples.

    This command places the application client JAR files in the target directories for the examples.

To Build All the Simple Examples Using Maven

  1. In a terminal window, go to the simple directory:

    cd jakartaee-examples/tutorial/jms/simple/
  2. Enter the following command to build all the projects:

    mvn install

    This command places the application client JAR files in the target directories for the examples.

Sending Messages

This section describes how to use a client to send messages. The Producer.java client will send messages in all of these examples.

General Steps Performed in the Example

General steps this example performs are as follows.

  1. Inject resources for the administered objects used by the example.

  2. Accept and verify command-line arguments. You can use this example to send any number of messages to either a queue or a topic, so you specify the destination type and the number of messages on the command line when you run the program.

  3. Create a JMSContext, then send the specified number of text messages in the form of strings, as described in Message Bodies.

  4. Send a final message of type Message to indicate that the consumer should expect no more messages.

  5. Catch any exceptions.

The Producer.java Client

The sending client, Producer.java, performs the following steps.

  1. Injects resources for a connection factory, queue, and topic:

    @Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
    private static ConnectionFactory connectionFactory;
    @Resource(lookup = "jms/MyQueue")
    private static Queue queue;
    @Resource(lookup = "jms/MyTopic")
    private static Topic topic;
  2. Retrieves and verifies command-line arguments that specify the destination type and the number of arguments:

    final int NUM_MSGS;
    String destType = args[0];
    System.out.println("Destination type is " + destType);
    if ( ! ( destType.equals("queue") || destType.equals("topic") ) ) {
        System.err.println("Argument must be \"queue\" or " + "\"topic\"");
        System.exit(1);
    }
    if (args.length == 2){
        NUM_MSGS = (new Integer(args[1])).intValue();
    } else {
        NUM_MSGS = 1;
    }
  3. Assigns either the queue or the topic to a destination object, based on the specified destination type:

    Destination dest = null;
    try {
        if (destType.equals("queue")) {
            dest = (Destination) queue;
        } else {
            dest = (Destination) topic;
        }
    } catch (Exception e) {
        System.err.println("Error setting destination: " + e.toString());
        System.exit(1);
    }
  4. Within a try-with-resources block, creates a JMSContext:

    try (JMSContext context = connectionFactory.createContext();) { ... }
  5. Sets the message count to zero, then creates a JMSProducer and sends one or more messages to the destination and increments the count. Messages in the form of strings are of the TextMessage message type:

        int count = 0;
        for (int i = 0; i < NUM_MSGS; i++) {
            String message = "This is message " + (i + 1)
                    + " from producer";
            // Comment out the following line to send many messages
            System.out.println("Sending message: " + message);
            context.createProducer().send(dest, message);
            count += 1;
        }
        System.out.println("Text messages sent: " + count);
  6. Sends an empty control message to indicate the end of the message stream:

        context.createProducer().send(dest, context.createMessage());

    Sending an empty message of no specified type is a convenient way for an application to indicate to the consumer that the final message has arrived.

  7. Catches and handles any exceptions. The end of the try-with-resources block automatically causes the JMSContext to be closed:

    } catch (Exception e) {
        System.err.println("Exception occurred: " + e.toString());
        System.exit(1);
    }
    System.exit(0);

To Run the Producer Client

You can run the client using the appclient command. The Producer client takes one or two command-line arguments: a destination type and, optionally, a number of messages. If you do not specify a number of messages, the client sends one message.

You will use the client to send three messages to a queue.

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server) and that you have created resources and built the simple Jakarta Messaging examples (see Creating Jakarta Messaging Administered Objects and Building All the Simple Examples).

  2. In a terminal window, go to the producer directory:

    cd producer
  3. Run the Producer program, sending three messages to the queue:

    appclient -client target/producer.jar queue 3

    The output of the program looks like this (along with some additional output):

    Destination type is queue
    Sending message: This is message 1 from producer
    Sending message: This is message 2 from producer
    Sending message: This is message 3 from producer
    Text messages sent: 3

    The messages are now in the queue, waiting to be received.

    When you run an application client, the command may take a long time to complete.

Receiving Messages Synchronously

This section describes the receiving client, which uses the receive method to consume messages synchronously. This section then explains how to run the clients using GlassFish Server.

The SynchConsumer.java Client

The receiving client, SynchConsumer.java, performs the following steps.

  1. Injects resources for a connection factory, queue, and topic.

  2. Assigns either the queue or the topic to a destination object, based on the specified destination type.

  3. Within a try-with-resources block, creates a JMSContext.

  4. Creates a JMSConsumer, starting message delivery:

    consumer = context.createConsumer(dest);
  5. Receives the messages sent to the destination until the end-of-message-stream control message is received:

    int count = 0;
    while (true) {
        Message m = consumer.receive(1000);
        if (m != null) {
            if (m instanceof TextMessage) {
                System.out.println(
                        "Reading message: " + m.getBody(String.class));
                count += 1;
            } else {
                break;
            }
        }
    }
    System.out.println("Messages received: " + count);

    Because the control message is not a TextMessage, the receiving client terminates the while loop and stops receiving messages after the control message arrives.

  6. Catches and handles any exceptions. The end of the try-with-resources block automatically causes the JMSContext to be closed.

The SynchConsumer client uses an indefinite while loop to receive messages, calling receive with a timeout argument.

To Run the SynchConsumer and Producer Clients

You can run the client using the appclient command. The SynchConsumer client takes one command-line argument, the destination type.

These steps show how to receive and send messages synchronously using both a queue and a topic. The steps assume you already ran the Producer client and have three messages waiting in the queue.

  1. In the same terminal window where you ran Producer, go to the synchconsumer directory:

    cd ../synchconsumer
  2. Run the SynchConsumer client, specifying the queue:

    appclient -client target/synchconsumer.jar queue

    The output of the client looks like this (along with some additional output):

    Destination type is queue
    Reading message: This is message 1 from producer
    Reading message: This is message 2 from producer
    Reading message: This is message 3 from producer
    Messages received: 3
  3. Now try running the clients in the opposite order. Run the SynchConsumer client:

    appclient -client target/synchconsumer.jar queue

    The client displays the destination type and then waits for messages.

  4. Open a new terminal window and run the Producer client:

    cd jakartaee-examples/tutorial/jms/simple/producer
    appclient -client target/producer.jar queue 3

    When the messages have been sent, the SynchConsumer client receives them and exits.

  5. Now run the Producer client using a topic instead of a queue:

    appclient -client target/producer.jar topic 3

    The output of the client looks like this (along with some additional output):

    Destination type is topic
    Sending message: This is message 1 from producer
    Sending message: This is message 2 from producer
    Sending message: This is message 3 from producer
    Text messages sent: 3
  6. Now, in the other terminal window, run the SynchConsumer client using the topic:

    appclient -client target/synchconsumer.jar topic

    The result, however, is different. Because you are using a subscription on a topic, messages that were sent before you created the subscription on the topic will not be added to the subscription and delivered to the consumer. (See Publish/Subscribe Messaging Style and Consuming Messages from Topics for details.) Instead of receiving the messages, the client waits for messages to arrive.

  7. Leave the SynchConsumer client running and run the Producer client again:

    appclient -client target/producer.jar topic 3

    Now the SynchConsumer client receives the messages:

    Destination type is topic
    Reading message: This is message 1 from producer
    Reading message: This is message 2 from producer
    Reading message: This is message 3 from producer
    Messages received: 3

    Because these messages were sent after the consumer was started, the client receives them.

Using a Message Listener for Asynchronous Message Delivery

This section describes the receiving clients in an example that uses a message listener for asynchronous message delivery. This section then explains how to compile and run the clients using GlassFish Server.

In the Jakarta EE platform, message listeners can be used only in application clients, as in this example. To allow asynchronous message delivery in a web or enterprise bean application, you use a message-driven bean, shown in later examples in this chapter.

Writing the AsynchConsumer.java and TextListener.java Clients

The sending client is Producer.java, the same client used in Receiving Messages Synchronously.

An asynchronous consumer normally runs indefinitely. This one runs until the user types the character q or Q to stop the client.

  1. The client, AsynchConsumer.java, performs the following steps.

    1. Injects resources for a connection factory, queue, and topic.

    2. Assigns either the queue or the topic to a destination object, based on the specified destination type.

    3. In a try-with-resources block, creates a JMSContext.

    4. Creates a JMSConsumer.

    5. Creates an instance of the TextListener class and registers it as the message listener for the JMSConsumer:

      listener = new TextListener();
      consumer.setMessageListener(listener);
    6. Listens for the messages sent to the destination, stopping when the user types the character q or Q (it uses a java.io.InputStreamReader to do this).

    7. Catches and handles any exceptions. The end of the try-with-resources block automatically causes the JMSContext to be closed, thus stopping delivery of messages to the message listener.

  2. The message listener, TextListener.java, follows these steps:

    1. When a message arrives, the onMessage method is called automatically.

    2. If the message is a TextMessage, the onMessage method displays its content as a string value. If the message is not a text message, it reports this fact:

      public void onMessage(Message m) {
          try {
              if (m instanceof TextMessage) {
                  System.out.println(
                          "Reading message: " + m.getBody(String.class));
              } else {
                   System.out.println("Message is not a TextMessage");
              }
          } catch (JMSException | JMSRuntimeException e) {
              System.err.println("JMSException in onMessage(): " + e.toString());
          }
      }

For this example, you will use the same connection factory and destinations you created in To Create Resources for the Simple Examples.

The steps assume that you have already built and packaged all the examples using NetBeans IDE or Maven.

To Run the AsynchConsumer and Producer Clients

You will need two terminal windows, as you did in Receiving Messages Synchronously.

  1. In the terminal window where you ran the SynchConsumer client, go to the asynchconsumer example directory:

    cd jakartaee-examples/tutorial/jms/simple/asynchconsumer
  2. Run the AsynchConsumer client, specifying the topic destination type:

    appclient -client target/asynchconsumer.jar topic

    The client displays the following lines (along with some additional output) and then waits for messages:

    Destination type is topic
    To end program, enter Q or q, then <return>
  3. In the terminal window where you ran the Producer client previously, run the client again, sending three messages:

    appclient -client target/producer.jar topic 3

    The output of the client looks like this (along with some additional output):

    Destination type is topic
    Sending message: This is message 1 from producer
    Sending message: This is message 2 from producer
    Sending message: This is message 3 from producer
    Text messages sent: 3

    In the other window, the AsynchConsumer client displays the following (along with some additional output):

    Destination type is topic
    To end program, enter Q or q, then <return>
    Reading message: This is message 1 from producer
    Reading message: This is message 2 from producer
    Reading message: This is message 3 from producer
    Message is not a TextMessage

    The last line appears because the client has received the non-text control message sent by the Producer client.

  4. Enter Q or q and press Return to stop the AsynchConsumer client.

  5. Now run the clients using a queue.

    In this case, as with the synchronous example, you can run the Producer client first, because there is no timing dependency between the sender and receiver:

    appclient -client target/producer.jar queue 3

    The output of the client looks like this:

    Destination type is queue
    Sending message: This is message 1 from producer
    Sending message: This is message 2 from producer
    Sending message: This is message 3 from producer
    Text messages sent: 3
  6. In the other window, run the AsynchConsumer client:

    appclient -client target/asynchconsumer.jar queue

    The output of the client looks like this (along with some additional output):

    Destination type is queue
    To end program, enter Q or q, then <return>
    Reading message: This is message 1 from producer
    Reading message: This is message 2 from producer
    Reading message: This is message 3 from producer
    Message is not a TextMessage
  7. Enter Q or q and press Return to stop the client.

Browsing Messages on a Queue

This section describes an example that creates a QueueBrowser object to examine messages on a queue, as described in Jakarta Messaging Queue Browsers. This section then explains how to compile, package, and run the example using GlassFish Server.

The MessageBrowser.java Client

To create a QueueBrowser for a queue, you call the JMSContext.createBrowser method with the queue as the argument. You obtain the messages in the queue as an Enumeration object. You can then iterate through the Enumeration object and display the contents of each message.

The MessageBrowser.java client performs the following steps.

  1. Injects resources for a connection factory and a queue.

  2. In a try-with-resources block, creates a JMSContext.

  3. Creates a QueueBrowser:

    QueueBrowser browser = context.createBrowser(queue);
  4. Retrieves the Enumeration that contains the messages:

    Enumeration msgs = browser.getEnumeration();
  5. Verifies that the Enumeration contains messages, then displays the contents of the messages:

    if ( !msgs.hasMoreElements() ) {
        System.out.println("No messages in queue");
    } else {
        while (msgs.hasMoreElements()) {
            Message tempMsg = (Message)msgs.nextElement();
            System.out.println("Message: " + tempMsg);
        }
    }
  6. Catches and handles any exceptions. The end of the try-with-resources block automatically causes the JMSContext to be closed.

Dumping the message contents to standard output retrieves the message body and properties in a format that depends on the implementation of the toString method. In GlassFish Server, the message format looks something like this:

Text:   This is message 3 from producer
Class:                  com.sun.messaging.jmq.jmsclient.TextMessageImpl
getJMSMessageID():      ID:8-10.152.23.26(bf:27:4:e:e7:ec)-55645-1363100335526
getJMSTimestamp():      1129061034355
getJMSCorrelationID():  null
JMSReplyTo:             null
JMSDestination:         PhysicalQueue
getJMSDeliveryMode():   PERSISTENT
getJMSRedelivered():    false
getJMSType():           null
getJMSExpiration():     0
getJMSPriority():       4
Properties:             {JMSXDeliveryCount=0}

Instead of displaying the message contents this way, you can call some of the Message interface’s getter methods to retrieve the parts of the message you want to see.

For this example, you will use the connection factory and queue you created for Receiving Messages Synchronously. It is assumed that you have already built and packaged all the examples.

To Run the QueueBrowser Client

To run the MessageBrowser example using the appclient command, follow these steps.

You also need the Producer example to send the message to the queue, and one of the consumer clients to consume the messages after you inspect them.

To run the clients, you need two terminal windows.

  1. In a terminal window, go to the producer directory:

    cd jakartaee-examples/tutorial/jms/simple/producer/
  2. Run the Producer client, sending one message to the queue, along with the non-text control message:

    appclient -client target/producer.jar queue

    The output of the client looks like this (along with some additional output):

    Destination type is queue
    Sending message: This is message 1 from producer
    Text messages sent: 1
  3. In another terminal window, go to the messagebrowser directory:

    cd jakartaee-examples/tutorial/jms/simple/messagebrowser
  4. Run the MessageBrowser client using the following command:

    appclient -client target/messagebrowser.jar

    The output of the client looks something like this (along with some additional output):

    Message:
    Text:   This is message 1 from producer
    Class:                  com.sun.messaging.jmq.jmsclient.TextMessageImpl
    getJMSMessageID():      ID:9-10.152.23.26(bf:27:4:e:e7:ec)-55645-1363100335526
    getJMSTimestamp():      1363100335526
    getJMSCorrelationID():  null
    JMSReplyTo:             null
    JMSDestination:         PhysicalQueue
    getJMSDeliveryMode():   PERSISTENT
    getJMSRedelivered():    false
    getJMSType():           null
    getJMSExpiration():     0
    getJMSPriority():       4
    Properties:             {JMSXDeliveryCount=0}
    
    Message:
    Class:                  com.sun.messaging.jmq.jmsclient.MessageImpl
    getJMSMessageID():      ID:10-10.152.23.26(bf:27:4:e:e7:ec)-55645-1363100335526
    getJMSTimestamp():      1363100335526
    getJMSCorrelationID():  null
    JMSReplyTo:             null
    JMSDestination:         PhysicalQueue
    getJMSDeliveryMode():   PERSISTENT
    getJMSRedelivered():    false
    getJMSType():           null
    getJMSExpiration():     0
    getJMSPriority():       4
    Properties:             {JMSXDeliveryCount=0}

    The first message is the TextMessage, and the second is the non-text control message.

  5. Go to the synchconsumer directory.

  6. Run the SynchConsumer client to consume the messages:

    appclient -client target/synchconsumer.jar queue

    The output of the client looks like this (along with some additional output):

    Destination type is queue
    Reading message: This is message 1 from producer
    Messages received: 1

Running Multiple Consumers on the Same Destination

To illustrate further the way point-to-point and publish/subscribe messaging works, you can use the Producer and SynchConsumer examples to send messages that are then consumed by two clients running simultaneously.

  1. Open three command windows. In one, go to the producer directory. In the other two, go to the synchconsumer directory.

  2. In each of the synchconsumer windows, start running the client, receiving messages from a queue:

    appclient -client target/synchconsumer.jar queue

    Wait until you see the "Destination type is queue" message in both windows.

  3. In the producer window, run the client, sending 20 or so messages to the queue:

    appclient -client target/producer.jar queue 20
  4. Look at the output in the synchconsumer windows. In point-to-point messaging, each message can have only one consumer. Therefore, each of the clients receives some of the messages. One of the clients receives the non-text control message, reports the number of messages received, and exits.

  5. In the window of the client that did not receive the non-text control message, enter Control-C to exit the program.

  6. Next, run the synchconsumer clients using a topic. In each window, run the following command:

    appclient -client target/synchconsumer.jar topic

    Wait until you see the "Destination type is topic" message in both windows.

  7. In the producer window, run the client, sending 20 or so messages to the topic:

    appclient -client target/producer.jar topic 20
  8. Again, look at the output in the synchconsumer windows. In publish/subscribe messaging, a copy of every message is sent to each subscription on the topic. Therefore, each of the clients receives all 20 text messages as well as the non-text control message.

Acknowledging Messages

Jakarta Messaging provides two alternative ways for a consuming client to ensure that a message is not acknowledged until the application has finished processing the message:

  • Using a synchronous consumer in a JMSContext that has been configured to use the CLIENT_ACKNOWLEDGE setting

  • Using a message listener for asynchronous message delivery in a JMSContext that has been configured to use the default AUTO_ACKNOWLEDGE setting

In the Jakarta EE platform, CLIENT_ACKNOWLEDGE sessions can be used only in application clients, as in this example.

The clientackconsumer example demonstrates the first alternative, in which a synchronous consumer uses client acknowledgment. The asynchconsumer example described in Using a Message Listener for Asynchronous Message Delivery demonstrates the second alternative.

For information about message acknowledgment, see Controlling Message Acknowledgment.

The following table describes four possible interactions between types of consumers and types of acknowledgment.

Message Acknowledgment with Synchronous and Asynchronous Consumers
Consumer Type Acknowledgment Type Behavior

Synchronous

Client

Client acknowledges message after processing is complete

Asynchronous

Client

Client acknowledges message after processing is complete

Synchronous

Auto

Acknowledgment happens immediately after receive call; message cannot be redelivered if any subsequent processing steps fail

Asynchronous

Auto

Message is automatically acknowledged when onMessage method returns

The example is under the jakartaee-examples/tutorial/jms/simple/clientackconsumer/ directory.

The example client, ClientAckConsumer.java, creates a JMSContext that specifies client acknowledgment:

try (JMSContext context =
      connectionFactory.createContext(JMSContext.CLIENT_ACKNOWLEDGE);) {
    ...
}

The client uses a while loop almost identical to that used by SynchConsumer.java, with the exception that after processing each message, it calls the acknowledge method on the JMSContext:

context.acknowledge();

The example uses the following objects:

  • The jms/MyQueue resource that you created for Receiving Messages Synchronously.

  • java:comp/DefaultJMSConnectionFactory, the platform default connection factory preconfigured with GlassFish Server

To Run the ClientAckConsumer Client

  1. In a terminal window, go to the following directory:

    jakartaee-examples/tutorial/jms/simple/producer/
  2. Run the Producer client, sending some messages to the queue:

    appclient -client target/producer.jar queue 3
  3. In another terminal window, go to the following directory:

    jakartaee-examples/tutorial/jms/simple/clientackconsumer/
  4. To run the client, use the following command:

    appclient -client target/clientackconsumer.jar

    The client output looks like this (along with some additional output):

    Created client-acknowledge JMSContext
    Reading message: This is message 1 from producer
    Acknowledging TextMessage
    Reading message: This is message 2 from producer
    Acknowledging TextMessage
    Reading message: This is message 3 from producer
    Acknowledging TextMessage
    Acknowledging non-text control message

    The client acknowledges each message explicitly after processing it, just as a JMSContext configured to use AUTO_ACKNOWLEDGE does automatically after a MessageListener returns successfully from processing a message received asynchronously.

Writing More Advanced Jakarta Messaging Applications

The following examples show how to use some of the more advanced Jakarta Messaging features: durable subscriptions and transactions.

Using Durable Subscriptions

The durablesubscriptionexample example shows how unshared durable subscriptions work. It demonstrates that a durable subscription continues to exist and accumulate messages even when there is no active consumer on it.

The example consists of two modules, a durableconsumer application that creates a durable subscription and consumes messages, and an unsubscriber application that enables you to unsubscribe from the durable subscription after you have finished running the durableconsumer application.

For information on durable subscriptions, see Creating Durable Subscriptions.

The main client, DurableConsumer.java, is under the jakartaee-examples/tutorial/jms/durablesubscriptionexample/durableconsumer directory.

The example uses a connection factory, jms/DurableConnectionFactory, that has a client ID.

The DurableConsumer client creates a JMSContext using the connection factory. It then stops the JMSContext, calls createDurableConsumer to create a durable subscription and a consumer on the topic by specifying a subscription name, registers a message listener, and starts the JMSContext again. The subscription is created only if it does not already exist, so the example can be run repeatedly:

try (JMSContext context = durableConnectionFactory.createContext();) {
    context.stop();
    consumer = context.createDurableConsumer(topic, "MakeItLast");
    listener = new TextListener();
    consumer.setMessageListener(listener);
    context.start();
    ...
}

To send messages to the topic, you run the producer client.

The unsubscriber example contains a very simple Unsubscriber client, which creates a JMSContext on the same connection factory and then calls the unsubscribe method, specifying the subscription name:

try (JMSContext context = durableConnectionFactory.createContext();) {
    System.out.println("Unsubscribing from durable subscription");
    context.unsubscribe("MakeItLast");
    ...
}

To Create Resources for the Durable Subscription Example

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. In a command window, go to the durableconsumer example.

    cd jakartaee-examples/tutorial/jms/durablesubscriptionexample/durableconsumer
  3. Create the resources using the asadmin add-resources command:

    asadmin add-resources src/main/setup/glassfish-resources.xml

    The command output reports the creation of a connector connection pool and a connector resource.

  4. Verify the creation of the resources:

    asadmin list-jms-resources

    In addition to the resources you created for the simple examples, the command lists the new connection factory:

    jms/MyQueue
    jms/MyTopic
    jms/__defaultConnectionFactory
    jms/DurableConnectionFactory
    Command list-jms-resources executed successfully.

To Run the Durable Subscription Example

  1. In a terminal window, go to the following directory:

    jakartaee-examples/tutorial/jms/durablesubscriptionexample/
  2. Build the durableconsumer and unsubscriber examples:

    mvn install
  3. Go to the durableconsumer directory:

    cd durableconsumer
  4. To run the client, enter the following command:

    appclient -client target/durableconsumer.jar

    The client creates the durable consumer and then waits for messages:

    Creating consumer for topic
    Starting consumer
    To end program, enter Q or q, then <return>
  5. In another terminal window, run the Producer client, sending some messages to the topic:

    cd jakartaee-examples/tutorial/jms/simple/producer
    appclient -client target/producer.jar topic 3
  6. After the DurableConsumer client receives the messages, enter q or Q to exit the program. At this point, the client has behaved like any other asynchronous consumer.

  7. Now, while the DurableConsumer client is not running, use the Producer client to send more messages:

    appclient -client target/producer.jar topic 2

    If a durable subscription did not exist, these messages would be lost, because no consumer on the topic is currently running. However, the durable subscription is still active, and it retains the messages.

  8. Run the DurableConsumer client again. It immediately receives the messages that were sent while it was inactive:

    Creating consumer for topic
    Starting consumer
    To end program, enter Q or q, then <return>
    Reading message: This is message 1 from producer
    Reading message: This is message 2 from producer
    Message is not a TextMessage
  9. Enter q or Q to exit the program.

To Run the unsubscriber Example

After you have finished running the DurableConsumer client, run the unsubscriber example to unsubscribe from the durable subscription.

  1. In a terminal window, go to the following directory:

    jakartaee-examples/tutorial/jms/durablesubscriptionexample/unsubscriber
  2. To run the Unsubscriber client, enter the following command:

    appclient -client target/unsubscriber.jar

    The client reports that it is unsubscribing from the durable subscription.

Using Local Transactions

The transactedexample example demonstrates the use of local transactions in a Messaging client application. It also demonstrates the use of the request/reply messaging pattern described in Creating Temporary Destinations, although it uses permanent rather than temporary destinations. The example consists of three modules, genericsupplier, retailer, and vendor, which can be found under the _jakartaee-examples/tutorial/jms/transactedexample/ directory. The source code can be found in the src/main/java/jakarta.tutorial trees for each module. The genericsupplier and retailer modules each contain a single class, genericsupplier/GenericSupplier.java and retailer/Retailer.java, respectively. The vendor module is more complex, containing four classes: vendor/Vendor.java, vendor/VendorMessageListener.java, vendor/Order.java, and vendor/SampleUtilities.java.

The example shows how to use a queue and a topic in a single transaction as well as how to pass a JMSContext to a message listener’s constructor function. The example represents a highly simplified e-commerce application in which the following actions occur.

  1. A retailer (retailer/src/main/java/jakarta/tutorial/retailer/Retailer.java) sends a MapMessage to a vendor order queue, ordering a quantity of computers, and waits for the vendor’s reply:

    outMessage = context.createMapMessage();
    outMessage.setString("Item", "Computer(s)");
    outMessage.setInt("Quantity", quantity);
    outMessage.setJMSReplyTo(retailerConfirmQueue);
    context.createProducer().send(vendorOrderQueue, outMessage);
    System.out.println("Retailer: ordered " + quantity + " computer(s)");
    orderConfirmReceiver = context.createConsumer(retailerConfirmQueue);
  2. The vendor (vendor/src/main/java/jakarta/tutorial/vendor/Vendor.java) receives the retailer’s order message and sends an order message to the supplier order topic in one transaction. This Jakarta Messaging transaction uses a single session, so you can combine a receive from a queue with a send to a topic. Here is the code that uses the same session to create a consumer for a queue:

    vendorOrderReceiver = session.createConsumer(vendorOrderQueue);

    The following code receives the incoming message, sends an outgoing message, and commits the JMSContext. The message processing has been removed to keep the sequence simple:

    inMessage = vendorOrderReceiver.receive();
    // Process the incoming message and format the outgoing
    // message
    ...
    context.createProducer().send(supplierOrderTopic, orderMessage);
    ...
    context.commit();

    For simplicity, there are only two suppliers, one for CPUs and one for hard drives.

  3. Each supplier (genericsupplier/src/main/java/jakarta/tutorial/genericsupplier/GenericSupplier.java) receives the order from the order topic, checks its inventory, and then sends the items ordered to the queue named in the order message’s JMSReplyTo field. If it does not have enough of the item in stock, the supplier sends what it has. The synchronous receive from the topic and the send to the queue take place in one Jakarta Messaging transaction:

    receiver = context.createConsumer(SupplierOrderTopic);
    ...
    inMessage = receiver.receive();
    if (inMessage instanceof MapMessage) {
        orderMessage = (MapMessage) inMessage;
    } ...
    // Process message
    outMessage = context.createMapMessage();
    // Add content to message
    context.createProducer().send(
             (Queue) orderMessage.getJMSReplyTo(),
             outMessage);
    // Display message contents
    context.commit();
  4. The vendor receives the suppliers' replies from its confirmation queue and updates the state of the order. Messages are processed by an asynchronous message listener, VendorMessageListener; this step shows the use of Jakarta Messaging transactions with a message listener:

    MapMessage component = (MapMessage) message;
    ...
    int orderNumber = component.getInt("VendorOrderNumber");
    Order order = Order.getOrder(orderNumber).processSubOrder(component);
    context.commit();
  5. When all outstanding replies are processed for a given order, the vendor message listener sends a message notifying the retailer whether it can fulfill the order:

    Queue replyQueue = (Queue) order.order.getJMSReplyTo();
    MapMessage retailerConfirmMessage = context.createMapMessage();
    // Format the message
    context.createProducer().send(replyQueue, retailerConfirmMessage);
    context.commit();
  6. The retailer receives the message from the vendor:

    inMessage = (MapMessage) orderConfirmReceiver.receive();

    The retailer then places a second order for twice as many computers as in the first order, so these steps are executed twice.

Diagram of steps in transaction example
Figure 1. Transactions: Messaging Client Example

All the messages use the MapMessage message type. Synchronous receives are used for all message reception except when the vendor processes the replies of the suppliers. These replies are processed asynchronously and demonstrate how to use transactions within a message listener.

At random intervals, the Vendor client throws an exception to simulate a database problem and cause a rollback.

All clients except Retailer use transacted contexts.

The example uses three queues named jms/AQueue, jms/BQueue, and jms/CQueue, and one topic named jms/OTopic.

To Create Resources for the transactedexample Example

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. In a command window, go to the genericsupplier example:

    cd jakartaee-examples/tutorial/jms/transactedexample/genericsupplier
  3. Create the resources using the asadmin add-resources command:

    asadmin add-resources src/main/setup/glassfish-resources.xml
  4. Verify the creation of the resources:

    asadmin list-jms-resources

    In addition to the resources you created for the simple examples and the durable subscription example, the command lists the four new destinations:

    jms/MyQueue
    jms/MyTopic
    jms/AQueue
    jms/BQueue
    jms/CQueue
    jms/OTopic
    jms/__defaultConnectionFactory
    jms/DurableConnectionFactory
    Command list-jms-resources executed successfully.

To Run the transactedexample Clients

You will need four terminal windows to run the clients. Make sure that you start the clients in the correct order.

  1. In a terminal window, go to the following directory:

    jakartaee-examples/tutorial/jms/transactedexample/
  2. To build and package all the modules, enter the following command:

    mvn install
  3. Go to the genericsupplier directory:

    cd genericsupplier
  4. Use the following command to start the CPU supplier client:

    appclient -client target/genericsupplier.jar CPU

    After some initial output, the client reports the following:

    Starting CPU supplier
  5. In a second terminal window, go to the genericsupplier directory:

    cd jakartaee-examples/tutorial/jms/transactedexample/genericsupplier
  6. Use the following command to start the hard drive supplier client:

    appclient -client target/genericsupplier.jar HD

    After some initial output, the client reports the following:

    Starting Hard Drive supplier
  7. In a third terminal window, go to the vendor directory:

    cd jakartaee-examples/tutorial/jms/transactedexample/vendor
  8. Use the following command to start the Vendor client:

    appclient -client target/vendor.jar

    After some initial output, the client reports the following:

    Starting vendor
  9. In another terminal window, go to the retailer directory:

    cd jakartaee-examples/tutorial/jms/transactedexample/retailer
  10. Use a command like the following to run the Retailer client. The argument specifies the number of computers to order:

    appclient -client target/retailer.jar 4

    After some initial output, the Retailer client reports something like the following. In this case, the first order is filled, but the second is not:

    Retailer: Quantity to be ordered is 4
    Retailer: Ordered 4 computer(s)
    Retailer: Order filled
    Retailer: Placing another order
    Retailer: Ordered 8 computer(s)
    Retailer: Order not filled

    The Vendor client reports something like the following, stating in this case that it is able to send all the computers in the first order, but not in the second:

    Vendor: Retailer ordered 4 Computer(s)
    Vendor: Ordered 4 CPU(s) and hard drive(s)
      Vendor: Committed transaction 1
    Vendor: Completed processing for order 1
    Vendor: Sent 4 computer(s)
      Vendor: committed transaction 2
    Vendor: Retailer ordered 8 Computer(s)
    Vendor: Ordered 8 CPU(s) and hard drive(s)
      Vendor: Committed transaction 1
    Vendor: Completed processing for order 2
    Vendor: Unable to send 8 computer(s)
      Vendor: Committed transaction 2

    The CPU supplier reports something like the following. In this case, it is able to send all the CPUs for both orders:

    CPU Supplier: Vendor ordered 4 CPU(s)
    CPU Supplier: Sent 4 CPU(s)
      CPU Supplier: Committed transaction
    CPU Supplier: Vendor ordered 8 CPU(s)
    CPU Supplier: Sent 8 CPU(s)
      CPU Supplier: Committed transaction

    The hard drive supplier reports something like the following. In this case, it has a shortage of hard drives for the second order:

    Hard Drive Supplier: Vendor ordered 4 Hard Drive(s)
    Hard Drive Supplier: Sent 4 Hard Drive(s)
      Hard Drive Supplier: Committed transaction
    Hard Drive Supplier: Vendor ordered 8 Hard Drive(s)
    Hard Drive Supplier: Sent 1 Hard Drive(s)
      Hard Drive Supplier: Committed transaction
  11. Repeat Step 10 as many times as you wish. Occasionally, the vendor will report an exception that causes a rollback:

    Vendor: JMSException occurred: jakarta.jms.JMSException: Simulated
    database concurrent access exception
      Vendor: Rolled back transaction 1
  12. After you finish running the clients, you can delete the destination resources by using the following commands:

    asadmin delete-jms-resource jms/AQueue
    asadmin delete-jms-resource jms/BQueue
    asadmin delete-jms-resource jms/CQueue
    asadmin delete-jms-resource jms/OTopic

Writing High Performance and Scalable Jakarta Messaging Applications

This section describes how to use Jakarta Messaging to write applications that can handle high volumes of messages robustly. These examples use both nondurable and durable shared consumers.

Using Shared Nondurable Subscriptions

This section describes the receiving clients in an example that shows how to use a shared consumer to distribute messages sent to a topic among different consumers. This section then explains how to compile and run the clients using GlassFish Server.

You may wish to compare this example to the results of Running Multiple Consumers on the Same Destination using an unshared consumer. In that example, messages are distributed among the consumers on a queue, but each consumer on the topic receives all the messages because each consumer on the topic is using a separate topic subscription.

In this example, however, messages are distributed among multiple consumers on a topic, because all the consumers are sharing the same subscription. Each message added to the topic subscription is received by only one consumer, similarly to the way in which each message added to a queue is received by only one consumer.

A topic may have multiple subscriptions. Each message sent to the topic will be added to each topic subscription. However, if there are multiple consumers on a particular subscription, each message added to that subscription will be delivered to only one of those consumers.

Writing the Clients for the Shared Consumer Example

The sending client is Producer.java, the same client used in previous examples.

The receiving client is SharedConsumer.java. It is very similar to AsynchConsumer.java, except that it always uses a topic. It performs the following steps.

  1. Injects resources for a connection factory and topic.

  2. In a try-with-resources block, creates a JMSContext.

  3. Creates a consumer on a shared nondurable subscription, specifying a subscription name:

    consumer = context.createSharedConsumer(topic, "SubName");
  4. Creates an instance of the TextListener class and registers it as the message listener for the shared consumer.

  5. Listens for the messages published to the destination, stopping when the user types the character q or Q.

  6. Catches and handles any exceptions. The end of the try-with-resources block automatically causes the JMSContext to be closed.

The TextListener.java class is identical to the one for the asynchconsumer example.

For this example, you will use the default connection factory and the topic you created in To Create Resources for the Simple Examples.

To Run the SharedConsumer and Producer Clients

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. Open three command windows. In the first, go to the simple/producer/ directory:

    cd jakartaee-examples/tutorial/jms/simple/producer/
  3. In the second and third command windows, go to the shared/sharedconsumer/ directory:

    cd jakartaee-examples/tutorial/jms/shared/sharedconsumer/
  4. In one of the sharedconsumer windows, build the example:

    mvn install
  5. In each of the two sharedconsumer windows, start running the client. You do not need to specify a topic argument:

    appclient -client target/sharedconsumer.jar

    Wait until you see the following output in both windows:

    Waiting for messages on topic
    To end program, enter Q or q, then <return>
  6. In the producer window, run the client, specifying the topic and a number of messages:

    appclient -client target/producer.jar topic 20

    Each consumer client receives some of the messages. Only one of the clients receives the non-text message that signals the end of the message stream.

  7. Enter Q or q and press Return to stop each client and see a report of the number of text messages received.

Using Shared Durable Subscriptions

The shareddurableconsumer client shows how to use shared durable subscriptions. It shows how shared durable subscriptions combine the advantages of durable subscriptions (the subscription remains active when the client is not) with those of shared consumers (the message load can be divided among multiple clients).

The example is much more similar to the sharedconsumer example than to the DurableConsumer.java client. It uses two classes, SharedDurableConsumer.java and TextListener.java, which can be found under the jakartaee-examples/tutorial/jms/shared/shareddurableconsumer/ directory.

The client uses java:comp/DefaultJMSConnectionFactory, the connection factory that does not have a client identifier, as is recommended for shared durable subscriptions. It uses the createSharedDurableConsumer method with a subscription name to establish the subscription:

consumer = context.createSharedDurableConsumer(topic, "MakeItLast");

You run the example in combination with the Producer.java client.

To Run the SharedDurableConsumer and Producer Clients

  1. In a terminal window, go to the following directory:

    jakartaee-examples/tutorial/jms/shared/shareddurableconsumer
  2. To compile and package the client, enter the following command:

    mvn install
  3. Run the client first to establish the durable subscription:

    appclient -client target/shareddurableconsumer.jar
  4. The client displays the following and pauses:

    Waiting for messages on topic
    To end program, enter Q or q, then <return>
  5. In the shareddurableconsumer window, enter q or Q to exit the program. The subscription remains active, although the client is not running.

  6. Open another terminal window and go to the producer example directory:

    cd jakartaee-examples/tutorial/jms/simple/producer
  7. Run the producer example, sending a number of messages to the topic:

    appclient -client target/producer.jar topic 6
  8. After the producer has sent the messages, open a third terminal window and go to the shareddurableconsumer directory.

  9. Run the client in both the first and third terminal windows. Whichever client starts first will receive all the messages that were sent when there was no active subscriber:

    appclient -client target/shareddurableconsumer.jar
  10. With both shareddurableconsumer clients still running, go to the producer window and send a larger number of messages to the topic:

    appclient -client target/producer.jar topic 25

    Now the messages will be shared by the two consumer clients. If you continue sending groups of messages to the topic, each client receives some of the messages. If you exit one of the clients and send more messages, the other client will receive all the messages.

Sending and Receiving Messages Using a Simple Web Application

Web applications can use Jakarta Messaging to send and receive messages, as noted in Using Jakarta EE Components to Produce and to Synchronously Receive Messages. This section describes the components of a very simple web application that uses Jakarta Messaging.

This section assumes that you are familiar with the basics of Jakarta Faces technology, described in the Introduction to Jakarta Faces Technology

The example, websimplemessage, is under the jakartaee-examples/tutorial/jms/ directory. It uses sending and receiving Facelets pages as well as corresponding backing beans. When a user enters a message in the text field of the sending page and clicks a button, the backing bean for the page sends the message to a queue and displays it on the page. When the user goes to the receiving page and clicks another button, the backing bean for that page receives the message synchronously and displays it.

Diagram showing a web application in which a managed bean sends a message to a queue, and another managed bean receives the message from the queue.
Figure 2. The websimplemessage Application

The websimplemessage Facelets Pages

The Facelets pages for the example are as follows.

  • sender.xhtml, which provides a labeled h:InputText tag where the user enters the message, along with two command buttons. When the user clicks the Send Message button, the senderBean.sendMessage method is called to send the message to the queue and display its contents. When the user clicks the Go to Receive Page button, the receiver.xhtml page appears.

  • receiver.xhtml, which also provides two command buttons. When the user clicks the Receive Message button, the receiverBean.getMessage method is called to fetch the message from the queue and display its contents. When the user clicks the Send Another Message button, the sender.xhtml page appears again.

The websimplemessage Managed Beans

The two managed beans for the example are as follows.

  • SenderBean.java, a CDI managed bean with one property, messageText, and one business method, sendMessage. The class is annotated with @JMSDestinationDefinition to create a component-private queue:

    @JMSDestinationDefinition(
            name = "java:comp/jms/webappQueue",
            interfaceName = "jakarta.jms.Queue",
            destinationName = "PhysicalWebappQueue")
    @Named
    @RequestScoped
    public class SenderBean { ... }

    The sendMessage method injects a JMSContext (using the default connection factory) and the queue, creates a producer, sends the message the user typed on the Facelets page, and creates a FacesMessage to display on the Facelets page:

    @Inject
    private JMSContext context;
    @Resource(lookup = "java:comp/jms/webappQueue")
    private Queue queue;
    private String messageText;
    ...
    public void sendMessage() {
        try {
            String text = "Message from producer: " + messageText;
            context.createProducer().send(queue, text);
    
            FacesMessage facesMessage =
                    new FacesMessage("Sent message: " + text);
            FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        } catch (Throwable t) {
            logger.log(Level.SEVERE,
                    "SenderBean.sendMessage: Exception: {0}",
                    t.toString());
        }
    }
  • ReceiverBean.java, a CDI managed bean with one business method, getMessage. The method injects a JMSContext (using the default connection factory) and the queue that was defined in SenderBean, creates a consumer, receives the message, and creates a FacesMessage to display on the Facelets page:

    @Inject
    private JMSContext context;
    @Resource(lookup = "java:comp/jms/webappQueue")
    private Queue queue;
    ...
    public void getMessage() {
        try {
            JMSConsumer receiver = context.createConsumer(queue);
            String text = receiver.receiveBody(String.class);
    
            if (text != null) {
                FacesMessage facesMessage =
                        new FacesMessage("Reading message: " + text);
                FacesContext.getCurrentInstance().addMessage(null, facesMessage);
            } else {
                FacesMessage facesMessage =
                        new FacesMessage("No message received after 1 second");
                FacesContext.getCurrentInstance().addMessage(null, facesMessage);
            }
        } catch (Throwable t) {
            logger.log(Level.SEVERE,
                    "ReceiverBean.getMessage: Exception: {0}",
                    t.toString());
        }
    }

Running the websimplemessage Example

You can use either NetBeans IDE or Maven to build, package, deploy, and run the websimplemessage application.

Creating Resources for the websimplemessage Example

This example uses an annotation-defined queue and the preconfigured default connection factory java:comp/DefaultJMSConnectionFactory.

To Package and Deploy websimplemessage Using NetBeans IDE

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. From the File menu, choose Open Project.

  3. In the Open Project dialog box, navigate to:

    jakartaee-examples/tutorial/jms
  4. Select the websimplemessage folder.

  5. Click Open Project.

  6. In the Projects tab, right-click the websimplemessage project and select Build.

    This command builds and deploys the project.

To Package and Deploy websimplemessage Using Maven

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. In a terminal window, go to:

    jakartaee-examples/tutorial/jms/websimplemessage/
  3. To compile the source files and package and deploy the application, use the following command:

    mvn install

To Run the websimplemessage Example

  1. In a web browser, enter the following URL:

    http://localhost:8080/websimplemessage
  2. Enter a message in the text field and click Send Message.

    If, for example, you enter "Hello, Duke", the following appears below the buttons:

    Sent message: Message from producer: Hello, Duke
  3. Click Go to Receive Page.

  4. Click Receive Message.

    The following appears below the buttons:

    Reading message: Message from producer: Hello, Duke
  5. Click Send Another Message to return to the sending page.

  6. After you have finished running the application, undeploy it using either the Services tab of NetBeans IDE or the mvn cargo:undeploy command.

Receiving Messages Asynchronously Using a Message-Driven Bean

If you are writing an application to run in the Jakarta EE application client container or on the Java SE platform, and you want to receive messages asynchronously, you need to define a class that implements the MessageListener interface, create a JMSConsumer, and call the method setMessageListener.

If you’re writing an application to run in the Jakarta EE web or enterprise bean container and want it to receive messages asynchronously, you also need to need to define a class that implements the MessageListener interface. However, instead of creating a JMSConsumer and calling the method setMessageListener, you must configure your message listener class to be a message-driven bean. The application server will then take care of the rest.

Message-driven beans can implement any messaging type. Most commonly, however, they implement the Jakarta Messaging technology.

This section describes a simple message-driven bean example. Before proceeding, you should read the basic conceptual information in the section What Is a Message-Driven Bean? as well as Using Message-Driven Beans to Receive Messages Asynchronously.

Overview of the simplemessage Example

The simplemessage application has the following components:

  • SimpleMessageClient: An application client that sends several messages to a queue

  • SimpleMessageBean: A message-driven bean that asynchronously processes the messages that are sent to the queue

Figure 3, “The simplemessage Application” illustrates the structure of this application. The application client sends messages to the queue, which was created administratively using the Administration Console. The Messaging provider (in this case, GlassFish Server) delivers the messages to the instances of the message-driven bean, which then processes the messages.

Diagram of application showing an application client sending a message to a queue, and the message being delivered to a message-driven bean
Figure 3. The simplemessage Application

The source code for this application is in the jakartaee-examples/tutorial/jms/simplemessage/ directory.

The simplemessage Application Client

The SimpleMessageClient sends messages to the queue that the SimpleMessageBean listens to. The client starts by injecting the connection factory and queue resources:

@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private static ConnectionFactory connectionFactory;

@Resource(lookup = "jms/MyQueue")
private static Queue queue;

Next, the client creates the JMSContext in a try-with-resources block:

String text;
final int NUM_MSGS = 3;

try (JMSContext context = connectionFactory.createContext();) { ... }

Finally, the client sends several text messages to the queue:

for (int i = 0; i < NUM_MSGS; i++) {
    text = "This is message " + (i + 1);
    System.out.println("Sending message: " + text);
    context.createProducer().send(queue, text);
}

The simplemessage Message-Driven Bean Class

The code for the SimpleMessageBean class illustrates the requirements of a message-driven bean class described in Using Message-Driven Beans to Receive Messages Asynchronously.

The first few lines of the SimpleMessageBean class use the @MessageDriven annotation’s activationConfig attribute to specify configuration properties:

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationLookup",
            propertyValue = "jms/MyQueue"),
    @ActivationConfigProperty(propertyName = "destinationType",
            propertyValue = "jakarta.jms.Queue")
})

See null for a list of the available properties.

See Sending Messages from a Session Bean to an MDB for examples of the subscriptionDurability, clientId, subscriptionName, and messageSelector properties.

The onMessage Method

When the queue receives a message, the enterprise bean container invokes the message listener method or methods. For a bean that uses Jakarta Messaging, this is the onMessage method of the MessageListener interface.

In the SimpleMessageBean class, the onMessage method casts the incoming message to a TextMessage and displays the text:

public void onMessage(Message inMessage) {

    try {
        if (inMessage instanceof TextMessage) {
            logger.log(Level.INFO,
                    "MESSAGE BEAN: Message received: {0}",
                    inMessage.getBody(String.class));
        } else {
            logger.log(Level.WARNING,
                    "Message of wrong type: {0}",
                    inMessage.getClass().getName());
        }
    } catch (JMSException e) {
        logger.log(Level.SEVERE,
                "SimpleMessageBean.onMessage: JMSException: {0}",
                e.toString());
        mdc.setRollbackOnly();
    }
}

Running the simplemessage Example

You can use either NetBeans IDE or Maven to build, deploy, and run the simplemessage example.

Creating Resources for the simplemessage Example

This example uses the queue named jms/MyQueue and the preconfigured default connection factory java:comp/DefaultJMSConnectionFactory.

If you have run the simple Jakarta Messaging examples in Writing Simple Jakarta Messaging Applications and have not deleted the resources, you already have the queue. Otherwise, follow the instructions in To Create Resources for the Simple Examples to create it.

For more information on creating Messaging resources, see Creating Jakarta Messaging Administered Objects.

To Run the simplemessage Example Using NetBeans IDE

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. From the File menu, choose Open Project.

  3. In the Open Project dialog box, navigate to:

    jakartaee-examples/tutorial/jms/simplemessage
  4. Select the simplemessage folder.

  5. Make sure that the Open Required Projects check box is selected, then click Open Project.

  6. In the Projects tab, right-click the simplemessage project and select Build. (If NetBeans IDE suggests that you run a priming build, click the box to do so.)

    This command packages the application client and the message-driven bean, then creates a file named simplemessage.ear in the simplemessage-ear/target/ directory. It then deploys the simplemessage-ear module, retrieves the client stubs, and runs the application client.

    The output in the output window looks like this (preceded by application client container output):

    Sending message: This is message 1
    Sending message: This is message 2
    Sending message: This is message 3
    To see if the bean received the messages,
     check <install_dir>/domains/domain1/logs/server.log.

    In the server log file, lines similar to the following appear:

    MESSAGE BEAN: Message received: This is message 1
    MESSAGE BEAN: Message received: This is message 2
    MESSAGE BEAN: Message received: This is message 3

    The received messages may appear in a different order from the order in which they were sent.

  7. After you have finished running the application, undeploy it using the Services tab.

To Run the simplemessage Example Using Maven

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. In a terminal window, go to:

    jakartaee-examples/tutorial/jms/simplemessage/
  3. To compile the source files and package the application, use the following command:

    mvn install

    This target packages the application client and the message-driven bean, then creates a file named simplemessage.ear in the simplemessage-ear/target/ directory. It then deploys the simplemessage-ear module, retrieves the client stubs, and runs the application client.

    The output in the terminal window looks like this (preceded by application client container output):

    Sending message: This is message 1
    Sending message: This is message 2
    Sending message: This is message 3
    To see if the bean received the messages,
     check <install_dir>/domains/domain1/logs/server.log.

    In the server log file, lines similar to the following appear:

    MESSAGE BEAN: Message received: This is message 1
    MESSAGE BEAN: Message received: This is message 2
    MESSAGE BEAN: Message received: This is message 3

    The received messages may appear in a different order from the order in which they were sent.

  4. After you have finished running the application, undeploy it using the mvn cargo:undeploy command.

Sending Messages from a Session Bean to an MDB

This section explains how to write, compile, package, deploy, and run an application that uses Jakarta Messaging in conjunction with a session bean. The application contains the following components:

  • An application client that invokes a session bean

  • A session bean that publishes several messages to a topic

  • A message-driven bean that receives and processes the messages using a durable topic subscription and a message selector

You will find the source files for this section in the jakartaee-examples/tutorial/jms/clientsessionmdb/ directory. Path names in this section are relative to this directory.

Writing the Application Components for the clientsessionmdb Example

This application demonstrates how to send messages from an enterprise bean (in this case, a session bean) rather than from an application client, as in the example in Receiving Messages Asynchronously Using a Message-Driven Bean. Figure 4, “An Enterprise Bean Application: Client to Session Bean to Message-Driven Bean” illustrates the structure of this application. Sending messages from an enterprise bean is very similar to sending messages from a managed bean, which was shown in Sending and Receiving Messages Using a Simple Web Application.

Diagram of application showing an application client calling a session bean, which sends messages that are processed by a message-driven bean
Figure 4. An Enterprise Bean Application: Client to Session Bean to Message-Driven Bean

The Publisher enterprise bean in this example is the enterprise-application equivalent of a wire-service news feed that categorizes news events into six news categories. The message-driven bean could represent a newsroom, where the sports desk, for example, would set up a subscription for all news events pertaining to sports.

The application client in the example injects the Publisher enterprise bean’s remote home interface and then calls the bean’s business method. The enterprise bean creates 18 text messages. For each message, it sets a String property randomly to one of six values representing the news categories and then publishes the message to a topic. The message-driven bean uses a message selector for the property to limit which of the published messages will be delivered to it.

Coding the Application Client: MyAppClient.java

The application client, MyAppClient.java, found under clientsessionmdb-app-client, performs no Messaging operations and so is simpler than the client in Receiving Messages Asynchronously Using a Message-Driven Bean. The client uses dependency injection to obtain the Publisher enterprise bean’s business interface:

@EJB(name="PublisherRemote")
private static PublisherRemote publisher;

The client then calls the bean’s business method twice.

Coding the Publisher Session Bean

The Publisher bean is a stateless session bean that has one business method. The Publisher bean uses a remote interface rather than a local interface because it is accessed from the application client.

The remote interface, PublisherRemote.java, found under clientsessionmdb-ejb, declares a single business method, publishNews.

The bean class, PublisherBean.java, also found under clientsessionmdb-ejb, implements the publishNews method and its helper method chooseType. The bean class injects SessionContext and Topic resources (the topic is defined in the message-driven bean). It then injects a JMSContext, which uses the preconfigured default connection factory unless you specify otherwise. The bean class begins as follows:

@Stateless
@Remote({
    PublisherRemote.class
})
public class PublisherBean implements PublisherRemote {

    @Resource
    private SessionContext sc;
    @Resource(lookup = "java:module/jms/newsTopic")
    private Topic topic;
    @Inject
    private JMSContext context;
    ...
}

The business method publishNews creates a JMSProducer and publishes the messages.

Coding the Message-Driven Bean: MessageBean.java

The message-driven bean class, MessageBean.java, found under clientsessionmdb-ejb, is almost identical to the one in Receiving Messages Asynchronously Using a Message-Driven Bean. However, the @MessageDriven annotation is different, because instead of a queue, the bean is using a topic, a durable subscription, and a message selector. The bean defines a topic for the use of the application; the definition uses the java:module scope because both the session bean and the message-driven bean are in the same module. Because the destination is defined in the message-driven bean, the @MessageDriven annotation uses the destinationLookup activation config property. (See Creating Resources for Jakarta EE Applications for more information.) The annotation also sets the activation config properties messageSelector, subscriptionDurability, clientId, and subscriptionName, as follows:

@JMSDestinationDefinition(
        name = "java:module/jms/newsTopic",
        interfaceName = "jakarta.jms.Topic",
        destinationName = "PhysicalNewsTopic")
@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationLookup",
            propertyValue = "java:module/jms/newsTopic"),
    @ActivationConfigProperty(propertyName = "destinationType",
            propertyValue = "jakarta.jms.Topic"),
    @ActivationConfigProperty(propertyName = "messageSelector",
            propertyValue = "NewsType = 'Sports' OR NewsType = 'Opinion'"),
    @ActivationConfigProperty(propertyName = "subscriptionDurability",
            propertyValue = "Durable"),
    @ActivationConfigProperty(propertyName = "clientId",
            propertyValue = "MyID"),
    @ActivationConfigProperty(propertyName = "subscriptionName",
            propertyValue = "MySub")
})

The topic is the one defined in the PublisherBean. The message selector in this case represents both the sports and opinion desks, just to demonstrate the syntax of message selectors.

The Jakarta Messaging resource adapter uses these properties to create a connection factory for the message-driven bean that allows the bean to use a durable subscription.

Running the clientsessionmdb Example

You can use either NetBeans IDE or Maven to build, deploy, and run the simplemessage example.

This example uses an annotation-defined topic and the preconfigured default connection factory java:comp/DefaultJMSConnectionFactory, so you do not have to create resources for it.

To Run clientsessionmdb Using NetBeans IDE

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. From the File menu, choose Open Project.

  3. In the Open Project dialog box, navigate to:

    jakartaee-examples/tutorial/jms/clientsessionmdb
  4. Select the clientsessionmdb folder.

  5. Make sure that the Open Required Projects check box is selected, then click Open Project.

  6. In the Projects tab, right-click the clientsessionmdb project and select Build. (If NetBeans IDE suggests that you run a priming build, click the box to do so.)

    This command creates the following:

    1. An application client JAR file that contains the client class file and the session bean’s remote interface, along with a manifest file that specifies the main class and places the Jakarta Enterprise Beans JAR file in its classpath

    2. An enterprise bean JAR file that contains both the session bean and the message-driven bean

    3. An application EAR file that contains the two JAR files

      The clientsessionmdb.ear file is created in the clientsessionmdb-ear/target/ directory.

      The command then deploys the EAR file, retrieves the client stubs, and runs the client.

      The client displays these lines:

      To view the bean output,
       check <install_dir>/domains/domain1/logs/server.log.

      The output from the enterprise beans appears in the server log file. The Publisher session bean sends two sets of 18 messages numbered 0 through 17. Because of the message selector, the message-driven bean receives only the messages whose NewsType property is Sports or Opinion.

  7. Use the Services tab to undeploy the application after you have finished running it.

To Run clientsessionmdb Using Maven

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. Go to the following directory:

    jakartaee-examples/tutorial/jms/clientsessionmdb/
  3. To compile the source files and package, deploy, and run the application, enter the following command:

    mvn install

    This command creates the following:

    • An application client JAR file that contains the client class file and the session bean’s remote interface, along with a manifest file that specifies the main class and places the enterprise bean JAR file in its classpath

    • An enterprise bean JAR file that contains both the session bean and the message-driven bean

    • An application EAR file that contains the two JAR files

      The clientsessionmdb.ear file is created in the clientsessionmdb-ear/target/ directory.

      The command then deploys the EAR file, retrieves the client stubs, and runs the client.

      The client displays these lines:

      To view the bean output,
       check <install_dir>/domains/domain1/logs/server.log.

      The output from the enterprise beans appears in the server log file. The Publisher session bean sends two sets of 18 messages numbered 0 through 17. Because of the message selector, the message-driven bean receives only the messages whose NewsType property is Sports or Opinion.

  4. Undeploy the application after you have finished running it:

    mvn cargo:undeploy

Using an Entity to Join Messages from Two MDBs

This section explains how to write, compile, package, deploy, and run an application that uses the Jakarta Messaging with an entity. The application uses the following components:

  • An application client that both sends and receives messages

  • Two message-driven beans

  • An entity class

You will find the source files for this section in the jakartaee-examples/tutorial/jms/clientmdbentity/ directory. Path names in this section are relative to this directory.

Overview of the clientmdbentity Example Application

This application simulates, in a simplified way, the work flow of a company’s human resources (HR) department when it processes a new hire. This application also demonstrates how to use the Jakarta EE platform to accomplish a task that many Messaging applications need to perform.

A messaging client must often wait for several messages from various sources. It then uses the information in all these messages to assemble a message that it then sends to another destination. The common term for this design pattern (which is not specific to Jakarta Messaging) is joining messages. Such a task must be transactional, with all the receives and the send as a single transaction. If not all the messages are received successfully, the transaction can be rolled back. For an application client example that illustrates this task, see Using Local Transactions.

A message-driven bean can process only one message at a time in a transaction. To provide the ability to join messages, an application can have the message-driven bean store the interim information in a Jakarta Persistence entity. The entity can then determine whether all the information has been received; when it has, the entity can report this back to one of the message-driven beans, which then creates and sends the message to the other destination. After it has completed its task, the entity can be removed.

The basic steps of the application are as follows.

  1. The HR department’s application client generates an employee ID for each new hire and then publishes a message (M1) containing the new hire’s name, employee ID, and position. It publishes the message to a topic because the message needs to be consumed by two message-driven beans. The client then creates a temporary queue, ReplyQueue, with a message listener that waits for a reply to the message. (See Creating Temporary Destinations for more information.)

  2. Two message-driven beans process each message: One bean, OfficeMDB, assigns the new hire’s office number, and the other bean, EquipmentMDB, assigns the new hire’s equipment. The first bean to process the message creates and persists an entity named SetupOffice, then calls a business method of the entity to store the information it has generated. The second bean locates the existing entity and calls another business method to add its information.

  3. When both the office and the equipment have been assigned, the entity business method returns a value of true to the message-driven bean that called the method. The message-driven bean then sends to the reply queue a message (M2) describing the assignments. Then it removes the entity. The application client’s message listener retrieves the information.

Figure 5, “An Enterprise Bean Application: Client to Message-Driven Beans to Entity” illustrates the structure of this application. Of course, an actual HR application would have more components; other beans could set up payroll and benefits records, schedule orientation, and so on.

Figure 5, “An Enterprise Bean Application: Client to Message-Driven Beans to Entity” assumes that OfficeMDB is the first message-driven bean to consume the message from the client. OfficeMDB then creates and persists the SetupOffice entity and stores the office information. EquipmentMDB then finds the entity, stores the equipment information, and learns that the entity has completed its work. EquipmentMDB then sends the message to the reply queue and removes the entity.

Diagram of application showing an application client, two message-driven beans, and an entity, as well as the associated topic and queue
Figure 5. An Enterprise Bean Application: Client to Message-Driven Beans to Entity

Writing the Application Components for the clientmdbentity Example

Writing the components of the application involves coding the application client, the message-driven beans, and the entity class.

Coding the Application Client: HumanResourceClient.java

The application client, HumanResourceClient.java, found under clientmdbentity-app-client, performs the following steps:

  1. Defines a topic for the application, using the java:app namespace because the topic is used in both the application client and the Jakarta Enterprise Beans module

  2. Injects ConnectionFactory and Topic resources

  3. Creates a TemporaryQueue to receive notification of processing that occurs, based on new-hire events it has published

  4. Creates a JMSConsumer for the TemporaryQueue, sets the JMSConsumer's message listener, and starts the connection

  5. Creates a MapMessage

  6. Creates five new employees with randomly generated names, positions, and ID numbers (in sequence) and publishes five messages containing this information

The message listener, HRListener, waits for messages that contain the assigned office and equipment for each employee. When a message arrives, the message listener displays the information received and determines whether all five messages have arrived. When they have, the message listener notifies the main method, which then exits.

Coding the Message-Driven Beans for the clientmdbentity Example

This example uses two message-driven beans, both under clientmdbentity-ejb:

  • EquipmentMDB.java

  • OfficeMDB.java

The beans take the following steps.

  1. They inject a MessageDrivenContext resource, an EntityManager, and a JMSContext.

  2. The onMessage method retrieves the information in the message. The EquipmentMDB's onMessage method chooses equipment, based on the new hire’s position; the OfficeMDB's onMessage method randomly generates an office number.

  3. After a slight delay to simulate real world processing hitches, the onMessage method calls a helper method, compose.

  4. The compose method takes the following steps.

    1. It either creates and persists the SetupOffice entity or finds it by primary key.

    2. It uses the entity to store the equipment or the office information in the database, calling either the doEquipmentList or the doOfficeNumber business method.

    3. If the business method returns true, meaning that all of the information has been stored, it retrieves the reply destination information from the message, creates a JMSProducer, and sends a reply message that contains the information stored in the entity.

    4. It removes the entity.

Coding the Entity Class for the clientmdbentity Example

The SetupOffice.java class, also under clientmdbentity-ejb, is an entity class. The entity and the message-driven beans are packaged together in an enterprise bean JAR file. The entity class is declared as follows:

@Entity
public class SetupOffice implements Serializable { ... }

The class contains a no-argument constructor and a constructor that takes two arguments, the employee ID and name. It also contains getter and setter methods for the employee ID, name, office number, and equipment list. The getter method for the employee ID has the @Id annotation to indicate that this field is the primary key:

@Id
public String getEmployeeId() {
    return id;
}

The class also implements the two business methods, doEquipmentList and doOfficeNumber, and their helper method, checkIfSetupComplete.

The message-driven beans call the business methods and the getter methods.

The persistence.xml file for the entity specifies the most basic settings:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="3.0"
             xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence
               https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
  <persistence-unit name="clientmdbentity-ejbPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>java:comp/DefaultDataSource</jta-data-source>
    <properties>
      <property name="eclipselink.ddl-generation"
                value="drop-and-create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Running the clientmdbentity Example

You can use either NetBeans IDE or Maven to build, deploy, and run the clientmdbentity example.

Because the example defines its own application-private topic and uses the preconfigured default connection factory java:comp/DefaultJMSConnectionFactory and the preconfigured default JDBC resource java:comp/DefaultDataSource, you do not need to create resources for it.

To Run clientmdbentity Using NetBeans IDE

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server), as well as the database server (see Starting and Stopping Apache Derby).

  2. From the File menu, choose Open Project.

  3. In the Open Project dialog box, navigate to:

    jakartaee-examples/tutorial/jms/clientmdbentity
  4. Select the clientmdbentity folder.

  5. Click Open Project.

  6. In the Projects tab, right-click the clientmdbentity project and select Build.

    This command creates the following:

    • An application client JAR file that contains the client class and listener class files, along with a manifest file that specifies the main class

    • An enterprise bean JAR file that contains the message-driven beans and the entity class, along with the persistence.xml file

    • An application EAR file that contains the two JAR files along with an application.xml file

      The clientmdbentity.ear file is created in the clientmdbentity-ear/target/ directory.

      The command then deploys the EAR file, retrieves the client stubs, and runs the application client.

To Run clientmdbentity Using Maven

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server), as well as the database server (see Starting and Stopping Apache Derby).

  2. Go to the following directory:

    jakartaee-examples/tutorial/jms/clientmdbentity/
  3. To compile the source files and package, deploy, and run the application, enter the following command:

    mvn install

    This command creates the following:

    • An application client JAR file that contains the client class and listener class files, along with a manifest file that specifies the main class

    • An enterprise bean JAR file that contains the message-driven beans and the entity class, along with the persistence.xml file

    • An application EAR file that contains the two JAR files along with an application.xml file

      The command then deploys the application, retrieves the client stubs, and runs the application client.

Viewing the Application Output

The output in the NetBeans IDE output window or in the terminal window looks something like this (preceded by application client container output and Maven output):

SENDER: Setting hire ID to 50, name Bill Tudor, position Programmer
SENDER: Setting hire ID to 51, name Carol Jones, position Senior Programmer
SENDER: Setting hire ID to 52, name Mark Wilson, position Manager
SENDER: Setting hire ID to 53, name Polly Wren, position Senior Programmer
SENDER: Setting hire ID to 54, name Joe Lawrence, position Director
Waiting for 5 message(s)
New hire event processed:
  Employee ID: 52
  Name: Mark Wilson
  Equipment: Tablet
  Office number: 294
Waiting for 4 message(s)
New hire event processed:
  Employee ID: 53
  Name: Polly Wren
  Equipment: Laptop
  Office number: 186
Waiting for 3 message(s)
New hire event processed:
  Employee ID: 54
  Name: Joe Lawrence
  Equipment: Mobile Phone
  Office number: 135
Waiting for 2 message(s)
New hire event processed:
  Employee ID: 50
  Name: Bill Tudor
  Equipment: Desktop System
  Office number: 200
Waiting for 1 message(s)
New hire event processed:
  Employee ID: 51
  Name: Carol Jones
  Equipment: Laptop
  Office number: 262

The output from the message-driven beans and the entity class appears in the server log.

For each employee, the application first creates the entity and then finds it. You may see runtime errors in the server log, and transaction rollbacks may occur. The errors occur if both of the message-driven beans discover at the same time that the entity does not yet exist, so they both try to create it. The first attempt succeeds, but the second fails because the bean already exists. After the rollback, the second message-driven bean tries again and succeeds in finding the entity. Container-managed transactions allow the application to run correctly, in spite of these errors, with no special programming.

To undeploy the application after you have finished running it, use the Services tab or issue the mvn cargo:undeploy command.

Using NetBeans IDE to Create Jakarta Messaging Resources

When you write your own Messaging applications, you will need to create resources for them. This section explains how to use NetBeans IDE to create src/main/setup/glassfish-resources.xml files similar to those used in the examples in this chapter. It also explains how to use NetBeans IDE to delete the resources.

You can also create, list, and delete Jakarta Messaging resources using the Administration Console or the asadmin create-jms-resource, asadmin list-jms-resources, and asadmin delete-jms-resources commands. For information, consult the GlassFish Server documentation or enter asadmin help command-name.

To Create Jakarta Messaging Resources Using NetBeans IDE

Follow these steps to create a Jakarta Messaging resource in GlassFish Server using NetBeans IDE. Repeat these steps for each resource you need.

  1. Right-click the project for which you want to create resources and select New, then select Other.

  2. In the New File wizard, under Categories, select GlassFish.

  3. Under File Types, select JMS Resource.

  4. On the General Attributes - JMS Resource page, in the JNDI Name field, enter the name of the resource.

    By convention, Messaging resource names begin with jms/.

  5. Select the option for the resource type.

    Normally, this is either jakarta.jms.Queue, jakarta.jms.Topic, or jakarta.jms.ConnectionFactory.

  6. Click Next.

  7. On the JMS Properties page, for a queue or topic, enter a name for a physical queue in the Value field for the Name property.

    You can enter any value for this required field.

    Connection factories have no required properties. In a few situations, you may need to specify a property.

  8. Click Finish.

    A file named glassfish-resources.xml is created in your Maven project, in a directory named src/main/setup/. In the Projects tab, you can find it under the Other Sources node. You will need to run the asadmin add-resources command to create the resources in GlassFish Server.

To Delete Jakarta Messaging Resources Using NetBeans IDE

  1. In the Services tab, expand the Servers node, then expand the GlassFish Server node.

  2. Expand the Resources node, then expand the Connector Resources node.

  3. Expand the Admin Object Resources node.

  4. Right-click any destination you want to remove and select Unregister.

  5. Expand the Connector Connection Pools node.

  6. Right-click the connection pool that corresponds to the connection factory you removed and select Unregister.

    When you remove a connector connection pool, the associated connector resource is also deleted. This action removes the connection factory.