IN PROGRESS - issue BATCH-572: Retryable exceptions cannot be skippable

Modified StatefulRetryStepFactoryBean to use skip listener instead of ItemRecoverer.
This commit is contained in:
dsyer
2008-05-22 16:12:08 +00:00
parent 5b0ed9e728
commit 42d672d401
6 changed files with 202 additions and 134 deletions

View File

@@ -22,12 +22,16 @@ import java.util.List;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepListener;
import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.listener.SkipListenerSupport;
import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
import org.springframework.batch.core.repository.dao.MapStepExecutionDao;
@@ -35,9 +39,9 @@ import org.springframework.batch.core.repository.support.SimpleJobRepository;
import org.springframework.batch.core.step.AbstractStep;
import org.springframework.batch.item.AbstractItemWriter;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.retry.RetryException;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -48,13 +52,15 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
*/
public class StatefulRetryStepFactoryBeanTests extends TestCase {
protected final Log logger = LogFactory.getLog(getClass());
private StatefulRetryStepFactoryBean factory = new StatefulRetryStepFactoryBean();
private List recovered = new ArrayList();
private List processed = new ArrayList();
int count = 0;
int count = 0;
private SimpleJobRepository repository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
new MapStepExecutionDao());
@@ -72,11 +78,11 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
MapJobInstanceDao.clear();
MapJobExecutionDao.clear();
MapStepExecutionDao.clear();
factory.setBeanName("step");
factory.setItemReader(new ListItemReader(new ArrayList()));
@@ -86,10 +92,11 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
JobSupport job = new JobSupport("jobName");
job.setRestartable(true);
JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique").toJobParameters();
JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique")
.toJobParameters();
jobExecution = repository.createJobExecution(job, jobParameters);
jobExecution.setEndTime(new Date());
}
public void testType() throws Exception {
@@ -100,14 +107,7 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
assertTrue(factory.getObject() instanceof Step);
}
public void testRecovery() throws Exception {
factory.setItemRecoverer(new ItemRecoverer() {
public Object recover(Object item, Throwable cause) {
recovered.add(item);
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
return item;
}
});
public void testSuccessfulRetry() throws Exception {
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(new String[] { "a", "b", "c" }));
ItemReader provider = new ListItemReader(items) {
@@ -126,14 +126,15 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
step.execute(stepExecution);
assertEquals(0, stepExecution.getSkipCount());
// b is processed twice, plus 1, plus c, plus the null at end
assertEquals(5, count);
}
public void testSkipAndRetry() throws Exception {
factory.setSkippableExceptionClasses(new Class[] {Exception.class});
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
factory.setSkipLimit(2);
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
@@ -153,46 +154,54 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
step.execute(stepExecution);
assertEquals(2, stepExecution.getSkipCount());
// b is processed once and skipped, plus 1, plus c, plus the null at end
assertEquals(7, count);
}
//The following test fails due to current expected behavior of retry
//that will be addressed in 1.1
// public void testSkipAndRetryWithWriteFailure() throws Exception {
//
// factory.setSkippableExceptionClasses(new Class[] {RetryException.class});
// factory.setSkipLimit(2);
// List items = TransactionAwareProxyFactory.createTransactionalList();
// items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
// ItemReader provider = new ListItemReader(items) {
// public Object read() {
// Object item = super.read();
// System.out.print("Read Called! Item: [" + item + "]");
// count++;
// return item;
// }
// };
//
// ItemWriter itemWriter = new AbstractItemWriter(){
// public void write(Object item) throws Exception {
// System.out.print("Write Called! Item: [" + item + "]");
// if ("b".equals(item) || "d".equals(item)) {
// throw new RuntimeException("Read error - planned but skippable.");
// }
// }};
// factory.setItemReader(provider);
// factory.setItemWriter(itemWriter);
// factory.setRetryLimit(5);
// factory.setRetryableExceptionClasses(new Class[]{RuntimeException.class});
// AbstractStep step = (AbstractStep) factory.getObject();
// step.setName("mytest");
// StepExecution stepExecution = new StepExecution(step, jobExecution);
// step.execute(stepExecution);
//
// assertEquals(2, stepExecution.getSkipCount());
// assertEquals(9, count);
// }
public void testSkipAndRetryWithWriteFailure() throws Exception {
factory.setSkippableExceptionClasses(new Class[] { RetryException.class });
factory.setListeners(new StepListener[] { new SkipListenerSupport() {
public void onSkipInWrite(Object item, Throwable t) {
recovered.add(item);
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
}
} });
factory.setSkipLimit(2);
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
ItemReader provider = new ListItemReader(items) {
public Object read() {
Object item = super.read();
logger.debug("Read Called! Item: [" + item + "]");
count++;
return item;
}
};
ItemWriter itemWriter = new AbstractItemWriter() {
public void write(Object item) throws Exception {
logger.debug("Write Called! Item: [" + item + "]");
if ("b".equals(item) || "d".equals(item)) {
throw new RuntimeException("Read error - planned but skippable.");
}
}
};
factory.setItemReader(provider);
factory.setItemWriter(itemWriter);
factory.setRetryLimit(5);
factory.setRetryableExceptionClasses(new Class[] { RuntimeException.class });
AbstractStep step = (AbstractStep) factory.getObject();
step.setName("mytest");
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
step.execute(stepExecution);
assertEquals(2, recovered.size());
assertEquals(2, stepExecution.getSkipCount());
assertEquals(2, stepExecution.getWriteSkipCount().intValue());
// each item once, plus 5 failed retries each for b and d, plus the null terminator
assertEquals(17, count);
}
}