From 2ce3013ac1ea7638bad37964ba8fa5ea876bb46b Mon Sep 17 00:00:00 2001 From: dsyer Date: Mon, 11 Feb 2008 17:23:57 +0000 Subject: [PATCH] RESOLVED - issue BATCH-268: retry configuration for ItemOrientedTasklet http://jira.springframework.org/browse/BATCH-268 The retry only works if you have an ItemStream as an ItemReader (so that you get a proper rollback). Applied the patch and fixed it up to fit the new m5 way of looking at things. --- .../execution/step/simple/AbstractStep.java | 20 ++++ .../step/simple/SimpleStepExecutor.java | 3 - .../io/exception/ReadFailureException.java | 2 + .../io/exception/WriteFailureException.java | 2 + .../io/file/DefaultFlatFileItemReader.java | 2 +- .../reader}/AbstractItemReaderRecoverer.java | 6 +- .../item/reader/DelegatingItemReader.java | 2 +- .../batch/item/stream/ItemStreamAdapter.java | 2 +- .../repeat/callback/NestedRepeatCallback.java | 2 +- .../policy/CompletionPolicySupport.java | 2 +- .../policy/CompositeCompletionPolicy.java | 2 +- .../policy/DefaultResultCompletionPolicy.java | 2 +- .../batch/jms/ExternalRetryInBatchTests.java | 2 +- .../batch/retry/jms/ExternalRetryTests.java | 2 +- spring-batch-samples/.springBeans | 12 ++ .../item/reader/GeneratingItemReader.java | 109 ++++++++++++++++++ .../item/writer/RetrySampleItemWriter.java | 29 +++++ .../src/main/resources/jobs/retrySample.xml | 51 ++++++++ .../sample/RetrySampleFunctionalTests.java | 34 ++++++ .../reader/GeneratingItemReaderTests.java | 31 +++++ .../writer/RetrySampleItemWriterTests.java | 35 ++++++ 21 files changed, 338 insertions(+), 14 deletions(-) rename {spring-batch-integration/src/test/java/org/springframework/batch/item => spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader}/AbstractItemReaderRecoverer.java (84%) create mode 100644 spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/GeneratingItemReader.java create mode 100644 spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriter.java create mode 100644 spring-batch-samples/src/main/resources/jobs/retrySample.xml create mode 100644 spring-batch-samples/src/test/java/org/springframework/batch/sample/RetrySampleFunctionalTests.java create mode 100644 spring-batch-samples/src/test/java/org/springframework/batch/sample/item/reader/GeneratingItemReaderTests.java create mode 100644 spring-batch-samples/src/test/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriterTests.java diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java index eeefe6f59..ab4af08fc 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java @@ -27,6 +27,7 @@ import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.stream.SimpleStreamManager; import org.springframework.batch.item.stream.StreamManager; import org.springframework.batch.repeat.exception.handler.ExceptionHandler; +import org.springframework.batch.retry.RetryPolicy; import org.springframework.beans.factory.InitializingBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.util.Assert; @@ -42,6 +43,8 @@ public abstract class AbstractStep extends StepSupport implements InitializingBe private int skipLimit = 0; private ExceptionHandler exceptionHandler; + + private RetryPolicy retryPolicy; private JobRepository jobRepository; @@ -71,6 +74,22 @@ public abstract class AbstractStep extends StepSupport implements InitializingBe super(name); } + /** + * Public getter for the {@link RetryPolicy}. + * @return the {@link RetryPolicy} + */ + public RetryPolicy getRetryPolicy() { + return retryPolicy; + } + + /** + * Public setter for the {@link RetryPolicy}. + * @param retryPolicy the {@link RetryPolicy} to set + */ + public void setRetryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + } + public ExceptionHandler getExceptionHandler() { return exceptionHandler; } @@ -177,6 +196,7 @@ public abstract class AbstractStep extends StepSupport implements InitializingBe executor.setItemWriter(itemWriter); executor.setItemRecoverer(itemRecoverer); executor.setRepository(jobRepository); + executor.setRetryPolicy(retryPolicy); executor.setStreamManager(manager); try { executor.afterPropertiesSet(); diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java index f309aa8ee..b01d28fc1 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java @@ -315,9 +315,6 @@ public class SimpleStepExecutor implements InitializingBean { try { - /* - * New transaction obtained, resynchronize TransactionSynchronization objects - */ result = processChunk(step, contribution); // TODO: check that stepExecution can diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/ReadFailureException.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/ReadFailureException.java index 06cdc1a51..88cacd442 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/ReadFailureException.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/ReadFailureException.java @@ -16,6 +16,8 @@ package org.springframework.batch.io.exception; +import org.springframework.batch.item.ItemReader; + /** * This exception indicates an error encountered while reading. It should generally * be thrown by classes that implement the {@link ItemReader} interface. diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/WriteFailureException.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/WriteFailureException.java index f31fdf216..93d6aefdb 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/WriteFailureException.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/exception/WriteFailureException.java @@ -16,6 +16,8 @@ package org.springframework.batch.io.exception; +import org.springframework.batch.item.ItemWriter; + /** * Exception thrown after encountering an error during a write. It should * generally be thrown by classes that implement the {@link ItemWriter} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/DefaultFlatFileItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/DefaultFlatFileItemReader.java index 1665a030b..1d82632c6 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/DefaultFlatFileItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/DefaultFlatFileItemReader.java @@ -23,8 +23,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.io.Skippable; import org.springframework.batch.io.file.separator.LineReader; -import org.springframework.batch.item.ItemStream; import org.springframework.batch.item.ExecutionAttributes; +import org.springframework.batch.item.ItemStream; import org.springframework.batch.item.exception.StreamException; /** diff --git a/spring-batch-integration/src/test/java/org/springframework/batch/item/AbstractItemReaderRecoverer.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/AbstractItemReaderRecoverer.java similarity index 84% rename from spring-batch-integration/src/test/java/org/springframework/batch/item/AbstractItemReaderRecoverer.java rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/AbstractItemReaderRecoverer.java index c93c1daf1..a1d66cdbd 100644 --- a/spring-batch-integration/src/test/java/org/springframework/batch/item/AbstractItemReaderRecoverer.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/AbstractItemReaderRecoverer.java @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.batch.item; +package org.springframework.batch.item.reader; + +import org.springframework.batch.item.ItemRecoverer; +import org.springframework.batch.item.KeyedItemReader; -import org.springframework.batch.item.reader.AbstractItemReader; /** * @author Dave Syer diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/DelegatingItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/DelegatingItemReader.java index b307c69cd..653bb43fa 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/DelegatingItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/DelegatingItemReader.java @@ -17,9 +17,9 @@ package org.springframework.batch.item.reader; import org.springframework.batch.io.Skippable; +import org.springframework.batch.item.ExecutionAttributes; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemStream; -import org.springframework.batch.item.ExecutionAttributes; import org.springframework.batch.item.exception.StreamException; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/stream/ItemStreamAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/stream/ItemStreamAdapter.java index 71ed3d4e8..c4731916b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/stream/ItemStreamAdapter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/stream/ItemStreamAdapter.java @@ -15,8 +15,8 @@ */ package org.springframework.batch.item.stream; -import org.springframework.batch.item.ItemStream; import org.springframework.batch.item.ExecutionAttributes; +import org.springframework.batch.item.ItemStream; import org.springframework.batch.item.exception.StreamException; /** diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/callback/NestedRepeatCallback.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/callback/NestedRepeatCallback.java index a0883bcb8..7c988bd52 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/callback/NestedRepeatCallback.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/callback/NestedRepeatCallback.java @@ -16,10 +16,10 @@ package org.springframework.batch.repeat.callback; +import org.springframework.batch.repeat.ExitStatus; import org.springframework.batch.repeat.RepeatCallback; import org.springframework.batch.repeat.RepeatContext; import org.springframework.batch.repeat.RepeatOperations; -import org.springframework.batch.repeat.ExitStatus; /** * Callback that delegates to another callback, via a {@link RepeatOperations} instance. diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompletionPolicySupport.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompletionPolicySupport.java index 246cc2d97..600796db1 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompletionPolicySupport.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompletionPolicySupport.java @@ -16,9 +16,9 @@ package org.springframework.batch.repeat.policy; +import org.springframework.batch.repeat.CompletionPolicy; import org.springframework.batch.repeat.ExitStatus; import org.springframework.batch.repeat.RepeatContext; -import org.springframework.batch.repeat.CompletionPolicy; import org.springframework.batch.repeat.context.RepeatContextSupport; /** diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompositeCompletionPolicy.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompositeCompletionPolicy.java index bb76fd702..78508ee1c 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompositeCompletionPolicy.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/CompositeCompletionPolicy.java @@ -19,9 +19,9 @@ package org.springframework.batch.repeat.policy; import java.util.ArrayList; import java.util.List; +import org.springframework.batch.repeat.CompletionPolicy; import org.springframework.batch.repeat.ExitStatus; import org.springframework.batch.repeat.RepeatContext; -import org.springframework.batch.repeat.CompletionPolicy; import org.springframework.batch.repeat.context.RepeatContextSupport; /** diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/DefaultResultCompletionPolicy.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/DefaultResultCompletionPolicy.java index e3c05afd3..2530aa73e 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/DefaultResultCompletionPolicy.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/policy/DefaultResultCompletionPolicy.java @@ -16,9 +16,9 @@ package org.springframework.batch.repeat.policy; -import org.springframework.batch.repeat.RepeatContext; import org.springframework.batch.repeat.CompletionPolicy; import org.springframework.batch.repeat.ExitStatus; +import org.springframework.batch.repeat.RepeatContext; /** * Very simple {@link CompletionPolicy} that bases its decision on the result of diff --git a/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java b/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java index df009abda..4b93c24cf 100644 --- a/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java +++ b/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java @@ -21,8 +21,8 @@ import java.util.List; import javax.sql.DataSource; -import org.springframework.batch.item.AbstractItemReaderRecoverer; import org.springframework.batch.item.KeyedItemReader; +import org.springframework.batch.item.reader.AbstractItemReaderRecoverer; import org.springframework.batch.item.writer.AbstractItemWriter; import org.springframework.batch.repeat.ExitStatus; import org.springframework.batch.repeat.RepeatCallback; diff --git a/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java b/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java index e73259468..1d1405530 100644 --- a/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java +++ b/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java @@ -21,8 +21,8 @@ import java.util.List; import javax.sql.DataSource; -import org.springframework.batch.item.AbstractItemReaderRecoverer; import org.springframework.batch.item.KeyedItemReader; +import org.springframework.batch.item.reader.AbstractItemReaderRecoverer; import org.springframework.batch.item.writer.AbstractItemWriter; import org.springframework.batch.retry.callback.ItemReaderRetryCallback; import org.springframework.batch.retry.policy.ItemReaderRetryPolicy; diff --git a/spring-batch-samples/.springBeans b/spring-batch-samples/.springBeans index a8e02af8e..87f6f6bba 100644 --- a/spring-batch-samples/.springBeans +++ b/spring-batch-samples/.springBeans @@ -31,6 +31,7 @@ src/main/resources/jobs/delegatingJob.xml src/main/resources/jobs/parallelJob.xml src/main/resources/jobs/rollbackJob.xml + src/main/resources/jobs/retrySample.xml @@ -235,5 +236,16 @@ src/main/resources/jobs/tradeJobIo.xml + + + true + false + + src/main/resources/jobs/retrySample.xml + src/main/resources/simple-container-definition.xml + src/main/resources/data-source-context.xml + src/main/resources/data-source-context-init.xml + + diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/GeneratingItemReader.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/GeneratingItemReader.java new file mode 100644 index 000000000..011d9435d --- /dev/null +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/GeneratingItemReader.java @@ -0,0 +1,109 @@ +package org.springframework.batch.sample.item.reader; + +import java.math.BigDecimal; + +import org.springframework.batch.item.ExecutionAttributes; +import org.springframework.batch.item.ItemStream; +import org.springframework.batch.item.exception.MarkFailedException; +import org.springframework.batch.item.exception.ResetFailedException; +import org.springframework.batch.item.exception.StreamException; +import org.springframework.batch.item.reader.AbstractItemReaderRecoverer; +import org.springframework.batch.sample.domain.Trade; + +/** + * Generates configurable number of {@link Trade} items. + * + * @author Robert Kasanicky + */ +public class GeneratingItemReader extends AbstractItemReaderRecoverer implements ItemStream { + + private int limit = 1; + + private int counter = 0; + + private int marked; + + public Object read() throws Exception { + if (counter < limit) { + counter++; + return new Trade( + "isin" + counter, + counter, + new BigDecimal(counter), + "customer" + counter); + } + return null; + } + + /** + * @param limit number of items that will be generated + * (null returned on consecutive calls). + */ + public void setLimit(int limit) { + this.limit = limit; + } + + public int getCounter() { + return counter; + } + + public int getLimit() { + return limit; + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ItemRecoverer#recover(java.lang.Object, java.lang.Throwable) + */ + public boolean recover(Object data, Throwable cause) { + return false; + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ItemStream#close() + */ + public void close() throws StreamException { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ItemStream#isMarkSupported() + */ + public boolean isMarkSupported() { + return true; + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ItemStream#mark() + */ + public void mark() throws MarkFailedException { + this.marked = this.counter; + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ItemStream#open() + */ + public void open() throws StreamException { + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ItemStream#reset() + */ + public void reset() throws ResetFailedException { + this.counter = this.marked; + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ItemStream#restoreFrom(org.springframework.batch.item.ExecutionAttributes) + */ + public void restoreFrom(ExecutionAttributes context) { + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.ExecutionAttributesProvider#getExecutionAttributes() + */ + public ExecutionAttributes getExecutionAttributes() { + return new ExecutionAttributes(); + } + +} diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriter.java new file mode 100644 index 000000000..11e1421ad --- /dev/null +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriter.java @@ -0,0 +1,29 @@ +package org.springframework.batch.sample.item.writer; + +import org.springframework.batch.item.ItemWriter; + +/** + * Simulates temporary output trouble - requires to + * retry 3 times to pass successfully. + * + * @author Robert Kasanicky + */ +public class RetrySampleItemWriter implements ItemWriter { + + private int counter = 0; + + public void write(Object data) throws Exception { + counter++; + if (counter == 2 || counter == 3) { + throw new RuntimeException("Temporary error"); + } + } + + /** + * @return number of times {@link #process(Object)} method was called. + */ + public int getCounter() { + return counter; + } + +} diff --git a/spring-batch-samples/src/main/resources/jobs/retrySample.xml b/spring-batch-samples/src/main/resources/jobs/retrySample.xml new file mode 100644 index 000000000..9fa6c00c9 --- /dev/null +++ b/spring-batch-samples/src/main/resources/jobs/retrySample.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/sample/RetrySampleFunctionalTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/sample/RetrySampleFunctionalTests.java new file mode 100644 index 000000000..9ebd8a4fd --- /dev/null +++ b/spring-batch-samples/src/test/java/org/springframework/batch/sample/RetrySampleFunctionalTests.java @@ -0,0 +1,34 @@ +package org.springframework.batch.sample; + +import org.springframework.batch.sample.item.reader.GeneratingItemReader; +import org.springframework.batch.sample.item.writer.RetrySampleItemWriter; + +/** + * Checks that expected number of items have been processed. + * + * @author Robert Kasanicky + */ +public class RetrySampleFunctionalTests extends AbstractValidatingBatchLauncherTests { + + private GeneratingItemReader itemGenerator; + + private RetrySampleItemWriter itemProcessor; + + protected String[] getConfigLocations() { + return new String[] {"jobs/retrySample.xml"}; + } + + protected void validatePostConditions() throws Exception { + //items processed = items read + 2 exceptions + assertEquals(itemGenerator.getLimit()+2, itemProcessor.getCounter()); + } + + public void setItemGenerator(GeneratingItemReader itemGenerator) { + this.itemGenerator = itemGenerator; + } + + public void setItemProcessor(RetrySampleItemWriter itemProcessor) { + this.itemProcessor = itemProcessor; + } + +} diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/sample/item/reader/GeneratingItemReaderTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/sample/item/reader/GeneratingItemReaderTests.java new file mode 100644 index 000000000..d21c3fbbe --- /dev/null +++ b/spring-batch-samples/src/test/java/org/springframework/batch/sample/item/reader/GeneratingItemReaderTests.java @@ -0,0 +1,31 @@ +package org.springframework.batch.sample.item.reader; + +import junit.framework.TestCase; + +/** + * Tests for {@link GeneratingItemReader}. + * + * @author Robert Kasanicky + */ +public class GeneratingItemReaderTests extends TestCase { + + private GeneratingItemReader reader = new GeneratingItemReader(); + + /** + * Generates a given number of not-null records, + * consecutive calls return null. + */ + public void testRead() throws Exception { + int counter = 0; + int limit = 10; + reader.setLimit(limit); + + while (reader.read() != null) { + counter++; + } + + assertEquals(null, reader.read()); + assertEquals(limit, counter); + assertEquals(counter, reader.getCounter()); + } +} diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriterTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriterTests.java new file mode 100644 index 000000000..bd2e74d6d --- /dev/null +++ b/spring-batch-samples/src/test/java/org/springframework/batch/sample/item/writer/RetrySampleItemWriterTests.java @@ -0,0 +1,35 @@ +package org.springframework.batch.sample.item.writer; + +import junit.framework.TestCase; + +/** + * Tests for {@link RetrySampleItemWriter}. + * + * @author Robert Kasanicky + */ +public class RetrySampleItemWriterTests extends TestCase { + + private RetrySampleItemWriter processor = new RetrySampleItemWriter(); + + /** + * Processing throws exception on 2nd and 3rd call. + */ + public void testProcess() throws Exception { + Object item = null; + processor.write(item); + + for (int i = 0; i < 2; i++) { + try { + processor.write(item); + fail(); + } + catch (RuntimeException e) { + // expected + } + } + + processor.write(item); + + assertEquals(4, processor.getCounter()); + } +}