An application sends a message to the JMS provider using a javax.jms.JMSProducer
producer. This producer can be obtained from a JMSContext
in the simplified API in JMS 2.0 by calling the
createProducer()
method.
In JMS 1.1, creating a javax.jms.MessageProducer
object sends the messages. Developers who are fortunate enough to experience this API will see code that looks similar to this:
// JMS 1.1 Connection conx = queueConnectionFactory.createConnection(); Session session = conx.createSession(true, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer() producer.setDeliverDelay(10*1000) producer.setPriority(7) producer.setTimeToLive(1000) producer.setDeliverMode(DeliveryMode.NON_PERSISTENT) producer.send(destination, message );
The older API only provides bean setter methods in order to configure destination parameters. JMSProducer
is the preferred way for JMS 2.0 because it always supports the fluent-style of interface; it has method chaining:
// JMS 2.0 JMSContext context = /* Injected */ JMSProducer producer = context.createProducer() producer.setDeliverDelay(10*1000) .setTimeToLive(1000) .setPriority(7) .setDeliverMode(DeliveryMode.NON_PERSISTENT) .send(destination, message );
The method chaining is clearer, eminently readable, and affords declarative code.
Synchronous sending occurs when the JMS client sends a message to the channel and the provider does not return the thread of control to the sender until it knows that the consumer endpoint has received and acknowledged that successful consumption of the message. This is an example of block-and-wait.
The JMSProducer
defines these methods as synchronous operations in the simplified API:
send(Destination destination, Message message) send(Destination destination, String body) send(Destination destination, Map<String,Object> body) send(Destination destination, byte[] body) send(Destination destination, Serializable body) send(Destination destination, String body)
Note that there is no need to create the intermediate Message
type object. Incidentally, the developer can set custom key value and pair properties on the JMSProducer
instance using the method
setStringProperty()
.
A JMSProducer
can also send messages asynchronously so the caller does not block-and-wait on the consumer to successfully acknowledge the message on the channel. This is a performance feature that is intended for unmanaged environment Java SE applications rather than inside an application server.
The JMSProducer
defines a setAsync()
method in the simplified API and it takes a single argument: an implementation of the Java interface class javax.jms.CompletionListener
.
The definition of CompletionListener
is as follows:
package javax.jms; public interface CompletionListener { void onCompletion(Message message); void onException(Message message, Exception exception); }
A completion listener must be registered prior to calling any of the send()
overloaded methods on JMSPublisher
. The JMS provider invokes the callback onCompletion()
method when the consumer successfully consumes the message. It will invoke the callback method
onException()
instead when a failure occurs delivering the message to the consumer.
setAsync()
on a JMSProducer
may not be called inside a Java EE web or EJB container. Asynchronous sending is designed for standard JMS applications running on Java SE. There is another way, and that is to write a concurrent worker, java.lang.Runnable
or java.util.concurrency.Callable,
that creates and sends messages on a destination object, JMSProducer
. Concurrent tasks are made available in Java EE 7 Concurrency Utilities (JSR 236) through the new service ManagedExecutorService
. Read more in Appendix D, Java EE 7 Assorted Topics.
Every JMS message has a map collection of header fields which are name and value pairs. The message header is sent to all the JMS clients and they are able to read the complete message with the headers on the consumer side.
The names of the header fields begin with the prefix 'JMS' string; here is a table of the headers and their descriptions:
Most of these properties are set on the javax.jms.Message
type, but they can be set on the JMSProducer
type directly in a fluent API style.
The standard reserves the JMSX
property prefix for JMSdefined properties. These are defined as key and value pairs on the message header and are important for message consumers.
An application can also set additional properties on JMS messages just before it is sent to the provider. There is a complete set of overloaded setProperty()
methods for every Java primitive except char
. The method setProperty( String, Object )
allows a Java primitive wrapper to be passed such as java.lang.Long
. Calling setProperty
with the same key and a different value overwrites the previous key-value association.
In JMS 2.0, it is also possible to set a delivery delay on messages in which the case JMS provider understands that the message must be delayed on the message destination and not delivered until the delay period expires.
An application can call the method setDeliveryDelay(long)
on the JMSProducer
instance, which accepts a single argument: the delay period in milliseconds.
Delivery delay of bank trade messages
Why is this feature so useful? Imagine a bank that trades on the stock market in two geographic locations. One location for the bank is in London, Great Britain, and the other in New York, United States. The financial centers are only open for certain trading hours during the day. Let us say that both are open from 08:00 to 16:00. Let's also say we have a trader called Brian in London who agrees a new deal with a counterparty and then creates a new trade at exactly 09:00. This trade is dependent on a derivative data that is derived from information effective in the USA. The full execution of the trade cannot take place until the market in New York opens in four hours time at 01:00 London time because the time zone difference between London and New York is five hours (GMT -5:00). The London trading system can still post a trade message to the downstream system for further execution because it can add a special message property to delay delivery of the message for 4 hours. The downstream will only receive the trade message once the delay expires.
3.144.26.138