Advanced JMS Messaging with OpenJMS JMSUPSUN
程序员文章站
2022-07-09 21:08:21
...
Learn to use the more advanced features of OpenJMS to filter messages, create clients that can receive messages sent even when they aren't running, and create persistent messages that can survive a provider failure.
by Kulvir Singh Bhogal
n a previous article I covered some of the basics of JMS using OpenJMS as the JMS provider. In this article, you'll see some more advanced OpenJMS topics such as message selectors, durable subscriptions, and message persistence along with code examples that show you how to implement these concepts programmatically.
Message Selectors
Sometimes you don't want message consumers to receive every message sent by a sender or publisher. Instead you want to be able to filter received messages. The JMS API provides this facility through message selectors. The message consumer specifies which messages it is interested in. The JMS provider then selectively sends just those messages to the client. Note that the onus of filtering messages is left up to the JMS provider, not the consuming application. The provider can scrutinize the header values and message properties with message selectors, but unfortunately, OpenJMS cannot analyze the incoming message bodies. I'll show you an example message selector in just a bit, but first here are a couple of topics (no JMS pun intended) to set the stage.
Message Header Fields
When a JMS provider sends a message it generates the following header fields:
* JMSMessageID—A unique message identifier
* JMSDestination—The queue or topic to which the message is sent.
* JMSRedelivered—States whether the message has been resent
The client sending application can set a number of header fields. Refer to the JMS API documentation for a full breakdown of what headers the client can set. Each header field has getter and setter methods. Some of the fields the client can set include:
* JMSPriority—You can set a message priority from 0 to 9 (9 being the highest priority and 4 being the default). However, note that the there is no guarantee that higher priority messages will be delivered before lower priority ones.
* JMSType—String identifying contents of a message
* JMSReplyTo—Where responses should be sent
* JMSExpiration—An expiration time for the message
Message Properties
While the preceding message header fields are predefined, clients can add more information to JMS messages via the extensibility of properties. These properties are name/value pairs which the client application defines. The values for properties can be of type boolean, byte, short, int, long, float, double, or string (each type has a corresponding Message.setProperty method). For example, using the syntax below, you could set a property named "Sport" to "Basketball"
Message.setStringProperty("Sport","Basketball");
Using Message Selectors
Here's an example that incorporates message properties, a message priority, and message selectors. Here's the scenario. A producer application publishes messages to a topic (see Figure 1). The messages have different JMS priorities and different message properties. One consumer application for this topic is finicky; it specifies to the JMS provider that it wants to filter the messages it will receive by using a message selector.
This example uses OpenJMS, an open source implementation of Sun Microsystem's Java Message Service API 1.0.2 specification as the JMS provider. You can learn more about the OpenJMS server at http://www.devx.com/Java/Article/20903.
The code fragment shown below (see the file PublishToTopic.java in the downloadable sample code for the full listing) is from the producer application.
TextMessage messageOne =
topicSession.createTextMessage();
message = "Message #1 - Sport: Basketball " + hour12 +
":" + min + ":" + sec;
messageOne.setText(message);
messageOne.setStringProperty("Sport", "Basketball");
topicPublisher.publish(messageOne,
DeliveryMode.PERSISTENT, 9, 999999);
Figure 1: The message producer publishes messages to the topic with different "Sport" property values.
Note that you need to have the consumer (which we'll cover in just a bit) running before you run PublishToTopic. You can mitigate this timing dependency with durable subscriptions which I'll cover later in this article.
The PublishToTopic application sends four different messages to the topic named "topic1." The publisher sets the "Sport" property to different values for different messages and also sets different priorities for each message using the publish method.
void publish(Message message, int deliveryMode,
int priority, long timeToLive)
Using the publish method, you can specify a JMSPriority (from 0-9, with 9 being the highest priority and 4 being the default). It's important to note that if you use the setPriority method of the MessageProducer interface, you set the priority level of all the messages sent by the producer; whereas, by default, if you do not set a priority level, the default level is 4. To set the priority of a particular message, use the publish(Message, int, int , long) method. The publish method also lets you specify a delivery mode and a "time to live" for the message. By default, a message never expires. If a message being sent will become obsolete after a certain period of time, you can specify its time to live via the fourth argument of the publish method. You specify the time to live in milliseconds. The delivery mode can be either the value deliveryMode.PERSISTENT or deliveryMode.NON_PERSISTENT.
The consumer application, ConsumerUsingFilters.java (a section of which is shown below) listens asynchronously to the topic. You can see that the subscriber filters its consumption of messages via the SQL92 string: "Sport in ('Basketball','Football')"
// create a topic subscriber and associate
// a filtering criterion
String filterQuery =
"Sport in ('Basketball','Football')";
topicSubscriber =
topicSession.createSubscriber(topic,
filterQuery, false);
The code shown above states that the client only wants messages where the property "Sport" is set to either "Basketball" or "Football." Messages having the property set to "Hockey" and "Baseball" will not be consumed because they will be filtered out by the subscribing application. This can be seen in Figure 2, which shows the consumer application running:
Figure 2: The Consumer application selectively filters messages based on the value of the "Sport" property.
You can also filter using message priority. For example, you can change the filter query to:
String filterQuery = "JMSPriority > 6";
topicSubscriber =
topicSession.createSubscriber(topic,
filterQuery, false);
Now when you run the client application, Figure 3 shows that the application consumes only messages with a JMSPriority higher than 6. Everything else was filtered.
Figure 3: The modified consumer application filters messages based on the JMSPriority.
by Kulvir Singh Bhogal
n a previous article I covered some of the basics of JMS using OpenJMS as the JMS provider. In this article, you'll see some more advanced OpenJMS topics such as message selectors, durable subscriptions, and message persistence along with code examples that show you how to implement these concepts programmatically.
Message Selectors
Sometimes you don't want message consumers to receive every message sent by a sender or publisher. Instead you want to be able to filter received messages. The JMS API provides this facility through message selectors. The message consumer specifies which messages it is interested in. The JMS provider then selectively sends just those messages to the client. Note that the onus of filtering messages is left up to the JMS provider, not the consuming application. The provider can scrutinize the header values and message properties with message selectors, but unfortunately, OpenJMS cannot analyze the incoming message bodies. I'll show you an example message selector in just a bit, but first here are a couple of topics (no JMS pun intended) to set the stage.
Message Header Fields
When a JMS provider sends a message it generates the following header fields:
* JMSMessageID—A unique message identifier
* JMSDestination—The queue or topic to which the message is sent.
* JMSRedelivered—States whether the message has been resent
The client sending application can set a number of header fields. Refer to the JMS API documentation for a full breakdown of what headers the client can set. Each header field has getter and setter methods. Some of the fields the client can set include:
* JMSPriority—You can set a message priority from 0 to 9 (9 being the highest priority and 4 being the default). However, note that the there is no guarantee that higher priority messages will be delivered before lower priority ones.
* JMSType—String identifying contents of a message
* JMSReplyTo—Where responses should be sent
* JMSExpiration—An expiration time for the message
Message Properties
While the preceding message header fields are predefined, clients can add more information to JMS messages via the extensibility of properties. These properties are name/value pairs which the client application defines. The values for properties can be of type boolean, byte, short, int, long, float, double, or string (each type has a corresponding Message.setProperty method). For example, using the syntax below, you could set a property named "Sport" to "Basketball"
Message.setStringProperty("Sport","Basketball");
Using Message Selectors
Here's an example that incorporates message properties, a message priority, and message selectors. Here's the scenario. A producer application publishes messages to a topic (see Figure 1). The messages have different JMS priorities and different message properties. One consumer application for this topic is finicky; it specifies to the JMS provider that it wants to filter the messages it will receive by using a message selector.
This example uses OpenJMS, an open source implementation of Sun Microsystem's Java Message Service API 1.0.2 specification as the JMS provider. You can learn more about the OpenJMS server at http://www.devx.com/Java/Article/20903.
The code fragment shown below (see the file PublishToTopic.java in the downloadable sample code for the full listing) is from the producer application.
TextMessage messageOne =
topicSession.createTextMessage();
message = "Message #1 - Sport: Basketball " + hour12 +
":" + min + ":" + sec;
messageOne.setText(message);
messageOne.setStringProperty("Sport", "Basketball");
topicPublisher.publish(messageOne,
DeliveryMode.PERSISTENT, 9, 999999);
Figure 1: The message producer publishes messages to the topic with different "Sport" property values.
Note that you need to have the consumer (which we'll cover in just a bit) running before you run PublishToTopic. You can mitigate this timing dependency with durable subscriptions which I'll cover later in this article.
The PublishToTopic application sends four different messages to the topic named "topic1." The publisher sets the "Sport" property to different values for different messages and also sets different priorities for each message using the publish method.
void publish(Message message, int deliveryMode,
int priority, long timeToLive)
Using the publish method, you can specify a JMSPriority (from 0-9, with 9 being the highest priority and 4 being the default). It's important to note that if you use the setPriority method of the MessageProducer interface, you set the priority level of all the messages sent by the producer; whereas, by default, if you do not set a priority level, the default level is 4. To set the priority of a particular message, use the publish(Message, int, int , long) method. The publish method also lets you specify a delivery mode and a "time to live" for the message. By default, a message never expires. If a message being sent will become obsolete after a certain period of time, you can specify its time to live via the fourth argument of the publish method. You specify the time to live in milliseconds. The delivery mode can be either the value deliveryMode.PERSISTENT or deliveryMode.NON_PERSISTENT.
The consumer application, ConsumerUsingFilters.java (a section of which is shown below) listens asynchronously to the topic. You can see that the subscriber filters its consumption of messages via the SQL92 string: "Sport in ('Basketball','Football')"
// create a topic subscriber and associate
// a filtering criterion
String filterQuery =
"Sport in ('Basketball','Football')";
topicSubscriber =
topicSession.createSubscriber(topic,
filterQuery, false);
The code shown above states that the client only wants messages where the property "Sport" is set to either "Basketball" or "Football." Messages having the property set to "Hockey" and "Baseball" will not be consumed because they will be filtered out by the subscribing application. This can be seen in Figure 2, which shows the consumer application running:
Figure 2: The Consumer application selectively filters messages based on the value of the "Sport" property.
You can also filter using message priority. For example, you can change the filter query to:
String filterQuery = "JMSPriority > 6";
topicSubscriber =
topicSession.createSubscriber(topic,
filterQuery, false);
Now when you run the client application, Figure 3 shows that the application consumes only messages with a JMSPriority higher than 6. Everything else was filtered.
Figure 3: The modified consumer application filters messages based on the JMSPriority.