Announcement Announcement Module
Collapse
No announcement yet.
xpath-router + malformed xml Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • xpath-router + malformed xml

    Hi all,

    I'm using xpath-router for routing my payload to target channels:

    Code:
        <si-xml:xpath-router id="messageTypeRouter" input-channel="jmsListenerChannel" resolution-required="false" default-output-channel="unmatchedMessageTypeChannel">
            <si-xml:xpath-expression expression="/messageNs:message/messageNs:header/messageNs:applicationMessageType/text()" namespace-map="messageNamespaceMap"/>
            <si-xml:mapping value="bp_list"     channel="bpListMessageTypeChannel"/>
            <si-xml:mapping value="person_list" channel="personListMessageTypeChannel"/>
        </si-xml:xpath-router>
    It works as expected.
    If my payload contains messages with "bp_list" / "person_list" xpath-expressions, payload is routed to the given channel.
    In any other cases I defined the default-output-channel="unmatchedMessageTypeChannel" where payload is written to file for manual handling.
    But if for any reason, the payload is a malformed xml, I got correctly an error and I lost it ... I would like to send that payload to a given error channel, let's say "malformedMessageTypeChannel", where for example I can store it on the file system.

    How could I address that ?
    Any help ss greatly appreciated!!!

    Thanks and regards
    nuvola

  • #2
    What is the entry point to the messaging system? Typically it's an inbound adapter, or gateway.

    Add and error-channel to that element.

    Comment


    • #3
      In my scenario the entry point is a message-driven-channel-adapter that routes the message to the xpath-router:

      Code:
          <!-- A default JMS message listener -->
          <jms:message-driven-channel-adapter id="jmsMessageChannelAdapter"
                                              connection-factory="connectionFactory"
                                              destination="queue"
                                              channel="jmsListenerChannel"/>
      
          <!-- Message type routing -->
          <si-xml:xpath-router id="messageTypeRouter" input-channel="jmsListenerChannel" resolution-required="false"
                               default-output-channel="unmatchedMessageTypeChannel" error-channel="errorChannel">
              <si-xml:xpath-expression
                      expression="/messageNs:message/messageNs:header/messageNs:applicationMessageType/text()"
                      namespace-map="messageNamespaceMap"/>
              <si-xml:mapping value="bp_list" channel="bpListMessageTypeChannel"/>
              <si-xml:mapping value="person_list" channel="personListMessageTypeChannel"/>
          </si-xml:xpath-router>
      So in the xpath-router I added an error channel as shown above.

      But I got below error:

      Code:
      Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 79 in XML document from class path resource [META-INF/ch/integration/signbookListener-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-complex-type.3.2.2: Attribute 'error-channel' is not allowed to appear in element 'si-xml:xpath-router'.
      May I ask you to help me in defining properly the error channel ?

      Thanks and regards
      nuvola

      Comment


      • #4
        You can move that 'error-channel' attribute to the jms:message-driven-channel-adapter element (since it is the entry point to the flow).

        Comment


        • #5
          Thanks!

          It works as you suggested :-)

          Comment


          • #6
            An additional question.

            Currently I moved the 'error-channel' attribute to the jms:message-driven-channel-adapter element:

            Code:
                <stream:stderr-channel-adapter channel="errorChannel" append-newline="true"/>
            
                <jms:message-driven-channel-adapter id="jmsMessageChannelAdapter"
                                                    connection-factory="connectionFactory"
                                                    destination="queue"
                                                    channel="jmsListenerChannel"
                                                    error-channel="errorChannel"/>
            so the error is traced.

            If instead I liked to store the offending payload into a file how could I do ?

            Thanks and regards
            nuvola

            Comment


            • #7
              You can add any messaging flow you want downstream from that error-channel. The Exception that is the payload of the Message sent to the error-channel will be of type MessagingException, and that has a "failedMessage" property. So, you can use a SpEL-based transformer followed by an outbound file adapter.

              HTH,
              Mark

              Comment


              • #8
                Hi Mark,

                thanks for the suggestion, I will try.

                May I ask you to provide some snippet or a high level example ?

                Thanks
                nuvola

                Comment


                • #9
                  See the <file:outbound-channel-adapter/> in the sample here... https://github.com/SpringSource/spri...ter/basic/file

                  Just insert a <transformer/> on the error flow from the gateway...

                  Code:
                  <transformer input-channel="gwErrorChannel" output-channel="toFileOutboundAdapter
                      expression="payload.failedMessage" />

                  Comment


                  • #10
                    Thanks Gary.

                    I'm trying but something is wrong in my configuration ...
                    I see the org.xml.sax.SAXParseException from log but then it seems my errorToFileChannel is not triggered ...

                    Code:
                        <!-- A default JMS message listener -->
                        <jms:message-driven-channel-adapter id="jmsMessageChannelAdapter"
                                                            connection-factory="connectionFactory"
                                                            destination="queue"
                                                            channel="jmsListenerChannel"
                                                            error-channel="errorChannel"/>
                    
                        <stream:stderr-channel-adapter channel="errorChannel" append-newline="true"/>
                    
                        <int:transformer input-channel="errorChannel" output-channel="errorToFileChannel" expression="payload.failedMessage"/>
                        <int:channel id="errorToFileChannel"/>
                        <file:outbound-gateway directory="file:${unmatchedMessageType.directory}"
                                               request-channel="errorChannel" reply-channel="error-file"
                                               filename-generator-expression="'error.' + headers.MessageId.replace(':','_') + '_' + new java.text.SimpleDateFormat('ddMMyyyy_HHmmss').format(new java.util.Date()) + '.xml'"/>
                        <int:channel id="error-file"/>
                        <int:logging-channel-adapter channel="error-file"
                                                     expression="'#### [Channel=errorChannel][' + headers.MessageId + '][Headers=' + headers + '][Payload=' + payload + ']'"
                                                     level="ERROR"/>

                    Comment


                    • #11
                      You have two subscribers on errorChannel (the stderr adapter and your transformer); this means they will alternate (round robin dispatching).

                      If you want to log as well as write to the file, define the error channel as publish/subscribe; that way, both subscribers get the messsage...

                      Code:
                      <int:publish-subscribe-channel id="errorChannel" />
                      Otherwise, simply remove (or comment out) the stderr channel adapter.

                      Comment


                      • #12
                        Sorry again ...

                        I tried to define the error channel as publish/subscribe simply adding your suggestion before my def

                        Code:
                            <int:publish-subscribe-channel id="errorChannel" />
                            <stream:stderr-channel-adapter channel="errorChannel" append-newline="true"/>
                            <int:transformer input-channel="errorChannel" output-channel="errorToFileChannel"
                               expression="payload.failedMessage"/>
                            <int:channel id="errorToFileChannel"/>
                            <file:outbound-gateway directory="file:${unmatchedMessageType.directory}"
                                                   request-channel="errorChannel" reply-channel="error-file"
                                                   filename-generator-expression.../>
                            <int:channel id="error-file"/>
                            <int:logging-channel-adapter channel="error-file"
                                                         expression="..."
                                                         level="ERROR"/>
                        but the behaviour is still the same. I mean, I see the exception from log but I don't see the file channel is triggered ...

                        Comment


                        • #13
                          Please run with debug log and take a look at the message flow. If you can't figure it out from the log, please attach as a zip.

                          Comment


                          • #14
                            I run with debug log and I got below additional info:

                            Code:
                            04.Jun.2012 18:08:21,895 - (JMS LISTENER SERVICE) (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) [WARN  ]-[AbstractMessageListenerContainer   (695 )] - Execution of JMS message listener failed, and no ErrorHandler has been set.
                            org.springframework.integration.MessageDeliveryException: Dispatcher has no subscribers for channel errorToFileChannel.
                            So the xpath-router raises correctly an error and the message-driven-channel-adapter caught it.
                            I see also in the log the output from stderr-channel-adapter.
                            No output instead from errorToFileChannel.

                            I'm reviewing those errorChannel/transformer/errorToFileChannel/etc in order to figure out where I'm wrong ...

                            Comment


                            • #15
                              Right; if you look at the configuration carefully, you'll see the output channel of the transformer is errorToFileChannel, but you didn't change the file gateway to set this as its request-channel - it is still subscribed to the errorChannel.

                              All components (endpoints) are connected together with channels - if you are using STS, click on the 'Integration Graph' tab you'll see a visual representation of your flow and errors like this will become very obvious.
                              Last edited by Gary Russell; Jun 5th, 2012, 06:53 AM.

                              Comment

                              Working...
                              X