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 8e5bbeafee..5095bb8dd3 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -21,6 +21,7 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.integration.Message;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.core.MessageHandler;
@@ -33,11 +34,11 @@ import org.springframework.integration.handler.AbstractReplyProducingMessageHand
* {@link MessageHandler#handleMessage(Message)} for other message handlers.
*
* @author Gary Russell
+ * @author Artem Bilan
* @since 2.2
- *
*/
public abstract class AbstractRequestHandlerAdvice extends IntegrationObjectSupport
- implements MethodInterceptor {
+ implements MethodInterceptor {
protected final Log logger = LogFactory.getLog(this.getClass());
@@ -54,7 +55,7 @@ public abstract class AbstractRequestHandlerAdvice extends IntegrationObjectSupp
else {
Message> message = (Message>) arguments[0];
try {
- return doInvoke(new ExecutionCallback(){
+ return doInvoke(new ExecutionCallback() {
public Object execute() throws Exception {
try {
@@ -64,6 +65,26 @@ public abstract class AbstractRequestHandlerAdvice extends IntegrationObjectSupp
throw new ThrowableHolderException(e);
}
}
+
+ public Object cloneAndExecute() throws Exception {
+ try {
+ /*
+ * If we don't copy the invocation carefully it won't keep a reference to the other
+ * interceptors in the chain.
+ */
+ if (invocation instanceof ProxyMethodInvocation) {
+ return ((ProxyMethodInvocation) invocation).invocableClone().proceed();
+ }
+ else {
+ throw new IllegalStateException(
+ "MethodInvocation of the wrong type detected - this should not happen with Spring AOP," +
+ " so please raise an issue if you see this exception");
+ }
+ }
+ catch (Throwable e) {
+ throw new ThrowableHolderException(e);
+ }
+ }
}, invocation.getThis(), message);
}
catch (Exception e) {
@@ -80,17 +101,33 @@ public abstract class AbstractRequestHandlerAdvice extends IntegrationObjectSupp
/**
* Subclasses implement this method to apply behavior to the {@link MessageHandler}.
callback.execute()
* invokes the handler method and returns its result, or null.
+ *
* @param callback Subclasses invoke the execute() method on this interface to invoke the handler method.
- * @param target The target handler.
- * @param message The message that will be sent to the handler.
+ * @param target The target handler.
+ * @param message The message that will be sent to the handler.
* @return the result after invoking the {@link MessageHandler}.
* @throws Exception
*/
protected abstract Object doInvoke(ExecutionCallback callback, Object target, Message> message) throws Exception;
+ /**
+ * Called by subclasses in doInvoke() to proceed() the invocation.
+ *
+ */
protected interface ExecutionCallback {
+ /**
+ * Call this for a normal invocation.proceed().
+ */
Object execute() throws Exception;
+
+ /**
+ * Call this when it is necessary to clone the invocation before
+ * calling proceed() - such as when the invocation might be called
+ * multiple times - for example in a retry advice.
+ */
+ Object cloneAndExecute() throws Exception;
+
}
@SuppressWarnings("serial")
@@ -99,5 +136,7 @@ public abstract class AbstractRequestHandlerAdvice extends IntegrationObjectSupp
public ThrowableHolderException(Throwable cause) {
super(cause);
}
+
}
-}
\ No newline at end of file
+
+}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java
index a89660b799..bed7607600 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -32,12 +32,13 @@ import org.springframework.util.Assert;
* exception is thrown but state is maintained to support
* the retry policies. Stateful retry requires a
* {@link RetryStateGenerator}.
- * @author Gary Russell
- * @since 2.2
*
+ * @author Gary Russell
+ * @author Artem Bilan
+ * @since 2.2
*/
public class RequestHandlerRetryAdvice extends AbstractRequestHandlerAdvice
- implements RetryListener {
+ implements RetryListener {
private volatile RetryTemplate retryTemplate = new RetryTemplate();
@@ -80,10 +81,10 @@ public class RequestHandlerRetryAdvice extends AbstractRequestHandlerAdvice
messageHolder.set(message);
try {
- return retryTemplate.execute(new RetryCallback