patpitchaya - Fotolia
Where JMS 2.0 misses the mark
JMS 2.0 added significant ease-of-use and messaging features to the popular API. Bill Claybrook looks at what's new in JMS 2.0 and what's missing.
Java Message Service (JMS), part of the Java Platform, Enterprise Edition, is an API that allows applications based on the Java Enterprise Edition to create, send, receive and read messages between computers in a network. JMS is an excellent mechanism for moving information from one point to another, because it guarantees zero message loss and resilience against hardware failure.
Although JMS 1.1 has been highly successful for creating applications with features such as loose coupling, message-based communications, resilience and distributability, it needs improvements in ease-of-use and messaging features, thus the release of JMS 2.0. JMS 2.0 was released in April 2013 as the first update to the JMS 1.1 specification published in March 2002. Although JMS was not updated for more than 10 years, it has a number of implementations and is arguably the most successful API in existence. JMS 2.0, part of the Java EE 7 platform, can be used in Java EE Web applications, or it can be used standalone in a Java SE environment.
A major addition in JMS 2.0 is the introduction of a new API for sending and receiving messages. This improved API, which includes three new interfaces, reduces the amount of code a developer must write and simplifies application development. For applications that run in Java EE servers, the new API allows application servers to handle the creation and management of JMS objects (referred to as resource injection).
The JMS 2.0 API is referred to as the simplified JMS API; the old API is referred to as the classic JMS API. Developers can use either the classic API or the simplified API. The simplified API offers all the features of the classic API, plus the following new interfaces:
- JMSContext: Replaces the separate Connection and Session objects in the classic API with a single object.
- JMSProducer: Replaces the MesssageProduer object in the classic API and allows message delivery options, headers and properties to be configured using method chaining (aka builder pattern).
- JMSConsumer: Replaces the MessageConsumer object in the classic API and is used similarly.
A JMS message consists of message headers, message properties and message body. JMS 2.0 provides a new method -- getBody -- that makes it easier to extract the body of a message. The getBody method is available to users of both the classic and simplified APIs.
JMS 2.0 provides three methods -- receiveBody(class), receiveBody(class, timeout) and receiveBodyNoWait(class) -- that will receive the next message synchronously and return its body. These three methods are available only to applications using the JMS 2.0 simplified API.
In JMS 1.1, the createSession method used to create a javax.jms.Session is confusing. It uses two arguments (Boolean transacted, int acknowledgeMode) to define a single aspect of the session and these two arguments define the same thing. To address this problem, JMS 2.0 adds two new methods with the name createSession that provide the same functionality as the confusing JMS 1.1 createSession method. One of the new methods has a single parameter; the other has no parameter.
New messaging features in JMS 2.0
JMS 2.0 also includes new messaging features. One of the messaging features allows multiple consumers on the same topic subscription. In JMS 1.1, a subscription on a topic is not permitted to have more than one consumer at a time. This meant the work of processing messages on a topic subscription could not be shared among multiple threads, connections or Java Virtual Machines (JVMs), limiting the scalability of the application. This restriction is removed in JMS 2.0 with the introduction of a topic subscription called a shared subscription. All shared consumers have a unique shared subscription name and each message from the subscription is delivered to only one of the consumers on that subscription.
A second new messaging feature in JMS 2.0 is the addition of new send methods to the MessageProducer object that allow messages to be sent asynchronously. In contrast to the traditional synchronous mode that blocks until an acknowledgement is received from the server, asynchronous mode returns immediately without blocking. The new methods return immediately and perform the send operation in a separate thread without blocking the calling thread. This feature is available only for applications running in Java SE or Java EE application client container.
A third new messaging feature allows applications that receive a message to determine how many times the message has been redelivered. This information is obtained from the message property JMSXDeliveryCount. If a message is being redelivered repeatedly, the cause may be a problem in the receiving application. Resources are wasted when a message is redelivered repeatedly.
Delayed message delivery is another messaging feature that allows a JMS client to schedule the future delivery of a message, providing support for deferred processing. The application can set the minimum time in milliseconds that a message should be retained by the messaging system before delivery to a consumer. The provider must not deliver messages before the delivery time has been reached.
The above list of new features included in JMS 2.0 is not exhaustive. Additional features include support for queue/topic shutdown or restart and definition of valid characters in a subscription name, along with the length of the name.
What's not in JMS 2.0?
Not all the features initially considered for JMS 2.0 made their way into the release. Some of these features will appear in JMS 2.1 (or whatever the version is that follows JMS 2.0). Bugs that have been found in JMS 2.0 are expected to be fixed in JMS 2.1.
A list of items that were planned for JMS 2.0 but could not be completed in time can be found here. These include:
- Providing a simpler mechanism to refer to queues and topics in a portable way, without always having to create administered objects in JDNI.
- Defining lifecycle of durable subscriptions used by message-driven beans (MDBs), a feature that would define when messages are kept or discarded; that is, it would define the lifecycle of the subscription.
- Providing Poison message management, allowing applications to manage messages that applications can never successfully process.
- Providing a durable subscription browser. Most JMS providers offer the ability to programmatically browse messages undelivered to a client on a durable subscription, and they do it in various ways. This feature would specify a standard way of doing this for all providers.
- Including individual message acknowledge mode. The implicit acknowledgement of all messages is inconvenient in cases where multiple threads are doing message processing asynchronously. The individual message-acknowledge mode would make it possible for multithreaded applications to achieve whatever behaviors they need.
- Allowing messages to be delivered asynchronously in batches. Some applications could process messages more efficiently if they were delivered in batches.
- Defining how messages from a topic are delivered to clustered application server instances. Java EE has strong support for clusters, but many Java EE specifications do not define what is actually supported. This feature is expected to define the precise, portable and cluster-compliant semantics about the number of times JMS messages get delivered.
- Specifying redelivery behavior when a JMS MDB performs rollback. This update would define what should happen if a JMS MDB receives a message and then rolls back the transaction.
Most developers like the new ease-of-use and messaging features in JMS 2.0. Few, if any, believe JMS 1.1 is better than JMS 2.0. JMS 2.0 enables developers to write code more quickly because less code is required to perform various functions than was the case with JMS 1.1.
Support for JMS 2.0 exists in HornetQ, Open MQ and Fiorano MG. But support for JMS 2.0 is not universal and is missing in important existing applications such as ActiveMQ, a popular open source messaging server. A potential reason for the somewhat lackluster support for JMS 2.0 is that a number of other protocols today get attention besides JMS, such as MQTT and AMQP. These protocols may be more important in the future than traditional JMS, meaning that holding off support for JMS 2.0 is not a showstopper.
A third reason for JMS 2.0's lack of support is that some applications support Java 6 and JMS 2.0 requires the use of some Java 7 features and APIs. There is also an issue about obtaining access to the JMS 2.0 Technology Compatibility Kit for testing compliance.
Comparing JMS and Java Mail API
How to create a JMS bridge for MSMQ