0
votes

I'm trying to include the inputMessage payload in errors, but it seems it's never being passed on and enriching doesn't seem to work either.

I have a directory polling service:

<file:inbound-channel-adapter
        id="incomingFiles"
        auto-startup="true"
        auto-create-directory="false"
        channel="myFiles"
        filename-pattern="${directory.local.pattern}"
        directory="file:${directory.local}">
    <int:poller id="poller" fixed-delay="${directory.local.poll}"/>
</file:inbound-channel-adapter>

These files are then being uploaded via SFTP:

<sftp:outbound-channel-adapter
        id="sftpOutboundAdapter"
        channel="myFiles"
        charset="UTF-8"
        remote-directory="${directory.remote}"
        session-factory="sftpSessionFactory">
    <sftp:request-handler-advice-chain>
        <bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
            <property name="onSuccessExpression" value="payload.delete()"/>
            <property name="successChannel" ref="successChannel"/>
            <property name="onFailureExpression" value="payload.renameTo(payload.absolutePath + '.error')"/>
            <property name="failureChannel" ref="failChannel" />
        </bean>
    </sftp:request-handler-advice-chain>
</sftp:outbound-channel-adapter>

On the success channel, I log it and send and send it via the successChannel where another service picks it up and sends an email, this works 100%:

    <!-- Log Channel -->
    <int:logging-channel-adapter id="logChannel" level="INFO"/>

    <!-- Success Endpoint -->
    <int:channel id="successChannel">
        <int:interceptors>
            <int:wire-tap channel="successLogChannel"/>
        </int:interceptors>
    </int:channel>

    <!-- Success Logging -->
    <int:channel id="successLogChannel"/>
    <int:transformer
            input-channel="successLogChannel"
            output-channel="logChannel"
            expression="'Successfully transferred ' + inputMessage.payload.absolutePath"/>

    <!-- Send success email -->
    <int:chain input-channel="successChannel">
        <int:header-enricher>
            <int:header name="to" value="${success.email.to}"/>
            <int:header name="from" value="${success.email.from}" />
            <int:header name="subject" value="${success.email.subject}"/>
            <int:header name="filename" expression="inputMessage.payload.absolutePath"/>
        </int:header-enricher>
        <int:service-activator ref="Email" method="sendSuccessMail"/>
    </int:chain>

org.springframework.integration.handler.LoggingHandler - Successfully transferred /tmp/test-file.dat

Now when I try the exact same thing for errors, the expression inputMessage.payload.filename fails to evaluate.

    <!-- Fail Endpoint -->
    <int:channel id="failChannel">
        <int:interceptors>
            <int:wire-tap channel="failLogChannel"/>
        </int:interceptors>
    </int:channel>

    <!-- Fail Logging -->
    <int:channel id="failLogChannel"/>
    <int:transformer
            input-channel="failLogChannel"
            output-channel="logChannel"
            expression="'Failed to transfer ' + inputMessage.payload.absolutePath"/>

    <!-- Send fail email -->
    <int:chain input-channel="failChannel">
        <int:header-enricher>
            <int:header name="to" value="${fail.email.to}"/>
            <int:header name="from" value="${fail.email.from}" />
            <int:header name="subject" value="${fail.email.subject}"/>
            <int:header name="filename" expression="inputMessage.payload.absolutePath"/>
        </int:header-enricher>
        <int:service-activator ref="Email" method="sendFailMail"/>
    </int:chain>

ERROR org.springframework.integration.handler.LoggingHandler - org.springframework.integration.transformer.MessageTransformationException: org.springframework.integration.MessageHandlingException: Expression evaluation failed: 'Failed to transfer ' + inputMessage.payload.absolutePath

I've tried adding a header enricher, but it seems that payload never even gets out of the SFTP outbound channel when there's an error:

    <!-- Fail Endpoint -->
    <int:channel id="failChannel"/>
    <int:chain input-channel="failChannel" output-channel="failChannelEnriched">
        <int:header-enricher>
            <int:header name="to" value="${fail.email.to}"/>
            <int:header name="from" value="${fail.email.from}"/>
            <int:header name="subject" value="${fail.email.subject}"/>
            <int:header name="filename" expression="inputMessage.payload.absolutePath"/>
        </int:header-enricher>
    </int:chain>


    <int:channel id="failChannelEnriched">
        <int:interceptors>
            <int:wire-tap channel="failLogChannel"/>
        </int:interceptors>
    </int:channel>

    <!-- Fail Logging -->
    <int:channel id="failLogChannel"/>
    <int:transformer
            input-channel="failLogChannel"
            output-channel="logChannel"
            expression="'Failed to transfer ' + headers['filename']"/>

    <!-- Send fail email -->
    <int:chain input-channel="failChannelEnriched">
        <int:service-activator ref="Email" method="sendFailMail"/>
    </int:chain>

ERROR org.springframework.integration.handler.LoggingHandler - org.springframework.integration.transformer.MessageTransformationException: org.springframework.integration.MessagingException: failed to transform message headers

...

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'inputMessage' cannot be found on object of type 'org.springframework.integration.message.ErrorMessage'

at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:246)

Looking at the spring docs, I can see that org.springframework.integration.message.ErrorMessage does accept headers, but somehow it's just not being set.

Any advice ?

1

1 Answers

1
votes

For success, a special AdviceMessage is sent to the channel; this has the inputMessage property (the payload is the result of the expression evaluation).

For the error case, a normal ErrorMessage is send to the channel; its payload is a MessagingException with the normal properties: the cause (the exception that occurred), and failedMessage.

The actual exception is MessageHandlingExpressionEvaluatingAdviceException which has an additional property evaluationResult containing the result of the expression evaluation.

So, you need a different expression for the failure case payload.failedMessage.payload.absolutePath.