Message Correlation

In the previous code example, the borrower sent a loan request on a request queue and waited for a reply from the lender on a response queue. Many borrowers may be making requests at the same time, meaning that the lender application is sending many messages to the response queue. Since the response queue may contain many messages, how can you be sure that the response you received from the lender was meant for you and not another borrower?

In general, whenever using the request/reply model, you must make sure the response you are receiving is associated with the original message you sent. Message correlation is the technique used to ensure that you receive the right message. The most popular method for correlating messages is leveraging the JMSCorrelationID message header property in conjunction with the JMSMessageID header property. The JMSCorrelationID property contains a unique String value that is known by both the sender and receiver. The JMSMessageID is typically used, since it is unique and is available to the sender and receiver.

When the message consumer (e.g., QLender) is ready to send the reply message, it sets the JMSCorrelationID message property to the message ID from the original message:

public class QLender implements MessageListener {

   ...
   public void onMessage(Message message) {
      try {
         ...         
         // Send the results back to the borrower
         TextMessage tmsg = qSession.createTextMessage();
         tmsg.setText(accepted ? "Accepted!" : "Declined");
         tmsg.setJMSCorrelationID(message.getJMSMessageID());
         
         // Create the sender and send the message
         QueueSender qSender = 
            qSession.createSender((Queue)message.getJMSReplyTo());
         qSender.send(tmsg);

         System.out.println("\nWaiting for loan requests...");
         ...
      }
   }
   ...            

The original message producer (e.g., QBorrower) expecting the response about whether the loan was approved creates a message selector based on the JMSCorrelationID message property:

public class QBorrower {

   ...
   private void sendLoanRequest(double salary, double loanAmt) {
      try {
         ...

         // Wait to see if the loan request was accepted or declined
         String filter = 
            "JMSCorrelationID = '" + msg.getJMSMessageID() + "'";
         QueueReceiver qReceiver = qSession.createReceiver(responseQ, filter);
         TextMessage tmsg = (TextMessage)qReceiver.receive(30000);
         ...
      }
   }
   ...            

Although the JMSMessageID is typically used to identify the unique message, it certainly is not a requirement. You can use anything that would correlate the request and reply messages. For example, as an alternative you could use the Java UUID class to generate a unique ID. In the following code example, the QBorrower class generates a unique ID and sets an application message property called “UUID” to the generated value:

public class QBorrower {

   ...
   private void sendLoanRequest(double salary, double loanAmt) {
      try {
         // Create JMS message
         MapMessage msg = qSession.createMapMessage();
         msg.setDouble("Salary", salary);
         msg.setDouble("LoanAmount", loanAmt);
         msg.setJMSReplyTo(responseQ);
         UUID uuid = UUID.randomUUID();
         String uniqueId = uuid.toString();
         msg.setStringProperty("UUID", uniqueId);

         // Create the sender and send the message
         QueueSender qSender = qSession.createSender(requestQ);
         qSender.send(msg);
        
         // Wait to see if the loan request was accepted or declined
         String filter = 
            "JMSCorrelationID = '" + uniqueId + "'";
         QueueReceiver qReceiver = qSession.createReceiver(responseQ, filter);
         TextMessage tmsg = (TextMessage)qReceiver.receive(30000);
         ...
      }
   }
   ...            

The QLender application must now get the UUID property from the original message and set the JMSCorrelationID message property to this value:

public class QLender implements MessageListener {

   ...
   public void onMessage(Message message) {
      try {
         ...         
         // Send the results back to the borrower
         TextMessage tmsg = qSession.createTextMessage();
         tmsg.setText(accepted ? "Accepted!" : "Declined");
         tmsg.setJMSCorrelationID(message.getStringProperty("UUID"));
         
         // Create the sender and send the message
         QueueSender qSender = 
            qSession.createSender((Queue)message.getJMSReplyTo());
         qSender.send(tmsg);

         System.out.println("\nWaiting for loan requests...");
         ...
      }
   }
   ...            

Although it is commonly used, you are not required to use the JMSCorrelationID message header property to correlate messages. As a matter of fact, you could set the correlation property to any application property in the message. While this is certainly possible, you should leverage the header properties if they exist for full compatibility with messaging servers, third-party brokers, and third-party message bridges.

Get Java Message Service, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.