Add clone for method invocation to preserve interceptor chain.

This commit is contained in:
dsyer
2007-09-28 07:10:08 +00:00
parent b91e9f92d8
commit 0d6cfca4df
4 changed files with 70 additions and 4 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.batch.repeat.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.batch.repeat.RepeatCallback;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.RepeatOperations;
@@ -50,14 +51,21 @@ public class RepeatOperationsInterceptor implements MethodInterceptor {
*
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
public Object invoke(final MethodInvocation invocation) throws Throwable {
batchTempate.iterate(new RepeatCallback() {
public ExitStatus doInIteration(RepeatContext context) throws Exception {
try {
MethodInvocation clone = invocation;
if (invocation instanceof ReflectiveMethodInvocation) {
clone = ((ReflectiveMethodInvocation) invocation)
.invocableClone();
}
// N.B. discards return value if there is one
return new ExitStatus(methodInvocation.proceed() != null);
return new ExitStatus(clone.proceed() != null);
}
catch (Throwable e) {
if (e instanceof Exception) {

View File

@@ -18,6 +18,7 @@ package org.springframework.batch.retry.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.batch.retry.RetryCallback;
import org.springframework.batch.retry.RetryContext;
import org.springframework.batch.retry.RetryOperations;
@@ -38,12 +39,26 @@ public class RetryOperationsInterceptor implements MethodInterceptor {
this.retryTemplate = retryTemplate;
}
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
public Object invoke(final MethodInvocation invocation) throws Throwable {
// TODO: use the method name to initialise a statistics context
return this.retryTemplate.execute(new RetryCallback() {
public Object doWithRetry(RetryContext context) throws Throwable {
return methodInvocation.proceed();
/*
* If we don't copy the invocation carefully it won't keep a
* reference to the other interceptors in the chain. We don't
* have a choice here but to specialise to
* ReflectiveMethodInvocation (but how often would another
* implementation come along?).
*/
MethodInvocation clone = invocation;
if (invocation instanceof ReflectiveMethodInvocation) {
clone = ((ReflectiveMethodInvocation) invocation)
.invocableClone();
}
return clone.proceed();
}
});

View File

@@ -21,12 +21,16 @@ import java.util.List;
import junit.framework.TestCase;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.batch.repeat.RepeatCallback;
import org.springframework.batch.repeat.RepeatOperations;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.exception.RepeatException;
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
import org.springframework.batch.retry.support.RetryTemplate;
public class RepeatOperationsInterceptorTests extends TestCase {
@@ -88,6 +92,22 @@ public class RepeatOperationsInterceptorTests extends TestCase {
}
}
public void testInterceptorChainWithRetry() throws Exception {
((Advised) service).addAdvice(interceptor);
final List list = new ArrayList();
((Advised) service).addAdvice(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
list.add("chain");
return invocation.proceed();
}
});
RetryTemplate template = new RetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(2));
service.service();
assertEquals(3, target.count);
assertEquals(3, list.size());
}
private interface Service {
Object service() throws Exception;

View File

@@ -16,12 +16,18 @@
package org.springframework.batch.retry.aop;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.batch.retry.policy.NeverRetryPolicy;
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
import org.springframework.batch.retry.support.RetryTemplate;
public class RetryOperationsInterceptorTests extends TestCase {
@@ -45,6 +51,23 @@ public class RetryOperationsInterceptorTests extends TestCase {
assertEquals(2, target.count);
}
public void testInterceptorChainWithRetry() throws Exception {
((Advised) service).addAdvice(interceptor);
final List list = new ArrayList();
((Advised) service).addAdvice(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
list.add("chain");
return invocation.proceed();
}
});
RetryTemplate template = new RetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(2));
interceptor.setRetryTemplate(template);
service.service();
assertEquals(2, target.count);
assertEquals(2, list.size());
}
public void testRetryExceptionAfterTooManyAttempts() throws Exception {
((Advised) service).addAdvice(interceptor);
RetryTemplate template = new RetryTemplate();