From 2340e6f442c6cb8b50fe6a5788955aea85c6161f Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Fri, 21 Sep 2012 17:55:50 +0100 Subject: [PATCH] INT-2763 Send AdviceMessage from Advice The ExpressionEvaluatingMessageHandlerAdvice now sends an AdviceMessage which has a payload of the original message, and a property 'inputMessage' referencing the message that was sent to the advised handler. INT-2763 Expression Advice Reference Doc Update Update to reflect the new behavior. --- .../advice/AbstractRequestHandlerAdvice.java | 4 +- ...ressionEvaluatingRequestHandlerAdvice.java | 170 +++++++++++------- .../integration/message/AdviceMessage.java | 53 ++++++ .../advice/AdvisedMessageHandlerTests.java | 73 ++++---- src/reference/docbook/handler-advice.xml | 46 ++--- 5 files changed, 214 insertions(+), 132 deletions(-) create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/message/AdviceMessage.java diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java index a471ec24a6..8e5bbeafee 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java @@ -22,6 +22,7 @@ import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.integration.Message; +import org.springframework.integration.context.IntegrationObjectSupport; import org.springframework.integration.core.MessageHandler; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; @@ -35,7 +36,8 @@ import org.springframework.integration.handler.AbstractReplyProducingMessageHand * @since 2.2 * */ -public abstract class AbstractRequestHandlerAdvice implements MethodInterceptor { +public abstract class AbstractRequestHandlerAdvice extends IntegrationObjectSupport + implements MethodInterceptor { protected final Log logger = LogFactory.getLog(this.getClass()); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java index 953d86d51b..3435dfe32c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java @@ -15,19 +15,21 @@ */ package org.springframework.integration.handler.advice; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; import org.springframework.integration.MessageHeaders; +import org.springframework.integration.MessagingException; import org.springframework.integration.core.MessageHandler; import org.springframework.integration.core.MessagingTemplate; -import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.util.StringUtils; +import org.springframework.integration.message.AdviceMessage; +import org.springframework.integration.message.ErrorMessage; +import org.springframework.integration.util.ExpressionUtils; +import org.springframework.util.Assert; /** * Used to advise {@link MessageHandler}s. @@ -40,16 +42,15 @@ import org.springframework.util.StringUtils; * @since 2.2 * */ -public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHandlerAdvice - implements BeanFactoryAware { +public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHandlerAdvice { - private final ExpressionEvaluatingMessageProcessor onSuccessMessageProcessor; + private volatile Expression onSuccessExpression; - private final MessageChannel successChannel; + private volatile MessageChannel successChannel; - private final ExpressionEvaluatingMessageProcessor onFailureMessageProcessor; + private volatile Expression onFailureExpression; - private final MessageChannel failureChannel; + private volatile MessageChannel failureChannel; private final MessagingTemplate messagingTemplate = new MessagingTemplate(); @@ -57,45 +58,28 @@ public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHan private volatile boolean returnFailureExpressionResult = false; - private volatile BeanFactory beanFactory; - private volatile boolean propagateOnSuccessEvaluationFailures; - /** - * @param onSuccessExpression - * @param successChannel - * @param onFailureExpression - * @param failureChannel - */ - public ExpressionEvaluatingRequestHandlerAdvice(Expression onSuccessExpression, MessageChannel successChannel, - Expression onFailureExpression, MessageChannel failureChannel) { - if (onSuccessExpression != null) { - this.onSuccessMessageProcessor = new ExpressionEvaluatingMessageProcessor(onSuccessExpression); - this.onSuccessMessageProcessor.setBeanFactory(this.beanFactory); - } - else { - this.onSuccessMessageProcessor = null; - } - this.successChannel = successChannel; - if (onFailureExpression != null) { - this.onFailureMessageProcessor = new ExpressionEvaluatingMessageProcessor(onFailureExpression); - onFailureMessageProcessor.setBeanFactory(this.beanFactory); - } - else { - this.onFailureMessageProcessor = null; - } - this.failureChannel = failureChannel; + private volatile EvaluationContext evaluationContext; + public void setOnSuccessExpression(String onSuccessExpression) { + Assert.notNull(onSuccessExpression, "'onSuccessExpression' must not be null"); + this.onSuccessExpression = new SpelExpressionParser().parseExpression(onSuccessExpression); } - public ExpressionEvaluatingRequestHandlerAdvice(String onSuccessExpression, MessageChannel successChannel, - String onFailureExpression, MessageChannel failureChannel) { - this(!StringUtils.hasText(onSuccessExpression) ? null : - new SpelExpressionParser().parseExpression(onSuccessExpression), - successChannel, - !StringUtils.hasText(onFailureExpression) ? null : - new SpelExpressionParser().parseExpression(onFailureExpression), - failureChannel); + public void setOnFailureExpression(String onFailureExpression) { + Assert.notNull(onFailureExpression, "'onFailureExpression' must not be null"); + this.onFailureExpression = new SpelExpressionParser().parseExpression(onFailureExpression); + } + + public void setSuccessChannel(MessageChannel successChannel) { + Assert.notNull(successChannel,"'successChannel' must not be null"); + this.successChannel = successChannel; + } + + public void setFailureChannel(MessageChannel failureChannel) { + Assert.notNull(failureChannel,"'failureChannel' must not be null"); + this.failureChannel = failureChannel; } /** @@ -126,22 +110,18 @@ public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHan this.propagateOnSuccessEvaluationFailures = propagateOnSuccessEvaluationFailures; } - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - @Override protected Object doInvoke(ExecutionCallback callback, Object target, Message message) throws Exception { try { Object result = callback.execute(); - if (this.onSuccessMessageProcessor != null) { - evaluateExpression(message, this.onSuccessMessageProcessor, this.successChannel, this.propagateOnSuccessEvaluationFailures); + if (this.onSuccessExpression != null) { + this.evaluateSuccessExpression(message); } return result; } catch (Exception e) { - if (this.onFailureMessageProcessor != null) { - Object evalResult = evaluateExpression(message, this.onFailureMessageProcessor, this.failureChannel, false); + if (this.onFailureExpression != null) { + Object evalResult = this.evaluateFailureExpression(message, e); if (this.returnFailureExpressionResult) { return evalResult; } @@ -153,28 +133,90 @@ public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHan } } - private Object evaluateExpression(Message message, - ExpressionEvaluatingMessageProcessor expressionEvaluatingMessageProcessor, - MessageChannel resultChannel, boolean propagateEvaluationFailure) throws Exception { + private void evaluateSuccessExpression(Message message) throws Exception { Object evalResult; boolean evaluationFailed = false; try { - evalResult = expressionEvaluatingMessageProcessor.processMessage(message); + evalResult = this.onSuccessExpression.getValue(this.prepareEvaluationContextToUse(null), message); } catch (Exception e) { evalResult = e; evaluationFailed = true; } - if (evalResult != null && resultChannel != null) { - message = MessageBuilder.fromMessage(message) - .setHeader(MessageHeaders.POSTPROCESS_RESULT, evalResult) - .build(); - this.messagingTemplate.send(resultChannel, message); + if (evalResult != null && this.successChannel != null) { + AdviceMessage resultMessage = new AdviceMessage(evalResult, message); + this.messagingTemplate.send(this.successChannel, resultMessage); } - if (evaluationFailed && propagateEvaluationFailure) { + if (evaluationFailed && this.propagateOnSuccessEvaluationFailures) { throw (Exception) evalResult; } + } + + private Object evaluateFailureExpression(Message message, Exception exception) throws Exception { + Object evalResult; + try { + evalResult = this.onFailureExpression.getValue(this.prepareEvaluationContextToUse(exception), message); + } + catch (Exception e) { + evalResult = e; + logger.error("Failure expression evaluation failed for " + message + ": " + e.getMessage()); + } + if (evalResult != null && this.failureChannel != null) { + MessagingException messagingException = new MessageHandlingExpressionEvaluatingAdviceException(message, + "Handler Failed", exception, evalResult); + ErrorMessage resultMessage = new ErrorMessage(messagingException); + this.messagingTemplate.send(this.failureChannel, resultMessage); + } return evalResult; } + protected StandardEvaluationContext createEvaluationContext(){ + if (this.getBeanFactory() != null) { + return ExpressionUtils.createStandardEvaluationContext(new BeanFactoryResolver(this.getBeanFactory()), + this.getConversionService()); + } + else { + return ExpressionUtils.createStandardEvaluationContext(this.getConversionService()); + } + } + + /** + * If we don't need variables (i.e., exception is null) + * we can use a singleton context; otherwise we need a new one each time. + * @param exception + * @return The context. + */ + private EvaluationContext prepareEvaluationContextToUse(Exception exception) { + EvaluationContext evaluationContextToUse; + if (exception != null) { + evaluationContextToUse = this.createEvaluationContext(); + evaluationContextToUse.setVariable("exception", exception); + } + else { + if (this.evaluationContext == null) { + this.evaluationContext = this.createEvaluationContext(); + } + evaluationContextToUse = this.evaluationContext; + } + return evaluationContextToUse; + } + + public static class MessageHandlingExpressionEvaluatingAdviceException extends MessagingException { + + private static final long serialVersionUID = 1L; + + private final Object evaluationResult; + + public MessageHandlingExpressionEvaluatingAdviceException(Message message, String description, + Throwable cause, Object evaluationResult) { + super(message, description, cause); + this.evaluationResult = evaluationResult; + } + + public Object getEvaluationResult() { + return evaluationResult; + } + + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/message/AdviceMessage.java b/spring-integration-core/src/main/java/org/springframework/integration/message/AdviceMessage.java new file mode 100644 index 0000000000..6f1b768968 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/message/AdviceMessage.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.message; + +import java.util.Map; + +import org.springframework.integration.Message; + +/** + * A message implementation that is produced by an advice after + * successful message handling. + * Contains the result of the expression evaluation in the payload + * and the original message that the advice passed to the + * handler. + * . + * @author Gary Russell + * @since 2.2 + */ +public class AdviceMessage extends GenericMessage { + + private static final long serialVersionUID = 1L; + + private final Message inputMessage; + + public AdviceMessage(Object payload, Message inputMessage) { + super(payload); + this.inputMessage = inputMessage; + } + + public AdviceMessage(Object payload, Map headers, Message inputMessage) { + super(payload, headers); + this.inputMessage = inputMessage; + } + + public Message getInputMessage() { + return inputMessage; + } + +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java index 98382f6c40..26b1f64864 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java @@ -28,13 +28,14 @@ import java.util.concurrent.atomic.AtomicInteger; import org.aopalliance.aop.Advice; import org.junit.Test; -import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.Message; import org.springframework.integration.MessageHandlingException; -import org.springframework.integration.MessageHeaders; +import org.springframework.integration.MessagingException; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.core.PollableChannel; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; +import org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice.MessageHandlingExpressionEvaluatingAdviceException; +import org.springframework.integration.message.AdviceMessage; import org.springframework.integration.message.GenericMessage; import org.springframework.retry.RecoveryCallback; import org.springframework.retry.RetryContext; @@ -72,9 +73,11 @@ public class AdvisedMessageHandlerTests { PollableChannel successChannel = new QueueChannel(); PollableChannel failureChannel = new QueueChannel(); - ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice( - "'foo'", successChannel, - "'bar'", failureChannel); + ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice(); + advice.setSuccessChannel(successChannel); + advice.setFailureChannel(failureChannel); + advice.setOnSuccessExpression("'foo'"); + advice.setOnFailureExpression("'bar:' + #exception.cause.message"); List adviceChain = new ArrayList(); adviceChain.add(advice); @@ -89,8 +92,8 @@ public class AdvisedMessageHandlerTests { Message success = successChannel.receive(1000); assertNotNull(success); - assertEquals("Hello, world!", success.getPayload()); - assertEquals("foo", success.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)); + assertEquals("Hello, world!", ((AdviceMessage) success).getInputMessage().getPayload()); + assertEquals("foo", success.getPayload()); // advice with failure, not trapped doFail.set(true); @@ -104,16 +107,16 @@ public class AdvisedMessageHandlerTests { Message failure = failureChannel.receive(1000); assertNotNull(failure); - assertEquals("Hello, world!", failure.getPayload()); - assertEquals("bar", failure.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)); + assertEquals("Hello, world!", ((MessagingException) failure.getPayload()).getFailedMessage().getPayload()); + assertEquals("bar:qux", ((MessageHandlingExpressionEvaluatingAdviceException) failure.getPayload()).getEvaluationResult()); // advice with failure, trapped advice.setTrapException(true); handler.handleMessage(message); failure = failureChannel.receive(1000); assertNotNull(failure); - assertEquals("Hello, world!", failure.getPayload()); - assertEquals("bar", failure.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)); + assertEquals("Hello, world!", ((MessagingException) failure.getPayload()).getFailedMessage().getPayload()); + assertEquals("bar:qux", ((MessageHandlingExpressionEvaluatingAdviceException) failure.getPayload()).getEvaluationResult()); assertNull(replies.receive(1)); // advice with failure, eval is result @@ -121,12 +124,12 @@ public class AdvisedMessageHandlerTests { handler.handleMessage(message); failure = failureChannel.receive(1000); assertNotNull(failure); - assertEquals("Hello, world!", failure.getPayload()); - assertEquals("bar", failure.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)); + assertEquals("Hello, world!", ((MessagingException) failure.getPayload()).getFailedMessage().getPayload()); + assertEquals("bar:qux", ((MessageHandlingExpressionEvaluatingAdviceException) failure.getPayload()).getEvaluationResult()); reply = replies.receive(1000); assertNotNull(reply); - assertEquals("bar", reply.getPayload()); + assertEquals("bar:qux", reply.getPayload()); } @@ -148,9 +151,11 @@ public class AdvisedMessageHandlerTests { PollableChannel successChannel = new QueueChannel(); PollableChannel failureChannel = new QueueChannel(); - ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice( - new SpelExpressionParser().parseExpression("1/0"), successChannel, - new SpelExpressionParser().parseExpression("1/0"), failureChannel); + ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice(); + advice.setSuccessChannel(successChannel); + advice.setFailureChannel(failureChannel); + advice.setOnSuccessExpression("1/0"); + advice.setOnFailureExpression("1/0"); List adviceChain = new ArrayList(); adviceChain.add(advice); @@ -165,9 +170,9 @@ public class AdvisedMessageHandlerTests { Message success = successChannel.receive(1000); assertNotNull(success); - assertEquals("Hello, world!", success.getPayload()); - assertEquals(MessageHandlingException.class, success.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT).getClass()); - assertEquals("Expression evaluation failed: 1/0", ((Exception) success.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)).getMessage()); + assertEquals("Hello, world!", ((AdviceMessage) success).getInputMessage().getPayload()); + assertEquals(ArithmeticException.class, success.getPayload().getClass()); + assertEquals("/ by zero", ((Exception) success.getPayload()).getMessage()); // propagate failing advice with success advice.setPropagateEvaluationFailures(true); @@ -176,16 +181,16 @@ public class AdvisedMessageHandlerTests { fail("Expected Exception"); } catch (MessageHandlingException e) { - assertEquals("Expression evaluation failed: 1/0", e.getMessage()); + assertEquals("/ by zero", e.getCause().getMessage()); } reply = replies.receive(1); assertNull(reply); success = successChannel.receive(1000); assertNotNull(success); - assertEquals("Hello, world!", success.getPayload()); - assertEquals(MessageHandlingException.class, success.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT).getClass()); - assertEquals("Expression evaluation failed: 1/0", ((Exception) success.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)).getMessage()); + assertEquals("Hello, world!", ((AdviceMessage) success).getInputMessage().getPayload()); + assertEquals(ArithmeticException.class, success.getPayload().getClass()); + assertEquals("/ by zero", ((Exception) success.getPayload()).getMessage()); } @@ -207,9 +212,11 @@ public class AdvisedMessageHandlerTests { PollableChannel successChannel = new QueueChannel(); PollableChannel failureChannel = new QueueChannel(); - ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice( - new SpelExpressionParser().parseExpression("1/0"), successChannel, - new SpelExpressionParser().parseExpression("1/0"), failureChannel); + ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice(); + advice.setSuccessChannel(successChannel); + advice.setFailureChannel(failureChannel); + advice.setOnSuccessExpression("1/0"); + advice.setOnFailureExpression("1/0"); List adviceChain = new ArrayList(); adviceChain.add(advice); @@ -229,9 +236,9 @@ public class AdvisedMessageHandlerTests { Message failure = failureChannel.receive(1000); assertNotNull(failure); - assertEquals("Hello, world!", failure.getPayload()); - assertEquals(MessageHandlingException.class, failure.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT).getClass()); - assertEquals("Expression evaluation failed: 1/0", ((Exception) failure.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)).getMessage()); + assertEquals("Hello, world!", ((MessagingException) failure.getPayload()).getFailedMessage().getPayload()); + assertEquals(MessageHandlingExpressionEvaluatingAdviceException.class, failure.getPayload().getClass()); + assertEquals("qux", ((Exception) failure.getPayload()).getCause().getCause().getMessage()); // propagate failing advice with failure; expect original exception advice.setPropagateEvaluationFailures(true); @@ -247,9 +254,9 @@ public class AdvisedMessageHandlerTests { failure = failureChannel.receive(1000); assertNotNull(failure); - assertEquals("Hello, world!", failure.getPayload()); - assertEquals(MessageHandlingException.class, failure.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT).getClass()); - assertEquals("Expression evaluation failed: 1/0", ((Exception) failure.getHeaders().get(MessageHeaders.POSTPROCESS_RESULT)).getMessage()); + assertEquals("Hello, world!", ((MessagingException) failure.getPayload()).getFailedMessage().getPayload()); + assertEquals(MessageHandlingExpressionEvaluatingAdviceException.class, failure.getPayload().getClass()); + assertEquals("qux", ((Exception) failure.getPayload()).getCause().getCause().getMessage()); } diff --git a/src/reference/docbook/handler-advice.xml b/src/reference/docbook/handler-advice.xml index 6ff7b2497e..b561bcac0a 100644 --- a/src/reference/docbook/handler-advice.xml +++ b/src/reference/docbook/handler-advice.xml @@ -369,46 +369,24 @@ Caused by: java.lang.RuntimeException: foo org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice. This advice is more general than the other two advices. It provides a mechanism to evaluate an expression on the original inbound message sent to the endpoint. Separate expressions are available to be evaluated, either after - success, or failure. Optionally, the original message, together with the result of the evaluation in a - header, can be sent to a message channel. + success, or failure. Optionally, a message containing the evaluation result, together with the input message, + can be sent to a message channel. A typical use case for this advice might be with an <ftp:outbound-channel-adapter />, perhaps to move the file to one directory if the transfer was successful, or to another directory if it fails: - - - - - - - - - - - - -DEBUG [main] preSend on channel 'ftpChannel', message: [Payload=target/toSend/b.txt][Headers=...] -DEBUG [main] Connected to server [localhost:21] -INFO [main] File has been successfully transfered to: ./b.txt.writing -INFO [main] File has been successfully renamed from: ./b.txt.writing to ./b.txt -DEBUG [main] preSend on channel 'successChannel', message: [Payload=target/toSend/b.txt][Headers={..., postProcessResult=true}] - -... - -DEBUG [main] preSend on channel 'ftpChannel', message: [Payload=target/toSend/a.txt][Headers=...] -DEBUG [main] Connected to server [localhost:21] -... -DEBUG [main] preSend on channel 'failureChannel', message: [Payload=target/toSend/a.txt][Headers={..., postProcessResult=true}]]]> - As you can see, in the first case, the successful transfer resulted in a message sent to - successChannel; the second case shows the result being sent to - failureChannel. In both cases, you can see the postProcessResult - header containing the result of the evaluation (true because the rename operations were successful - - java.io.File.renameTo(...) returns a boolean). + The Advice has properties to set an expression when successful, an expression for failures, + and corresponding channels for each. For the successful case, the message sent to the + successChannel is an AdviceMessage, with + the payload being the result of the expression evaluation, and an additional property + inputMessage which contains the original message sent to the handler. A message + sent to the failureChannel (when the handler throws an excecption) + is an ErrorMessage with a payload of MessageHandlingExpressionEvaluatingAdviceException. + Like all MessagingExceptions, this payload has failedMessage + and cause properties, as well as an additional property evaluationResult, + containing the result of the expression evaluation.