Results 1 to 5 of 5

Thread: Handling Exceptions in Interceptors

  1. #1
    Join Date
    Jan 2008
    Location
    San Diego
    Posts
    780

    Default Handling Exceptions in Interceptors

    I have the following configuration:

    Code:
     <!-- Base Gateway Message Channel -->
      <integration:channel id="gatewayMessageChannel">
        <integration:interceptors>
          <ref bean="gatewayTransformingInterceptor"/>
          <ref bean="jsonInterceptor"/>
        </integration:interceptors>
      </integration:channel>
    The first interceptor is basically a transformer. It takes an external message format, e.g.:

    Code:
    <message>
      <header>
        ..header fields
      </header>
      <payload>
       ...payload data
      </payload>
    </message>
    and extracts the headers and payload and converts the incoming message to a SI Message format.

    The second interceptor parses the payload as a JSON message and extracts a 'type' attribute in the message payload that is used in routing.

    With both of these interceptors, if the message format is incorrect (bad xml, missing fields, bad json, etc) then the message is not recoverable and there is no point in having the jms provider redeliver it. I just need to log the event and drop it on the floor.

    Initially I had the interceptors return NULL if they could not process the message. This, however, was causing rollback. The message channel docs say:

    http://static.springsource.org/sprin...n.core.Message)

    Send a Message to this channel. May throw a RuntimeException for non-recoverable errors.
    So I changed the code to throw a RuntimeException instead of returning null in my interceptors. However, that exception is still bubbling all the way up to the message listener container and the message is still being rolled back.

    The rest of my message processing takes place in a chain:

    Code:
    <integration:chain input-channel="gatewayMessageChannel">
         <!-- Throw away duplicate messages -->
         <integration:filter ref="duplicateMessageSelector"/>
         <!-- Route messages to appropriate channels for handling -->
         <integration:router ref="jsonMessageTypeRouter" default-output-channel="unroutableMessageChannel"/>
       </integration:chain>
    Here I check for incoming duplicate messages (in the db) and then route them to the appropriate channel for processing.

    Is there a better way to handle these error conditions? Can I just make them Transformers that return NULL in the case that they can't process the message (will this trigger a redelivery as well)?

    I certainly want exceptions (such as temporary db access) that are recoverable to trigger message delivery but I don't want to waste my time when repeated attempts to reprocess the message will never succeed.

    Thanks!

  2. #2
    Join Date
    Oct 2005
    Location
    Boston, MA
    Posts
    2,840

    Default

    Have you tried moving those Transformers into the chain rather than in the channel?

    If the Transformers are themselves configured as "handlers/endpoints" rather than in channel interceptors, then they can return null, and it should be considered "done" (and hence ignored) as far as the Message flow is concerned.

  3. #3
    Join Date
    Jan 2008
    Location
    San Diego
    Posts
    780

    Default

    Quote Originally Posted by Mark Fisher View Post
    Have you tried moving those Transformers into the chain rather than in the channel?

    If the Transformers are themselves configured as "handlers/endpoints" rather than in channel interceptors, then they can return null, and it should be considered "done" (and hence ignored) as far as the Message flow is concerned.
    I haven't tried that yet. I wanted confirmation that returning null in the transform method would in fact just terminate the chain (like the filter returning false) and not cause further problems.

    I'll refactor things and see how it works...

    Thanks Mark.

  4. #4
    Join Date
    Oct 2005
    Location
    Boston, MA
    Posts
    2,840

    Default

    Please do try that. The difference is that a ChannelInterceptor returning null in the preSend() method produces a MessageDeliveryException in the AbstractMessagingGateway (where it delegates to MessageChannelTemplate and considers a 'false' return from the send method to be a failure).

  5. #5
    Join Date
    Jan 2008
    Location
    San Diego
    Posts
    780

    Default

    Quote Originally Posted by Mark Fisher View Post
    Please do try that. The difference is that a ChannelInterceptor returning null in the preSend() method produces a MessageDeliveryException in the AbstractMessagingGateway (where it delegates to MessageChannelTemplate and considers a 'false' return from the send method to be a failure).
    Works like a champ. Thanks Mark!

    Code:
    <!-- Gateway message handler chain -->
      <integration:chain input-channel="gatewayMessageChannel">
         <!-- Reformat message -->
         <integration:transformer ref="gatewayMessageTransformer"/>
         <!-- Extract JSON type header -->
         <integration:transformer ref="jsonMessageTypeExtractingTransformer"/>
         <!-- Throw away duplicate messages -->
         <integration:filter ref="duplicateMessageSelector"/>
         <!-- Route messages to appropriate channels for handling -->
         <integration:router ref="jsonMessageTypeRouter" default-output-channel="unroutableMessageChannel"/>
       </integration:chain>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •