Exploring JMS specifications and features

With JMS-1.x Specification:

Developers had to keep the following things in mind

Establish a connection

Initiate a session

Close the connection & session

Handle exceptions

Reading messages by typecasting.

With the new JMS-2 specification:

The JMSContext interface simplifies the process for developers by providing a way to create connections and manage sessions.

  • JMSContext can be used to create JMSProducer and JMSConsumer objects. All of these interfaces implement the AutoCloseable interface, so they will be closed by the JVM when no longer needed.

  • JMSConsumer and JMSProducer give developers more control over message bodies, headers, and properties. Annotations can be used to look up JMS-administered objects in the JNDI namespace.

JMS message consists of the following components:

Messages are used to communicate any events, data, etc. APIs are designed to send and receive messages.

  1. Message headers:

    1. Metadata - says something about the message provider

    2. headers : Destination: Queue to which message to be delivered. JMSDelivery Mode: Persistent or non-persistent

    3. JMSMessageID: Unique ID for each message

    4. JMSTimestamp: message received by JMS provider

    5. JMSExpiration: set a time after which the message will be expired if not delivered

    6. JMSRedelivered: If a prior attempt to deliver failed, this will be set to convey it is re-tried JMSPriority [0-4 normal] 5-9 high priority

    7. Developer headers:

      • JMSReplyTo: The application will set this so that the provider should know which destination to reply to. Used in the request-reply scenario.

      • JMSCOrrelationID: consumer takes JMSMessageID will read from the request and add it to response/reply in this field.

      • JMSType: What type of JMS message is being sent?

  2. Message properties

  3. Message Body

Message Types

JMS is a specification used to support communication between different software components. It allows for different types of messages to be exchanged between components, based on the use case and need.

Care should be taken to read the values in the same hierarchy to which they were added. This will ensure that you don't miss any important data.

  • TextMessage

  • ByteMessage

  • ObjectMessage

  • StreamMessage

  • MapMessage

Message acknowledgment for guaranteed messaging

JMS guarantees message delivery by providing a protocol between the JMS server and the producer/consumer. Once a message is delivered by a producer to the server, the server will acknowledge receipt of the message.

Similarly, once the message is consumed by the consumer, the consumer will need to acknowledge receipt.

There are three modes of acknowledgment:

  • Auto_acknowledged

  • Client_acknowledged

  • Dups_ok_acknowledged.

In auto_acknowledgement mode, Acknowledgment is automatically handled by JMS Provider.

  • The producer creates the message using either the send() or publish() method.

  • This blocks the send() or publish() call until an acknowledgment is received from the JMS server.

  • The acknowledgment only means that the message is with the server and that the consumer will be able to retrieve it whenever they are ready to do so.

  • The consumer is then ready and active and consumes the message, sending an acknowledgment back to the server.

  • JMS providers are responsible for delivering messages.

    • Their responsibilities include

      • Persisting the message if it is configured to do so.

      • Ensuring that the message is delivered if the subscriber is inactive for a while

      • And delivering the message only once.

In client_acknowledge mode:

  • The producer creates the message using send() or publish().

  • The consumer is ready/active, and the message will be consumed. The consumer will then send an acknowledgment back to the server explicitly using message.acknowledge().

  • Until the message is acknowledged by the consumer, it will continue to stay in the queue.

  • This way, the JMS provider doesn't have to worry about one less thing.

In Dups_ok_acknowledge mode:

  • Same as auto_acknowledged

  • Here, the consumer is responsible for receiving the message only once. In case the JMS-Provider sends it more than once, the consumer will be responsible for only receiving it once. [consumer needs to use JMS-MessageID for this]

JMS Transactions

Transactions can be assumed to be similar to database transactions. It can either be commit() or rollback(). It is a basic grouping of messages and committing in one go. When a transaction is enabled JMS system will tend to behave like a synchronous process.

JMS transactions involve three entities Producer, Consumer and JMS-Server

One transaction can be considered from JMS-Producer to JMS-Server, and another transaction can be considered from JMS-Consumer to JMS-Server.

JMS-Server will know it's a transaction based on the context that will be configured by the producer when the messages are sent. If the jms context is configured with "SESSION_TRANSACTED"

In the above diagram, one transaction consists of three messages. This means that the producer will still send three messages, but not at the same time. JMS-Server will keep the messages received in the "SESSION_TRANSACTED" jms context in a separate cache and not in the actual queue until and unless a commit() is been initiated by the producer.

If the producer encounters an exception or error before committing, they can choose to roll back. This will remove all messages that were previously sent and stored in the JMS server cache.

JMS Server will keep sending messages to the consumer until it receives a commit(). Once a commit is received from the consumer, the messages will be removed from the queue.

If for some reason the messages are corrupted or lost at the consumer end, the consumer can initiate a rollback before committing so all previous messages will be discarded and resent.

In case a rollback is sent from the consumer, we can see in the below pictorial representation messages will not be removed from the queue as the commit() was not called.

when a commit is called, messages will be removed from the queue.

Did you find this article valuable?

Support Ashwin Padiyar by becoming a sponsor. Any amount is appreciated!