What is new in JMS 2.0
In software integration landscape, it is an essential requirement to communicate from one software component to another. While there is a lot of technologies emerged with the capability of doing that, Java programming language provides us with an API to facilitate messaging between components written in Java. The implementation of this API will be provided by different vendors (JMS Providers) with broker software.
This API is called Java Message Service (JMS).
Last update to JMS specification was done in 2002 which brought up JMS 1.1. Since then, over the years, this API was used in many software components around the world, proving its developer friendliness. The next version of JMS (JMS 2.0) emerged in April 2013, may years later since 1.1 version.
JMS 2.0 can be used only with Java SE 7 and above. It will be interesting to have a look on what is new in JMS 2.0.
Ease-of-use language features
The most significant change done to the API in language perspective is reducing the amount of code a developer need to write. Let’s compare JMS 2.0 with 1.1 to identify what there are.
Connection and session objects brought into a single JMSContext
There is no need to create connection and session objets anymore. You can create JMSContext and directly use that to create the message producer.
No need to call connection.close()
However, there’s no need to explicitly call close from your code. JMSContext implements the Java SE 7 java.lang.AutoCloseable interface. This means that if we create the JMSContext in a try-with-resources block (also a new feature of Java SE 7), the close method will be called automatically at the end of the block without the need to explicitly add it to your code.
Please refer above example.
No need to pass in two parameters when creating a session
In JMS 1.1 there is an additional parameter to pass to specify if the session is transacted. In JMS 2.0 it is enough to pass Session.SESSION_TRANSACTED
.
If we wanted to specify one of the other session modes (local transaction, CLIENT_ACKNOWLEDGE, or DUPS_OK_ACKNOWLEDGE), we would pass in just a single parameter rather than two. If you need the session to be in Session.AUTO_ACKNOWLEDGE, no need to pass any arguments as it is the default.
Support for method chaining
This drastically reduces the amount of code to be written. Please refer below example.
In Java EE, injecting a JMSContext means you don’t need to create or close it
When sending, no need to instantiate a Message object
Note that you can do this even when you want to set message properties since these can be set on the JMSProducer.
Receive message payload directly
When receiving synchronously, you are given a Message object and need to cast it to the appropriate subtype before you can extract its body.
No need for a cast before extracting message body
When receiving a message asynchronously, the message passed to the onMessage method is a javax.jms.Message You need to cast it to the expected subtype before you can extract the body. If the message is an ObjectMessage this gives you a Serializable body which you have to cast a second time to the expected body type. A new method getBody
allows you to extract the body from the Message
without the need to cast it to the appropriate subtype first.
Five New Features
JMS 2.0 introduces a few new messaging features as well.
1. Multiple consumers allowed on the same topic subscription
JMS 1.1 has a limitation that only one subscriber can be made having a particular subscription ID for a topic. This restricts us from having load distributed among several JVMs, machines, as we cannot create another subscription with same ID.
JMS 2.0 provides a solution. You can create a “shared” nondurable subscription using a new method: createSharedConsumer. This method is available both on Session (for applications using the classic API) and on JMSContext (for applications using the simplified API). Since the two JVMs need to be able to identify the subscription that they need to share, they need to supply a name to identify the shared subscription, as shown below.
If you run the above code in two separate JVMs, each message sent to the topic will be delivered to one or the other of the two consumers. This allows them to share the work of processing messages from the subscription.
2. Delivery delay
You can now specify a delivery delay on a message. The JMS provider will not deliver the message until after the specified delivery delay has elapsed.
3. Sending messages asynchronously
This feature is available for applications running in Java SE or the Java EE application client container. It is not available to applications that run in the Java EE Web or EJB container.
Normally, when a persistent message is sent, the send method does not return until the JMS client has sent the message to the server and received a reply to notify the client that the message has been safely received and persisted. We call this a synchronous send.
JMS 2.0 introduces the ability to perform an asynchronous send. When a message is sent asynchronously, the send method sends the message to the server and then returns control to the application without waiting for a reply from the server.
When a reply is received back from the server to indicate that the message has been received by the server and persisted, the JMS provider notifies the application by invoking the callback method onCompletion on an application-specified CompletionListener object.
This is useful to allow a large number of messages to be sent in succession without waiting for a reply from the server after each message.
4. JMSXDeliveryCount
JMS 2.0 allows applications that receive a message to determine how many times the message has been redelivered. This information can be obtained from the message property JMSXDeliveryCount:
int deliveryCount = message.getIntProperty(“JMSXDeliveryCount”);
The JMSXDeliveryCount property allows a consuming application to detect that a message has been redelivered multiple times and is, therefore, “bad” in some way. The application can use this information to take some special action (instead of simply triggering yet another redelivery), such as consuming the message and sending it to a separate queue of “bad” messages for administrator action.
5. MDB configuration properties
A Java EE application that needs to receive messages asynchronously does so using an MDB, which is configured by specifying a number of configuration properties.
- destinationLookup: The JNDI name of an administratively defined Queue or Topic object that represents the queue or topic from which the MDB will receive messages
- connectionFactoryLookup: The JNDI name of an administratively defined ConnectionFactory object that the MDB will use to connect to the JMS provider
- clientId: A client identifier used when the MDB connects to the JMS provider
subscriptionName: A durable subscription name used when subscriptionDurability is set to Durable
Middleware from WSO2
Now Enterprise Integrator from WSO2 supports JMS 2.0 out of the box. This product enables you to use above new features when you send, receive messages from a queue or a topic defined at a third part broker with JMS 2.0 support.