RESOLVED - issue BATCH-973: Switch RetryPolicy back to Throwable instead of Exception as in 1.x
http://jira.springframework.org/browse/BATCH-973
This commit is contained in:
@@ -123,7 +123,7 @@ public class BatchRetryTemplate implements RetryOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerThrowable(RetryPolicy retryPolicy, RetryState state, RetryContext context, Exception e) {
|
||||
protected void registerThrowable(RetryPolicy retryPolicy, RetryState state, RetryContext context, Throwable e) {
|
||||
|
||||
BatchRetryState batchState = (BatchRetryState) state;
|
||||
BatchRetryContext batchContext = (BatchRetryContext) context;
|
||||
|
||||
@@ -222,7 +222,7 @@ public class Chunk<W> implements Iterable<W> {
|
||||
return next;
|
||||
}
|
||||
|
||||
public void remove(Exception e) {
|
||||
public void remove(Throwable e) {
|
||||
remove();
|
||||
skips.add(new SkipWrapper<W>(next, e));
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ public class FaultTolerantChunkProcessor<I, O> extends SimpleChunkProcessor<I, O
|
||||
RecoveryCallback<O> recoveryCallback = new RecoveryCallback<O>() {
|
||||
|
||||
public O recover(RetryContext context) throws Exception {
|
||||
Exception e = context.getLastThrowable();
|
||||
Throwable e = context.getLastThrowable();
|
||||
if (itemProcessSkipPolicy.shouldSkip(e, contribution.getStepSkipCount())) {
|
||||
contribution.incrementProcessSkipCount();
|
||||
iterator.remove(e);
|
||||
@@ -315,7 +315,7 @@ public class FaultTolerantChunkProcessor<I, O> extends SimpleChunkProcessor<I, O
|
||||
|
||||
public Object recover(RetryContext context) throws Exception {
|
||||
|
||||
Exception e = context.getLastThrowable();
|
||||
Throwable e = context.getLastThrowable();
|
||||
if (outputs.size() > 1 && !rollbackClassifier.classify(e)) {
|
||||
throw new RetryException("Invalid retry state during write caused by "
|
||||
+ "exception that does not classify for rollback: ", e);
|
||||
@@ -387,12 +387,12 @@ public class FaultTolerantChunkProcessor<I, O> extends SimpleChunkProcessor<I, O
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
Exception e = wrapper.getException();
|
||||
Throwable e = wrapper.getException();
|
||||
callProcessSkipListener(item, e);
|
||||
}
|
||||
|
||||
for (SkipWrapper<O> wrapper : outputs.getSkips()) {
|
||||
Exception e = wrapper.getException();
|
||||
Throwable e = wrapper.getException();
|
||||
try {
|
||||
getListener().onSkipInWrite(wrapper.getItem(), e);
|
||||
}
|
||||
@@ -414,7 +414,7 @@ public class FaultTolerantChunkProcessor<I, O> extends SimpleChunkProcessor<I, O
|
||||
* @param item the item that is skipped
|
||||
* @param e the cause of the skip
|
||||
*/
|
||||
private void callProcessSkipListener(I item, Exception e) {
|
||||
private void callProcessSkipListener(I item, Throwable e) {
|
||||
try {
|
||||
getListener().onSkipInProcess(item, e);
|
||||
}
|
||||
@@ -442,7 +442,7 @@ public class FaultTolerantChunkProcessor<I, O> extends SimpleChunkProcessor<I, O
|
||||
}
|
||||
|
||||
private void checkSkipPolicy(Chunk<I>.ChunkIterator inputIterator, Chunk<O>.ChunkIterator outputIterator,
|
||||
Exception e, StepContribution contribution) {
|
||||
Throwable e, StepContribution contribution) {
|
||||
logger.debug("Checking skip policy after failed write");
|
||||
if (itemWriteSkipPolicy.shouldSkip(e, contribution.getStepSkipCount())) {
|
||||
contribution.incrementWriteSkipCount();
|
||||
|
||||
@@ -24,7 +24,7 @@ package org.springframework.batch.core.step.item;
|
||||
*/
|
||||
public class SkipWrapper<T> {
|
||||
|
||||
final private Exception exception;
|
||||
final private Throwable exception;
|
||||
|
||||
final private T item;
|
||||
|
||||
@@ -38,12 +38,12 @@ public class SkipWrapper<T> {
|
||||
/**
|
||||
* @param e
|
||||
*/
|
||||
public SkipWrapper(Exception e) {
|
||||
public SkipWrapper(Throwable e) {
|
||||
this(null, e);
|
||||
}
|
||||
|
||||
|
||||
public SkipWrapper(T item, Exception e) {
|
||||
public SkipWrapper(T item, Throwable e) {
|
||||
this.item = item;
|
||||
this.exception = e;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class SkipWrapper<T> {
|
||||
* Public getter for the exception.
|
||||
* @return the exception
|
||||
*/
|
||||
public Exception getException() {
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,10 +99,10 @@ public class FaultTolerantChunkProcessorTests {
|
||||
}
|
||||
|
||||
/**
|
||||
* An Error pops right back up (no skips, no retry)
|
||||
* An Error can be retried or skipped but by default it is just propagated
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test(expected=AssertionError.class)
|
||||
@Test
|
||||
public void testWriteSkipOnError() throws Exception {
|
||||
processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
processor.setItemWriter(new ItemWriter<String>() {
|
||||
|
||||
@@ -64,6 +64,6 @@ public interface RetryContext extends AttributeAccessor {
|
||||
* be null if this is the first attempt, but also if the enclosing policy
|
||||
* decides not to provide it (e.g. because of concerns about memory usage).
|
||||
*/
|
||||
Exception getLastThrowable();
|
||||
Throwable getLastThrowable();
|
||||
|
||||
}
|
||||
|
||||
@@ -58,6 +58,6 @@ public interface RetryPolicy {
|
||||
* @param context the current status object.
|
||||
*
|
||||
*/
|
||||
void registerThrowable(RetryContext context, Exception throwable);
|
||||
void registerThrowable(RetryContext context, Throwable throwable);
|
||||
|
||||
}
|
||||
|
||||
@@ -55,6 +55,6 @@ public interface RetryState {
|
||||
* @param exception the exception that caused a retry attempt to fail
|
||||
* @return true if this exception should cause a rollback
|
||||
*/
|
||||
boolean rollbackFor(Exception exception);
|
||||
boolean rollbackFor(Throwable exception);
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public class RetryContextSupport extends AttributeAccessorSupport implements Ret
|
||||
|
||||
private int count;
|
||||
|
||||
private Exception lastException;
|
||||
private Throwable lastException;
|
||||
|
||||
private RetryContext parent;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class RetryContextSupport extends AttributeAccessorSupport implements Ret
|
||||
return count;
|
||||
}
|
||||
|
||||
public Exception getLastThrowable() {
|
||||
public Throwable getLastThrowable() {
|
||||
return lastException;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class RetryContextSupport extends AttributeAccessorSupport implements Ret
|
||||
* @param throwable the exception that caused the current retry attempt to
|
||||
* fail.
|
||||
*/
|
||||
public void registerThrowable(Exception throwable) {
|
||||
public void registerThrowable(Throwable throwable) {
|
||||
this.lastException = throwable;
|
||||
if (throwable != null)
|
||||
count++;
|
||||
|
||||
@@ -107,7 +107,7 @@ public class CompositeRetryPolicy implements RetryPolicy {
|
||||
*
|
||||
* @see org.springframework.batch.retry.RetryPolicy#close(org.springframework.batch.retry.RetryContext)
|
||||
*/
|
||||
public void registerThrowable(RetryContext context, Exception throwable) {
|
||||
public void registerThrowable(RetryContext context, Throwable throwable) {
|
||||
RetryContext[] contexts = ((CompositeRetryContext) context).contexts;
|
||||
RetryPolicy[] policies = ((CompositeRetryContext) context).policies;
|
||||
for (int i = 0; i < contexts.length; i++) {
|
||||
|
||||
@@ -99,9 +99,9 @@ public class ExceptionClassifierRetryPolicy implements RetryPolicy {
|
||||
* Delegate to the policy currently activated in the context.
|
||||
*
|
||||
* @see org.springframework.batch.retry.RetryPolicy#registerThrowable(org.springframework.batch.retry.RetryContext,
|
||||
* Exception)
|
||||
* Throwable)
|
||||
*/
|
||||
public void registerThrowable(RetryContext context, Exception throwable) {
|
||||
public void registerThrowable(RetryContext context, Throwable throwable) {
|
||||
RetryPolicy policy = (RetryPolicy) context;
|
||||
policy.registerThrowable(context, throwable);
|
||||
((RetryContextSupport) context).registerThrowable(throwable);
|
||||
@@ -144,7 +144,7 @@ public class ExceptionClassifierRetryPolicy implements RetryPolicy {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void registerThrowable(RetryContext context, Exception throwable) {
|
||||
public void registerThrowable(RetryContext context, Throwable throwable) {
|
||||
policy = exceptionClassifier.classify(throwable);
|
||||
Assert.notNull(policy, "Could not locate policy for exception=[" + throwable + "].");
|
||||
this.context = getContext(policy, context.getParent());
|
||||
|
||||
@@ -60,11 +60,11 @@ public class NeverRetryPolicy implements RetryPolicy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing.
|
||||
* Make the throwable available for downstream use through the context.
|
||||
* @see org.springframework.batch.retry.RetryPolicy#registerThrowable(org.springframework.batch.retry.RetryContext,
|
||||
* Exception)
|
||||
* Throwable)
|
||||
*/
|
||||
public void registerThrowable(RetryContext context, Exception throwable) {
|
||||
public void registerThrowable(RetryContext context, Throwable throwable) {
|
||||
((NeverRetryContext) context).setFinished();
|
||||
((RetryContextSupport) context).registerThrowable(throwable);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,8 @@ public class SimpleRetryPolicy implements RetryPolicy {
|
||||
* attempts.
|
||||
*/
|
||||
public SimpleRetryPolicy() {
|
||||
this(DEFAULT_MAX_ATTEMPTS, Collections.<Class<? extends Throwable>, Boolean>singletonMap(Exception.class, true));
|
||||
this(DEFAULT_MAX_ATTEMPTS, Collections
|
||||
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,10 +106,9 @@ public class SimpleRetryPolicy implements RetryPolicy {
|
||||
/**
|
||||
* Update the status with another attempted retry and the latest exception.
|
||||
*
|
||||
* @see org.springframework.batch.retry.RetryPolicy#registerThrowable(org.springframework.batch.retry.RetryContext,
|
||||
* Exception)
|
||||
* @see RetryPolicy#registerThrowable(RetryContext, Throwable)
|
||||
*/
|
||||
public void registerThrowable(RetryContext context, Exception throwable) {
|
||||
public void registerThrowable(RetryContext context, Throwable throwable) {
|
||||
SimpleRetryContext simpleContext = ((SimpleRetryContext) context);
|
||||
simpleContext.registerThrowable(throwable);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class TimeoutRetryPolicy implements RetryPolicy {
|
||||
return new TimeoutRetryContext(parent, timeout);
|
||||
}
|
||||
|
||||
public void registerThrowable(RetryContext context, Exception throwable) {
|
||||
public void registerThrowable(RetryContext context, Throwable throwable) {
|
||||
((RetryContextSupport) context).registerThrowable(throwable);
|
||||
// otherwise no-op - we only time out, otherwise retry everything...
|
||||
}
|
||||
|
||||
@@ -103,10 +103,10 @@ public class DefaultRetryState implements RetryState {
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.batch.retry.IRetryState#rollbackFor(java.lang.Exception
|
||||
* org.springframework.batch.retry.RetryState#rollbackFor(java.lang.Throwable
|
||||
* )
|
||||
*/
|
||||
public boolean rollbackFor(Exception exception) {
|
||||
public boolean rollbackFor(Throwable exception) {
|
||||
if (rollbackClassifier == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.repeat.RepeatException;
|
||||
import org.springframework.batch.retry.ExhaustedRetryException;
|
||||
import org.springframework.batch.retry.RecoveryCallback;
|
||||
import org.springframework.batch.retry.RetryCallback;
|
||||
@@ -236,7 +237,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
lastException = null;
|
||||
return retryCallback.doWithRetry(context);
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Throwable e) {
|
||||
|
||||
lastException = e;
|
||||
|
||||
@@ -258,7 +259,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
logger.debug("Checking for rethrow: count=" + context.getRetryCount());
|
||||
if (shouldRethrow(retryPolicy, context, state)) {
|
||||
logger.debug("Rethrow in retry for policy: count=" + context.getRetryCount());
|
||||
throw e;
|
||||
throw wrapIfNecessary(e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -327,7 +328,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
* @param context
|
||||
* @param e
|
||||
*/
|
||||
protected void registerThrowable(RetryPolicy retryPolicy, RetryState state, RetryContext context, Exception e) {
|
||||
protected void registerThrowable(RetryPolicy retryPolicy, RetryState state, RetryContext context, Throwable e) {
|
||||
if (state != null) {
|
||||
Object key = state.getKey();
|
||||
if (context.getRetryCount() > 0 && !retryContextCache.containsKey(key)) {
|
||||
@@ -415,7 +416,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
throw new ExhaustedRetryException("Retry exhausted after last attempt with no recovery path", context
|
||||
.getLastThrowable());
|
||||
}
|
||||
throw context.getLastThrowable();
|
||||
throw wrapIfNecessary(context.getLastThrowable());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,4 +463,20 @@ public class RetryTemplate implements RetryOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-throws the original throwable if it is unchecked, wraps checked
|
||||
* exceptions into {@link RepeatException}.
|
||||
*/
|
||||
private static Exception wrapIfNecessary(Throwable throwable) {
|
||||
if (throwable instanceof Error) {
|
||||
throw (Error) throwable;
|
||||
}
|
||||
else if (throwable instanceof Exception) {
|
||||
return (Exception) throwable;
|
||||
}
|
||||
else {
|
||||
return new RetryException("Exception in batch process", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class CompositeRetryPolicyTests extends TestCase {
|
||||
return !errorRegistered;
|
||||
}
|
||||
|
||||
public void registerThrowable(RetryContext context, Exception throwable) {
|
||||
public void registerThrowable(RetryContext context, Throwable throwable) {
|
||||
errorRegistered = true;
|
||||
}
|
||||
} });
|
||||
@@ -70,7 +70,7 @@ public class CompositeRetryPolicyTests extends TestCase {
|
||||
assertNotNull(context);
|
||||
assertTrue(policy.canRetry(context));
|
||||
policy.registerThrowable(context, null);
|
||||
assertFalse(policy.canRetry(context));
|
||||
assertFalse("Should be still able to retry", policy.canRetry(context));
|
||||
}
|
||||
|
||||
public void testNonTrivialPoliciesClose() throws Exception {
|
||||
|
||||
@@ -16,14 +16,18 @@
|
||||
|
||||
package org.springframework.batch.retry.support;
|
||||
|
||||
import static org.easymock.EasyMock.createStrictMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.expectLastCall;
|
||||
import static org.easymock.EasyMock.isA;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -295,7 +299,7 @@ public class RetryTemplateTests {
|
||||
}, null, new DefaultRetryState(tested) {
|
||||
|
||||
@Override
|
||||
public boolean rollbackFor(Exception exception) {
|
||||
public boolean rollbackFor(Throwable exception) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user