0

I've a service-activator bean which has a method that gets a List of SI messages as input.

The method iterates through the list, gets each SI message from it, gets the payload from SI message and then sends the payload to a MQ (I'm not using any outbound channel adapters to send message to MQ; I'm just using plain vanilla JMS APIs).

I've configured a <request-handler-advice-chain> onto this service-activator with class as RequestHandlerRetryAdvice and mapped it to a retryTemplate that is configured for SimpleRetry policy.

In the service-activator method I've put in a logic to add a header (say MESSAGE_SENT_STATUS) with a value "SUCCESS" to each SI message if the payload is sent successfully to MQ.

EDIT1 [[ This is how my logic looks like:

 public void doSendMessage(List<Message<?> inputMsgs) {
        for(Message<?> msg : inputMsgs) {
          if(msg.getHeaders().get("MESSAGE_SENT_STATUS") != null)
              continue;
          Object payload = msg.getPayload();

          //some code logic to send 'payload' to a MQ goes here

          msg.getHeaders().put("MESSAGE_SENT_STATUS","SUCCESS");
          return;
        }
    }
//I've just typed in the code logic; so pls ignore any typos for syntax errors.

]]

I would like to know if this header will be retained on the message in case there is an exception and the service-activator method is retried ?

So, as an example, say my List contains 3 SI messages.

The first and second SI message were deposited successfully on MQ (which in-turn means that those messages were enriched with a header MESSAGE_SENT_STATUS with value as "SUCCESS") but there was an exception while trying to deposit the 3rd SI message.

IF I add a code in the iteration of List to check for the header MESSAGE_SENT_STATUS and if its value is "SUCCESS" then skip that iteration (basically by placing a continue) THEN will it ensure that only the 3rd message will be retired on MQ ?

OR this is a case of Stateless retry and all the messages will be pushed to MQ (since MESSAGE_SENT_STATUS is not present on them) ?

I was also referring the manual to see if I can leverage ExpressionEvaluatingRequestHandlerAdvice for my above use case but couldn't get a hold of it. Is it possible to leverage this advice for my use case ? If yes, can you pls suggest how ?

Appreciate a response !

Many thanks and Best Regards

lbvirgo
  • 354
  • 1
  • 5
  • 22

1 Answers1

0

logic to add a header

What does that logic look like?

Messages (and the collection of headers) are immutable, so you can't "add a header" to an existing message, only create a new message from an existing one.

The retry advice (and any advice) only sees the inbound message.

Since your message payload is a List of Messages, while you can't change the main message payload itself (i.e. change it to a new List), you can, of course change the contents of the List in the payload.

So, yes, if you create a new message from one of the list elements, and replace that list element, the retry will see the changed state, not the original state.

If you add a mutable header upstream (to each list element), say an AtomicBoolean, you can set that boolean without having to create a new message from the original one.

The bottom line is while the message itself is immutable, message contents can be mutable, and that is in the domain of the application.

Generally, you need to take care in this area, particularly if the same message is sent to multiple destinations, such as with a pub/sub channel or a recipient list router, but you can mutate the contents as you wish.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • No. As I said, you can't mutate the headers object, only any mutable header values; you have to use `MessageBuilder.fromMessage()` to create a new message builder, set the new header and build() a new message. Then replace the old message in its place in the list. If you add the header earlier with, say, an `AtomicBoolean` you can change the header value. – Gary Russell Oct 21 '15 at 00:19
  • How do I "replace" my message ? How will my List know which message to replace ? Also, if I ensure that each message in my incoming "List inputMsgs" has a header with key "MESSAGE_SENT_STATUS" and during the iteration I modify the value of this header key, will that work ? OR since Strings are immutable, a String header will not work ? – lbvirgo Oct 21 '15 at 01:43
  • You can manipulate the list with `remove(int)` and `add(int, ...)` but a prepopulated mutable header such as `AtomicBoolean` would be better. Strings are immutable. If you need a string value, use `AtomicReference`. – Gary Russell Oct 21 '15 at 01:53
  • Thanks Gary ! That helps. – lbvirgo Oct 21 '15 at 02:02
  • Sorry Gary but a quick confirmation --> So my "header key" can still be a String object (say "MESSAGE_SENT_STATUS") but the "header value" should be a AtomicReference [say, new AtomicReference("NOT_SENT")] in case I chose to have a string "header value" ? And this "header value" can be modified using compareAndSet() method of AtomicReference ? – lbvirgo Oct 21 '15 at 02:22
  • Pls ignore my above comment; just noted in api that the put method only accepts a String as the "key" ! So your suggestion for using Atomic* objects was basically for "header values". Thanks ! – lbvirgo Oct 21 '15 at 02:30