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:
-
Use NetBeans IDE or Maven to compile, package, and in some cases deploy the example.
-
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.
Example Directory | Description |
---|---|
|
Using an application client to send messages; see Sending Messages |
|
Using an application client to receive messages synchronously; see Receiving Messages Synchronously |
|
Using an application client to receive messages asynchronously; see Using a Message Listener for Asynchronous Message Delivery |
|
Using an application client to use a |
|
Using an application client to acknowledge messages received synchronously; see Acknowledging Messages |
|
Using an application client to create a durable subscription on a topic; see Using Durable Subscriptions |
|
Using an application client to send and receive messages in local transactions (also uses request-reply messaging); see Using Local Transactions |
|
Using an application client to create shared nondurable topic subscriptions; see Using Shared Nondurable Subscriptions |
|
Using an application client to create shared durable topic subscriptions; see Using Shared Durable Subscriptions |
Example Directory | Description |
---|---|
|
Using managed beans to send messages and to receive messages synchronously; see Sending and Receiving Messages Using a Simple Web Application |
|
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 |
|
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 |
|
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.
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a command window, go to the
Producer
example.cd jakartaee-examples/tutorial/jms/simple/producer
-
Create the resources using the
asadmin add-resources
command:asadmin add-resources src/main/setup/glassfish-resources.xml
-
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 namedjms/__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
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
jakartaee-examples/tutorial/jms
-
Expand the
jms
node and select thesimple
folder. -
Click Open Project to open all the simple examples.
-
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
-
In a terminal window, go to the
simple
directory:cd jakartaee-examples/tutorial/jms/simple/
-
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.
-
Inject resources for the administered objects used by the example.
-
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.
-
Create a
JMSContext
, then send the specified number of text messages in the form of strings, as described in Message Bodies. -
Send a final message of type
Message
to indicate that the consumer should expect no more messages. -
Catch any exceptions.
The Producer.java Client
The sending client, Producer.java
, performs the following steps.
-
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;
-
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; }
-
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); }
-
Within a
try-with-resources
block, creates aJMSContext
:try (JMSContext context = connectionFactory.createContext();) { ... }
-
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 theTextMessage
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);
-
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.
-
Catches and handles any exceptions. The end of the
try-with-resources
block automatically causes theJMSContext
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.
-
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).
-
In a terminal window, go to the
producer
directory:cd producer
-
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.
-
Injects resources for a connection factory, queue, and topic.
-
Assigns either the queue or the topic to a destination object, based on the specified destination type.
-
Within a
try-with-resources
block, creates aJMSContext
. -
Creates a
JMSConsumer
, starting message delivery:consumer = context.createConsumer(dest);
-
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 thewhile
loop and stops receiving messages after the control message arrives. -
Catches and handles any exceptions. The end of the
try-with-resources
block automatically causes theJMSContext
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.
-
In the same terminal window where you ran
Producer
, go to thesynchconsumer
directory:cd ../synchconsumer
-
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
-
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.
-
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. -
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
-
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.
-
Leave the
SynchConsumer
client running and run theProducer
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.
-
The client,
AsynchConsumer.java
, performs the following steps.-
Injects resources for a connection factory, queue, and topic.
-
Assigns either the queue or the topic to a destination object, based on the specified destination type.
-
In a
try-with-resources
block, creates aJMSContext
. -
Creates a
JMSConsumer
. -
Creates an instance of the
TextListener
class and registers it as the message listener for theJMSConsumer
:listener = new TextListener(); consumer.setMessageListener(listener);
-
Listens for the messages sent to the destination, stopping when the user types the character
q
orQ
(it uses ajava.io.InputStreamReader
to do this). -
Catches and handles any exceptions. The end of the
try-with-resources
block automatically causes theJMSContext
to be closed, thus stopping delivery of messages to the message listener.
-
-
The message listener,
TextListener.java
, follows these steps:-
When a message arrives, the
onMessage
method is called automatically. -
If the message is a
TextMessage
, theonMessage
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.
-
In the terminal window where you ran the
SynchConsumer
client, go to theasynchconsumer
example directory:cd jakartaee-examples/tutorial/jms/simple/asynchconsumer
-
Run the
AsynchConsumer
client, specifying thetopic
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>
-
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. -
Enter
Q
orq
and press Return to stop theAsynchConsumer
client. -
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
-
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
-
Enter
Q
orq
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.
-
Injects resources for a connection factory and a queue.
-
In a
try-with-resources
block, creates aJMSContext
. -
Creates a
QueueBrowser
:QueueBrowser browser = context.createBrowser(queue);
-
Retrieves the
Enumeration
that contains the messages:Enumeration msgs = browser.getEnumeration();
-
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); } }
-
Catches and handles any exceptions. The end of the
try-with-resources
block automatically causes theJMSContext
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.
-
In a terminal window, go to the
producer
directory:cd jakartaee-examples/tutorial/jms/simple/producer/
-
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
-
In another terminal window, go to the
messagebrowser
directory:cd jakartaee-examples/tutorial/jms/simple/messagebrowser
-
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. -
Go to the
synchconsumer
directory. -
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.
-
Open three command windows. In one, go to the
producer
directory. In the other two, go to thesynchconsumer
directory. -
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.
-
In the
producer
window, run the client, sending 20 or so messages to the queue:appclient -client target/producer.jar queue 20
-
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. -
In the window of the client that did not receive the non-text control message, enter Control-C to exit the program.
-
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.
-
In the
producer
window, run the client, sending 20 or so messages to the topic:appclient -client target/producer.jar topic 20
-
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 theCLIENT_ACKNOWLEDGE
setting -
Using a message listener for asynchronous message delivery in a
JMSContext
that has been configured to use the defaultAUTO_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.
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 |
Asynchronous |
Auto |
Message is automatically acknowledged when |
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
-
In a terminal window, go to the following directory:
jakartaee-examples/tutorial/jms/simple/producer/
-
Run the
Producer
client, sending some messages to the queue:appclient -client target/producer.jar queue 3
-
In another terminal window, go to the following directory:
jakartaee-examples/tutorial/jms/simple/clientackconsumer/
-
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 useAUTO_ACKNOWLEDGE
does automatically after aMessageListener
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a command window, go to the
durableconsumer
example.cd jakartaee-examples/tutorial/jms/durablesubscriptionexample/durableconsumer
-
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.
-
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
-
In a terminal window, go to the following directory:
jakartaee-examples/tutorial/jms/durablesubscriptionexample/
-
Build the
durableconsumer
andunsubscriber
examples:mvn install
-
Go to the
durableconsumer
directory:cd durableconsumer
-
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>
-
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
-
After the
DurableConsumer
client receives the messages, enterq
orQ
to exit the program. At this point, the client has behaved like any other asynchronous consumer. -
Now, while the
DurableConsumer
client is not running, use theProducer
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.
-
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
-
Enter
q
orQ
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.
-
In a terminal window, go to the following directory:
jakartaee-examples/tutorial/jms/durablesubscriptionexample/unsubscriber
-
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.
-
A retailer (
retailer/src/main/java/jakarta/tutorial/retailer/Retailer.java
) sends aMapMessage
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);
-
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.
-
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’sJMSReplyTo
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();
-
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();
-
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();
-
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.
Figure 1, “Transactions: Messaging Client Example” illustrates these steps.
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a command window, go to the
genericsupplier
example:cd jakartaee-examples/tutorial/jms/transactedexample/genericsupplier
-
Create the resources using the
asadmin add-resources
command:asadmin add-resources src/main/setup/glassfish-resources.xml
-
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.
-
In a terminal window, go to the following directory:
jakartaee-examples/tutorial/jms/transactedexample/
-
To build and package all the modules, enter the following command:
mvn install
-
Go to the
genericsupplier
directory:cd genericsupplier
-
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
-
In a second terminal window, go to the
genericsupplier
directory:cd jakartaee-examples/tutorial/jms/transactedexample/genericsupplier
-
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
-
In a third terminal window, go to the
vendor
directory:cd jakartaee-examples/tutorial/jms/transactedexample/vendor
-
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
-
In another terminal window, go to the
retailer
directory:cd jakartaee-examples/tutorial/jms/transactedexample/retailer
-
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
-
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
-
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.
-
Injects resources for a connection factory and topic.
-
In a
try-with-resources
block, creates aJMSContext
. -
Creates a consumer on a shared nondurable subscription, specifying a subscription name:
consumer = context.createSharedConsumer(topic, "SubName");
-
Creates an instance of the
TextListener
class and registers it as the message listener for the shared consumer. -
Listens for the messages published to the destination, stopping when the user types the character
q
orQ
. -
Catches and handles any exceptions. The end of the
try-with-resources
block automatically causes theJMSContext
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
Open three command windows. In the first, go to the
simple/producer/
directory:cd jakartaee-examples/tutorial/jms/simple/producer/
-
In the second and third command windows, go to the
shared/sharedconsumer/
directory:cd jakartaee-examples/tutorial/jms/shared/sharedconsumer/
-
In one of the
sharedconsumer
windows, build the example:mvn install
-
In each of the two
sharedconsumer
windows, start running the client. You do not need to specify atopic
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>
-
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.
-
Enter
Q
orq
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
-
In a terminal window, go to the following directory:
jakartaee-examples/tutorial/jms/shared/shareddurableconsumer
-
To compile and package the client, enter the following command:
mvn install
-
Run the client first to establish the durable subscription:
appclient -client target/shareddurableconsumer.jar
-
The client displays the following and pauses:
Waiting for messages on topic To end program, enter Q or q, then <return>
-
In the
shareddurableconsumer
window, enterq
orQ
to exit the program. The subscription remains active, although the client is not running. -
Open another terminal window and go to the
producer
example directory:cd jakartaee-examples/tutorial/jms/simple/producer
-
Run the
producer
example, sending a number of messages to the topic:appclient -client target/producer.jar topic 6
-
After the producer has sent the messages, open a third terminal window and go to the
shareddurableconsumer
directory. -
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
-
With both
shareddurableconsumer
clients still running, go to theproducer
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.
The websimplemessage Facelets Pages
The Facelets pages for the example are as follows.
-
sender.xhtml
, which provides a labeledh:InputText
tag where the user enters the message, along with two command buttons. When the user clicks the Send Message button, thesenderBean.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, thereceiver.xhtml
page appears. -
receiver.xhtml
, which also provides two command buttons. When the user clicks the Receive Message button, thereceiverBean.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 aJMSContext
(using the default connection factory) and the queue, creates a producer, sends the message the user typed on the Facelets page, and creates aFacesMessage
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 aJMSContext
(using the default connection factory) and the queue that was defined inSenderBean
, creates a consumer, receives the message, and creates aFacesMessage
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
jakartaee-examples/tutorial/jms
-
Select the
websimplemessage
folder. -
Click Open Project.
-
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a terminal window, go to:
jakartaee-examples/tutorial/jms/websimplemessage/
-
To compile the source files and package and deploy the application, use the following command:
mvn install
To Run the websimplemessage Example
-
In a web browser, enter the following URL:
http://localhost:8080/websimplemessage
-
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
-
Click Go to Receive Page.
-
Click Receive Message.
The following appears below the buttons:
Reading message: Message from producer: Hello, Duke
-
Click Send Another Message to return to the sending page.
-
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.
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
jakartaee-examples/tutorial/jms/simplemessage
-
Select the
simplemessage
folder. -
Make sure that the Open Required Projects check box is selected, then click Open Project.
-
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 thesimplemessage-ear/target/
directory. It then deploys thesimplemessage-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.
-
After you have finished running the application, undeploy it using the Services tab.
To Run the simplemessage Example Using Maven
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a terminal window, go to:
jakartaee-examples/tutorial/jms/simplemessage/
-
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 thesimplemessage-ear/target/
directory. It then deploys thesimplemessage-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.
-
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.
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
jakartaee-examples/tutorial/jms/clientsessionmdb
-
Select the
clientsessionmdb
folder. -
Make sure that the Open Required Projects check box is selected, then click Open Project.
-
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:
-
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
-
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 theclientsessionmdb-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 isSports
orOpinion
.
-
-
Use the Services tab to undeploy the application after you have finished running it.
To Run clientsessionmdb Using Maven
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
Go to the following directory:
jakartaee-examples/tutorial/jms/clientsessionmdb/
-
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 theclientsessionmdb-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 isSports
orOpinion
.
-
-
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.
-
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.) -
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 namedSetupOffice
, 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. -
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.
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:
-
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 -
Injects
ConnectionFactory
andTopic
resources -
Creates a
TemporaryQueue
to receive notification of processing that occurs, based on new-hire events it has published -
Creates a
JMSConsumer
for theTemporaryQueue
, sets theJMSConsumer
's message listener, and starts the connection -
Creates a
MapMessage
-
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.
-
They inject a
MessageDrivenContext
resource, anEntityManager
, and aJMSContext
. -
The
onMessage
method retrieves the information in the message. TheEquipmentMDB
'sonMessage
method chooses equipment, based on the new hire’s position; theOfficeMDB
'sonMessage
method randomly generates an office number. -
After a slight delay to simulate real world processing hitches, the
onMessage
method calls a helper method,compose
. -
The
compose
method takes the following steps.-
It either creates and persists the
SetupOffice
entity or finds it by primary key. -
It uses the entity to store the equipment or the office information in the database, calling either the
doEquipmentList
or thedoOfficeNumber
business method. -
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 aJMSProducer
, and sends a reply message that contains the information stored in the entity. -
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
-
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).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
jakartaee-examples/tutorial/jms/clientmdbentity
-
Select the
clientmdbentity
folder. -
Click Open Project.
-
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
fileThe
clientmdbentity.ear
file is created in theclientmdbentity-ear/target/
directory.The command then deploys the EAR file, retrieves the client stubs, and runs the application client.
-
To Run clientmdbentity Using Maven
-
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).
-
Go to the following directory:
jakartaee-examples/tutorial/jms/clientmdbentity/
-
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
fileThe 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.
-
Right-click the project for which you want to create resources and select New, then select Other.
-
In the New File wizard, under Categories, select GlassFish.
-
Under File Types, select JMS Resource.
-
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/
. -
Select the option for the resource type.
Normally, this is either
jakarta.jms.Queue
,jakarta.jms.Topic
, orjakarta.jms.ConnectionFactory
. -
Click Next.
-
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.
-
Click Finish.
A file named
glassfish-resources.xml
is created in your Maven project, in a directory namedsrc/main/setup/
. In the Projects tab, you can find it under the Other Sources node. You will need to run theasadmin add-resources
command to create the resources in GlassFish Server.
To Delete Jakarta Messaging Resources Using NetBeans IDE
-
In the Services tab, expand the Servers node, then expand the GlassFish Server node.
-
Expand the Resources node, then expand the Connector Resources node.
-
Expand the Admin Object Resources node.
-
Right-click any destination you want to remove and select Unregister.
-
Expand the Connector Connection Pools node.
-
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.