BATCH-798: Samples working again. TODO: refactor rollbackClassifier into the stateless execution API

This commit is contained in:
dsyer
2008-08-29 17:14:59 +00:00
parent 2ea0fe68cf
commit bd91d0c35e
6 changed files with 35 additions and 13 deletions

View File

@@ -33,6 +33,7 @@ import org.springframework.batch.retry.policy.MapRetryContextCache;
import org.springframework.batch.retry.policy.RetryContextCache;
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
import org.springframework.batch.retry.support.RetryTemplate;
import org.springframework.batch.support.Classifier;
/**
* Factory bean for step that provides options for configuring skip behaviour.
@@ -225,6 +226,12 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
retryTemplate.setBackOffPolicy(backOffPolicy);
}
retryTemplate.setRetryPolicy(retryPolicy);
Classifier<Throwable, Boolean> rollbackClassifier = new Classifier<Throwable, Boolean>() {
public Boolean classify(Throwable classifiable) {
return getTransactionAttribute().rollbackOn(classifiable);
}
};
retryTemplate.setRollbackClassifier(rollbackClassifier);
// Co-ordinate the retry policy with the exception handler:
RepeatOperations stepOperations = getStepOperations();
@@ -254,7 +261,7 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
ItemSkipPolicy writeSkipPolicy = new LimitCheckingItemSkipPolicy(skipLimit, exceptions,
new ArrayList<Class<? extends Throwable>>(fatalExceptionClasses));
ChunkOrientedTasklet<T, S> tasklet = new StatefulRetryTasklet<T, S>(getItemReader(), getItemProcessor(),
getItemWriter(), getChunkOperations(), retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
getItemWriter(), getChunkOperations(), retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
tasklet.setListeners(getListeners());
step.setTasklet(tasklet);
@@ -297,6 +304,8 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
final private ItemSkipPolicy processSkipPolicy;
final private Classifier<Throwable, Boolean> rollbackClassifier;
/**
* @param itemReader
* @param itemWriter
@@ -304,10 +313,11 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
*/
public StatefulRetryTasklet(ItemReader<? extends T> itemReader,
ItemProcessor<? super T, ? extends S> itemProcessor, ItemWriter<? super S> itemWriter,
RepeatOperations chunkOperations, RetryOperations retryTemplate, ItemSkipPolicy readSkipPolicy,
RepeatOperations chunkOperations, RetryOperations retryTemplate, Classifier<Throwable, Boolean> rollbackClassifier, ItemSkipPolicy readSkipPolicy,
ItemSkipPolicy writeSkipPolicy, ItemSkipPolicy processSkipPolicy) {
super(itemReader, itemProcessor, itemWriter, chunkOperations);
this.retryOperations = retryTemplate;
this.rollbackClassifier = rollbackClassifier;
this.readSkipPolicy = readSkipPolicy;
this.writeSkipPolicy = writeSkipPolicy;
this.processSkipPolicy = processSkipPolicy;
@@ -472,7 +482,9 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
}
catch (Exception e) {
checkSkipPolicy(contribution, iterator, e);
throw e;
if (rollbackClassifier.classify(e)) {
throw e;
}
}
}

View File

@@ -3,8 +3,6 @@ package org.springframework.batch.core.repository.dao;
import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.JobExecution;

View File

@@ -42,6 +42,7 @@ import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.batch.retry.policy.NeverRetryPolicy;
import org.springframework.batch.retry.support.RetryTemplate;
import org.springframework.batch.support.Classifier;
/**
* @author Dave Syer
@@ -84,6 +85,12 @@ public class StatefulRetryTaskletTests {
};
private RetryTemplate retryTemplate = new RetryTemplate();
private Classifier<Throwable, Boolean> rollbackClassifier = new Classifier<Throwable, Boolean>() {
public Boolean classify(Throwable classifiable) {
return true;
}
};
private ItemSkipPolicy readSkipPolicy = new ItemSkipPolicy() {
public boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException {
@@ -105,7 +112,7 @@ public class StatefulRetryTaskletTests {
@Test
public void testBasicHandle() throws Exception {
handler = new StatefulRetryTasklet<Integer, String>(itemReader, itemProcessor, itemWriter, chunkOperations,
retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
handler.execute(contribution, new BasicAttributeAccessor());
assertEquals(limit, contribution.getItemCount());
@@ -117,7 +124,7 @@ public class StatefulRetryTaskletTests {
public Integer read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException {
throw new RuntimeException("Barf!");
}
}, itemProcessor, itemWriter, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
}, itemProcessor, itemWriter, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(1));
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
BasicAttributeAccessor attributes = new BasicAttributeAccessor();
@@ -139,7 +146,7 @@ public class StatefulRetryTaskletTests {
written.addAll(items);
throw new RuntimeException("Barf!");
}
}, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
}, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(1));
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
BasicAttributeAccessor attributes = new BasicAttributeAccessor();
@@ -165,7 +172,7 @@ public class StatefulRetryTaskletTests {
written.addAll(items);
throw new RuntimeException("Barf!");
}
}, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
}, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(2));
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
BasicAttributeAccessor attributes = new BasicAttributeAccessor();
@@ -217,7 +224,7 @@ public class StatefulRetryTaskletTests {
throw new RuntimeException("Barf!");
}
}
, itemWriter, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
, itemWriter, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(2));
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
BasicAttributeAccessor attributes = new BasicAttributeAccessor();

View File

@@ -448,6 +448,8 @@ public class RetryTemplate implements RetryOperations {
protected boolean shouldRethrow(RetryPolicy retryPolicy, RetryContext context, RetryState state) {
// Allow stateless behaviour to take over for certain exception types
if (rollbackClassifier != null) {
// TODO: remove this. Make it part of the stateful execution parameters?
// Then we wouldn't have to make assertions about the stateless case.
boolean rollback = rollbackClassifier.classify(context.getLastThrowable());
if (rollback && state == null && retryPolicy.canRetry(context)) {
throw new RetryException("Inconsistent configuration. The retry policy says we can retry but "

View File

@@ -28,6 +28,7 @@ public class ItemTrackingItemWriter<T> implements ItemWriter<T> {
counter += items.size();
if (current < failure && counter >= failure) {
failed = items.get(failure-current-1);
this.items.remove(failed);
throw new ValidationException("validation failed");
}
}

View File

@@ -51,9 +51,10 @@ public class ItemTrackingItemWriterTests {
catch (ValidationException e) {
// expected
}
assertEquals(3, writer.getItems().size());
// the failed item is removed
assertEquals(2, writer.getItems().size());
writer.write(Arrays.asList("a", "e", "c"));
assertEquals(6, writer.getItems().size());
assertEquals(5, writer.getItems().size());
try {
writer.write(Arrays.asList("f", "b", "g"));
fail("Expected ValidationException");
@@ -61,7 +62,8 @@ public class ItemTrackingItemWriterTests {
catch (ValidationException e) {
// expected
}
assertEquals(6, writer.getItems().size());
// barf immediately if a failure is detected
assertEquals(5, writer.getItems().size());
}
}