Announcement Announcement Module
No announcement yet.
Consuming unparseable JMS messages Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Consuming unparseable JMS messages


    This scenario is a little complex (sorry).

    Transaction Start
    JMS->Sends XML->SI Listener->Transformer->Router->Processor->Database
    Transaction End

    "Happy Path" is working.

    When the XML can not be transformed, it logs it (using the corporate logger).
    Q: How does one "consume" the message so that it does not get passed to the Router, or rolled back on the JMS Queue? (There is no error channel for a Transformer -- and some Database errors, such as Deadlocks, we do want to roll the message back for a retry)


  • #2
    Consuming unparseable JMS messages - Workaround

    Transformer generates a dummy object for the invalid message, Router routes to a dummy processor. There has GOT to be a better way of handling this scenario.


    • #3
      Maybe you just need to add a <filter>? That can drop the Messages that you are not interested in, and if you prefer to do so quietly (not throwing an Exception), you can. That way the transaction can still commit.

      If I'm not understanding your requirement, please let me know.



      • #4
        Consuming unparseable JMS messages

        Hi Mark.

        Sorry we missed in Dallas -- that was a really nasty storm a couple of weeks ago.

        Unfortunately, until we try to Transform the Message from XML to a Jaxb object, we don't know if it's valid. The requirement here is that we need to remove invalid/non-conforming XML messages from the JMS Q so that they don't block the queue (its a FIFO Queue) continually retrying a message that can not be consumed, and the transformer is the first thing in line that has the ability to detect this.



        • #5
          It sounds like you might want to specify an "error-channel" on the inbound adapter. You can view that as playing the role of a catch block for the message flow that initiates at that adapter. If you "handle" the validation errors there (e.g. record the data somewhere for auditing purposes), then the JMS transaction will commit so that no redelivery occurs.


          • #6
            Hi Mark.

            Thanks for the reply.

            JMS Adapter -> Transformer -> JDBC Processor (End Consumer)

            Transformer - errors here need to be consumed.
            JDBC Processor - unhandled errors here need to be put back on the Queue for a retry.

            How do I get both?

            [Edited for clarity]


            • #7
              If you add the 'error-channel' on the JMS adapter, it will be the starting point for an error-handling flow. You can think of that as the messaging equivalent to a catch block. As with a catch block, if you rethrow any Exception from within that flow, it will propagate, thereby triggering a rollback. If you "handle" the Exception (e.g. write to a log and suppress propagation), the TX will commit instead.

              Is that clearer?


              • #8
                Yes, much, thanks!


                • #9
                  Question: How do you configure ErrorMessageExceptionTypeRouter? I've not found any examples anywhere in the documentation?
                  Answer: (Found this while looking for examples in Google)



                  • #10
                    That link seems to be SI 1.x, NOT 2.x, which is what I am working with. What I came up with was;
                    <router input-channel="errorChannel" default-output-channel="defaultErrorChannel">
                    channel="databaseErrorChannel" />
                    <beans:bean id="errorRouter"
                    class="org.springframework.integration.router.Erro rMessageExceptionTypeRouter">

                    <channel id="defaultErrorChannel" />
                    <channel id="databaseErrorChannel" />

                    And for the ExceptionHandlers:
                    public class ExceptionHandler
                    @ServiceActivator(inputChannel = "defaultErrorChannel")
                    public void handleMessage(final Message<Exception> message)
                    final Exception exception = message.getPayload();
                    //do stuff

                    public class DatabaseExceptionHandler extends ExceptionHandler
                    @ServiceActivator(inputChannel = "databaseErrorChannel")
                    public void handleMessage(final Message<Exception> message){
                    //DO Stuff
                    //Otherwise, default handling

                    Snippets from the attached log output:
                    2011-03-08 11:53:11,466 [main] INFO o.s.i.e.EventDrivenConsumer:AbstractEndpoint - started databaseExceptionHandler.handleMessage.serviceActi vator
                    2011-03-08 11:53:11,466 [main] INFO o.s.i.e.EventDrivenConsumer:AbstractEndpoint - started databaseExceptionHandler.handleMessage.serviceActi vator#2
                    2011-03-08 11:53:11,466 [main] INFO o.s.i.e.EventDrivenConsumer:AbstractEndpoint - started exceptionHandler.handleMessage.serviceActivator

                    Followed by a large number of:
                    2011-03-08 11:54:25,049 [org.springframework.jms.listener.DefaultMessageLis tenerContainer#0-1] WARN

                    o.s.j.l.DefaultMessageListenerContainer:AbstractMe ssageListenerContainer - Execution of JMS message listener failed, and no ErrorHandler has been set.
                    java.lang.IllegalArgumentException: payload must not be null

                    Q1) what's up that the DatabaseExceptionHandler seems to get setup twice?
                    Q2) Why does the listener think that no Exception Handlers have been configured?
                    NOTE: In some cases, the exception handler needs to throw an exception back to the Adapter for a Rollback, as there are cases when a message should be retried.

                    Last edited by Gorky; Mar 8th, 2011, 12:32 PM. Reason: Forgot the log.


                    • #11
                      Any ideas why not all Errors are being redirected to the ErrorChannel? How do I configure an "ErrorListener"?



                      • #12
                        Could you elaborate on your use case a bit? Provide some context?
                        Generally error-channel is used by default *only* in the async flows since Message send happens on the different thread the Message processing, thus leaving no other way but the default error-channel to let the Message sender know that something wrong happened.
                        For all other components there are means to specify the error-channel and that is why I am asking about your particular use case.


                        • #13
                          - Message has no payload (IBM MQ Header: content = nil) JMS Listener throws an Exception that does NOT get passed to the errorchannel, but instead rolls the transaction back, leaving message on the Queue (for immediate and infinite retry).
                          - Message has empty payload JMS Listener or SI Base Transformer throws an Exception that DOES get passed to the error channel.
                          - Message can not be processed Processor throws an Exception, which then gets put on the Error Channel. Listener on Error Channel determines if an intermittent Database Error (Transaction Time Out, Table Contention, etc.), in which case, throws an Exception to roll the Transaction back and leave message on Queue. If NOT an intermittent Database Error (ex. Invalid data), then consumes and logs the message, removing from the JMS Q.

                          Originally, it was suggested I use an Error Channel, and listeners on the Channel for this. Is there a better pattern that should be used?

                          Last edited by Gorky; Mar 14th, 2011, 05:27 PM. Reason: Added note about retry