Merging changes from branch...

BATCH-1323: Modify skip/retry/no-rollback exception class configurations to allow for include/exclude
BATCH-1339: Move task-executor attribute up from <chunk/> to <tasklet/>
BATCH-1348: Allow inlining of reader/writer/processor into <chunk/>
BATCH-1357: Allow empty <listeners/>, <retry-listeners/>, and <streams/> lists
BATCH-1358: Move InfiniteLoopIncrementer into core, and rename it to RunIdIncrementer
BATCH-1367: Syntactic sugar for Item*Adapter in namespace
BATCH-1375: Give CompositeItemProcessor's and CompositeItemWriter's property the same name (delegates)
This commit is contained in:
dhgarrette
2009-08-23 15:17:20 +00:00
parent 9e8bdba83d
commit 8146e55503
72 changed files with 1168 additions and 902 deletions

View File

@@ -16,12 +16,12 @@
package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import org.springframework.batch.core.Step;
@@ -48,38 +48,30 @@ public class ChunkElementParserTests {
@Test
public void testInheritSkippable() throws Exception {
Collection<Class<?>> skippable = getExceptionClasses("s1", "skippable",
Map<Class<? extends Throwable>, Boolean> skippable = getExceptionClasses("s1",
chunkElementParentAttributeParserTestsContext);
assertEquals(3, skippable.size());
boolean e = false;
boolean f = false;
for (Class<?> cls : skippable) {
if (cls.equals(NullPointerException.class)) {
e = true;
}
else if (cls.equals(ArithmeticException.class)) {
f = true;
}
}
assertTrue(e);
assertTrue(f);
assertEquals(11, skippable.size());
containsClassified(skippable, NullPointerException.class, true);
containsClassified(skippable, ArithmeticException.class, true);
containsClassified(skippable, CannotAcquireLockException.class, false);
containsClassified(skippable, DeadlockLoserDataAccessException.class, false);
}
@Test
public void testInheritFatal() throws Exception {
Collection<Class<?>> fatal = getExceptionClasses("s1", "fatal", chunkElementParentAttributeParserTestsContext);
boolean a = false;
boolean b = false;
for (Class<?> cls : fatal) {
if (cls.equals(CannotAcquireLockException.class)) {
a = true;
}
else if (cls.equals(DeadlockLoserDataAccessException.class)) {
b = true;
}
}
assertTrue(a);
assertTrue(b);
public void testInheritSkippableWithNoMerge() throws Exception {
Map<Class<? extends Throwable>, Boolean> skippable = getExceptionClasses("s2",
chunkElementParentAttributeParserTestsContext);
assertEquals(9, skippable.size());
containsClassified(skippable, NullPointerException.class, true);
assertFalse(skippable.containsKey(ArithmeticException.class));
containsClassified(skippable, CannotAcquireLockException.class, false);
assertFalse(skippable.containsKey(DeadlockLoserDataAccessException.class));
}
private void containsClassified(Map<Class<? extends Throwable>, Boolean> classified,
Class<? extends Throwable> cls, boolean include) {
assertTrue(classified.containsKey(cls));
assertEquals(include, classified.get(cls));
}
@Test
@@ -114,37 +106,6 @@ public class ChunkElementParserTests {
assertTrue(h);
}
@Test
public void testInheritSkippableWithNoMerge() throws Exception {
Collection<Class<?>> skippable = getExceptionClasses("s2", "skippable",
chunkElementParentAttributeParserTestsContext);
assertEquals(2, skippable.size());
boolean e = false;
for (Class<?> cls : skippable) {
if (cls.equals(NullPointerException.class)) {
e = true;
}
}
assertTrue(e);
}
@Test
public void testInheritFatalWithNoMerge() throws Exception {
Collection<Class<?>> fatal = getExceptionClasses("s2", "fatal", chunkElementParentAttributeParserTestsContext);
boolean a = false;
boolean b = false;
for (Class<?> cls : fatal) {
if (cls.equals(CannotAcquireLockException.class)) {
a = true;
}
else if (cls.equals(DeadlockLoserDataAccessException.class)) {
b = true;
}
}
assertTrue(a);
assertTrue(!b);
}
@Test
public void testInheritStreamsWithNoMerge() throws Exception {
Collection<ItemStream> streams = getStreams("s2", chunkElementParentAttributeParserTestsContext);
@@ -173,7 +134,8 @@ public class ChunkElementParserTests {
}
@SuppressWarnings("unchecked")
private Set<Class<?>> getExceptionClasses(String stepName, String type, ApplicationContext ctx) throws Exception {
private Map<Class<? extends Throwable>, Boolean> getExceptionClasses(String stepName, ApplicationContext ctx)
throws Exception {
Map<String, Step> beans = ctx.getBeansOfType(Step.class);
assertTrue(beans.containsKey(stepName));
Object step = ctx.getBean(stepName);
@@ -182,10 +144,8 @@ public class ChunkElementParserTests {
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
Object skipPolicy = ReflectionTestUtils.getField(chunkProvider, "skipPolicy");
Object classifier = ReflectionTestUtils.getField(skipPolicy, type + "ExceptionClassifier");
Map<Class<?>, ?> classified = (Map<Class<?>, ?>) ReflectionTestUtils.getField(classifier, "classified");
return classified.keySet();
Object classifier = ReflectionTestUtils.getField(skipPolicy, "skippableExceptionClassifier");
return (Map<Class<? extends Throwable>, Boolean>) ReflectionTestUtils.getField(classifier, "classified");
}
@SuppressWarnings("unchecked")

View File

@@ -0,0 +1,20 @@
package org.springframework.batch.core.configuration.xml;
/**
* @author Dan Garrette
* @since 2.1
*/
public class DummyItemHandlerAdapter {
public Object dummyRead() {
return null;
}
public Object dummyProcess(Object o) {
return null;
}
public void dummyWrite(Object o) {
}
}

View File

@@ -0,0 +1,67 @@
package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.batch.item.adapter.ItemProcessorAdapter;
import org.springframework.batch.item.adapter.ItemReaderAdapter;
import org.springframework.batch.item.adapter.ItemWriterAdapter;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.util.ReflectionTestUtils;
/**
* @author Dan Garrette
* @since 2.1
*/
public class InlineItemHandlerParserTests {
private ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests-context.xml");
@Test
public void testInlineHandlers() throws Exception {
Object step = ctx.getBean("inlineHandlers");
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
Object reader = ReflectionTestUtils.getField(chunkProvider, "itemReader");
Object chunkProcessor = ReflectionTestUtils.getField(tasklet, "chunkProcessor");
Object processor = ReflectionTestUtils.getField(chunkProcessor, "itemProcessor");
Object writer = ReflectionTestUtils.getField(chunkProcessor, "itemWriter");
assertTrue(reader instanceof TestReader);
assertTrue(processor instanceof TestProcessor);
assertTrue(writer instanceof TestWriter);
}
@Test
public void testInlineAdapters() throws Exception {
Object step = ctx.getBean("inlineAdapters");
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
Object reader = ReflectionTestUtils.getField(chunkProvider, "itemReader");
Object chunkProcessor = ReflectionTestUtils.getField(tasklet, "chunkProcessor");
Object processor = ReflectionTestUtils.getField(chunkProcessor, "itemProcessor");
Object writer = ReflectionTestUtils.getField(chunkProcessor, "itemWriter");
assertTrue(reader instanceof ItemReaderAdapter<?>);
Object readerObject = ReflectionTestUtils.getField(reader, "targetObject");
assertTrue(readerObject instanceof DummyItemHandlerAdapter);
Object readerMethod = ReflectionTestUtils.getField(reader, "targetMethod");
assertEquals("dummyRead", readerMethod);
assertTrue(processor instanceof ItemProcessorAdapter<?, ?>);
Object processorObject = ReflectionTestUtils.getField(processor, "targetObject");
assertTrue(processorObject instanceof DummyItemHandlerAdapter);
Object processorMethod = ReflectionTestUtils.getField(processor, "targetMethod");
assertEquals("dummyProcess", processorMethod);
assertTrue(writer instanceof ItemWriterAdapter<?>);
Object writerObject = ReflectionTestUtils.getField(writer, "targetObject");
assertTrue(writerObject instanceof DummyItemHandlerAdapter);
Object writerMethod = ReflectionTestUtils.getField(writer, "targetMethod");
assertEquals("dummyWrite", writerMethod);
}
}

View File

@@ -184,8 +184,7 @@ public class JobParserTests {
@Test
public void testListenerClearingJob() throws Exception {
// TODO BATCH-1357:
// assertEquals(0, getListeners("listenerClearingJob", jobParserParentAttributeTestsCtx).size());
assertEquals(0, getListeners("listenerClearingJob", jobParserParentAttributeTestsCtx).size());
}
}

View File

@@ -19,10 +19,10 @@ package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.HashMap;
import org.junit.Test;
import org.springframework.batch.core.StepListener;
import org.springframework.batch.core.configuration.xml.StepParserStepFactoryBean;
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
import org.springframework.batch.core.step.JobRepositorySupport;
import org.springframework.batch.core.step.item.ChunkOrientedTasklet;
@@ -147,9 +147,8 @@ public class StepParserStepFactoryBeanTests {
fb.setRetryLimit(5);
fb.setSkipLimit(100);
fb.setRetryListeners(new RetryListenerSupport());
fb.setSkippableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
fb.setRetryableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
fb.setFatalExceptionClasses(new ArrayList<Class<? extends Throwable>>());
fb.setSkippableExceptionClasses(new HashMap<Class<? extends Throwable>, Boolean>());
fb.setRetryableExceptionClasses(new HashMap<Class<? extends Throwable>, Boolean>());
Object step = fb.getObject();
assertTrue(step instanceof TaskletStep);
@@ -204,9 +203,8 @@ public class StepParserStepFactoryBeanTests {
fb.setRetryLimit(5);
fb.setSkipLimit(100);
fb.setRetryListeners(new RetryListenerSupport());
fb.setSkippableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
fb.setRetryableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
fb.setFatalExceptionClasses(new ArrayList<Class<? extends Throwable>>());
fb.setSkippableExceptionClasses(new HashMap<Class<? extends Throwable>, Boolean>());
fb.setRetryableExceptionClasses(new HashMap<Class<? extends Throwable>, Boolean>());
Object step = fb.getObject();
assertTrue(step instanceof TaskletStep);

View File

@@ -21,8 +21,10 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -83,8 +85,7 @@ public class StepParserTests {
Map<String, StepParserStepFactoryBean> beans = ctx.getBeansOfType(StepParserStepFactoryBean.class);
String factoryName = (String) beans.keySet().toArray()[0];
@SuppressWarnings("unchecked")
StepParserStepFactoryBean<Object, Object> factory = (StepParserStepFactoryBean<Object, Object>) beans
.get(factoryName);
StepParserStepFactoryBean<Object, Object> factory = beans.get(factoryName);
TaskletStep bean = (TaskletStep) factory.getObject();
assertEquals("wrong start-limit:", 25, bean.getStartLimit());
}
@@ -420,11 +421,14 @@ public class StepParserTests {
public void testStepWithListsMerge() throws Exception {
ApplicationContext ctx = stepParserParentAttributeTestsCtx;
List<Class<? extends Exception>> skippable = Arrays.asList(SkippableRuntimeException.class,
SkippableException.class);
Collection<Class<? extends Exception>> fatal = Arrays.asList(FatalRuntimeException.class, FatalException.class);
Collection<Class<? extends Exception>> retryable = Arrays.asList(DeadlockLoserDataAccessException.class,
FatalException.class);
Map<Class<? extends Throwable>, Boolean> skippable = new HashMap<Class<? extends Throwable>, Boolean>();
skippable.put(SkippableRuntimeException.class, true);
skippable.put(SkippableException.class, true);
skippable.put(FatalRuntimeException.class, false);
skippable.put(FatalException.class, false);
Map<Class<? extends Throwable>, Boolean> retryable = new HashMap<Class<? extends Throwable>, Boolean>();
retryable.put(DeadlockLoserDataAccessException.class, true);
retryable.put(FatalException.class, true);
List<Class<? extends ItemStream>> streams = Arrays.asList(CompositeItemStream.class, TestReader.class);
List<Class<? extends RetryListener>> retryListeners = Arrays.asList(RetryListenerSupport.class,
DummyRetryListener.class);
@@ -435,17 +439,15 @@ public class StepParserTests {
StepParserStepFactoryBean<?, ?> fb = (StepParserStepFactoryBean<?, ?>) ctx.getBean("&stepWithListsMerge");
Collection<Class<? extends Throwable>> skippableFound = getExceptionList(fb, "skippableExceptionClasses");
Collection<Class<? extends Throwable>> fatalFound = getExceptionList(fb, "fatalExceptionClasses");
Collection<Class<? extends Throwable>> retryableFound = getExceptionList(fb, "retryableExceptionClasses");
Map<Class<? extends Throwable>, Boolean> skippableFound = getExceptionMap(fb, "skippableExceptionClasses");
Map<Class<? extends Throwable>, Boolean> retryableFound = getExceptionMap(fb, "retryableExceptionClasses");
ItemStream[] streamsFound = (ItemStream[]) ReflectionTestUtils.getField(fb, "streams");
RetryListener[] retryListenersFound = (RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners");
StepListener[] stepListenersFound = (StepListener[]) ReflectionTestUtils.getField(fb, "listeners");
Collection<Class<? extends Throwable>> noRollbackFound = getExceptionList(fb, "noRollbackExceptionClasses");
assertSameCollections(skippable, skippableFound);
assertSameCollections(fatal, fatalFound);
assertSameCollections(retryable, retryableFound);
assertSameMaps(skippable, skippableFound);
assertSameMaps(retryable, retryableFound);
assertSameCollections(streams, toClassCollection(streamsFound));
assertSameCollections(retryListeners, toClassCollection(retryListenersFound));
assertSameCollections(stepListeners, toClassCollection(stepListenersFound));
@@ -457,9 +459,11 @@ public class StepParserTests {
public void testStepWithListsNoMerge() throws Exception {
ApplicationContext ctx = stepParserParentAttributeTestsCtx;
List<Class<SkippableException>> skippable = Arrays.asList(SkippableException.class);
List<Class<FatalException>> fatal = Arrays.asList(FatalException.class);
List<Class<FatalException>> retryable = Arrays.asList(FatalException.class);
Map<Class<? extends Throwable>, Boolean> skippable = new HashMap<Class<? extends Throwable>, Boolean>();
skippable.put(SkippableException.class, true);
skippable.put(FatalException.class, false);
Map<Class<? extends Throwable>, Boolean> retryable = new HashMap<Class<? extends Throwable>, Boolean>();
retryable.put(FatalException.class, true);
List<Class<CompositeItemStream>> streams = Arrays.asList(CompositeItemStream.class);
List<Class<DummyRetryListener>> retryListeners = Arrays.asList(DummyRetryListener.class);
List<Class<CompositeStepExecutionListener>> stepListeners = Arrays.asList(CompositeStepExecutionListener.class);
@@ -467,17 +471,15 @@ public class StepParserTests {
StepParserStepFactoryBean<?, ?> fb = (StepParserStepFactoryBean<?, ?>) ctx.getBean("&stepWithListsNoMerge");
Collection<Class<? extends Throwable>> skippableFound = getExceptionList(fb, "skippableExceptionClasses");
Collection<Class<? extends Throwable>> fatalFound = getExceptionList(fb, "fatalExceptionClasses");
Collection<Class<? extends Throwable>> retryableFound = getExceptionList(fb, "retryableExceptionClasses");
Map<Class<? extends Throwable>, Boolean> skippableFound = getExceptionMap(fb, "skippableExceptionClasses");
Map<Class<? extends Throwable>, Boolean> retryableFound = getExceptionMap(fb, "retryableExceptionClasses");
ItemStream[] streamsFound = (ItemStream[]) ReflectionTestUtils.getField(fb, "streams");
RetryListener[] retryListenersFound = (RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners");
StepListener[] stepListenersFound = (StepListener[]) ReflectionTestUtils.getField(fb, "listeners");
Collection<Class<? extends Throwable>> noRollbackFound = getExceptionList(fb, "noRollbackExceptionClasses");
assertSameCollections(skippable, skippableFound);
assertSameCollections(fatal, fatalFound);
assertSameCollections(retryable, retryableFound);
assertSameMaps(skippable, skippableFound);
assertSameMaps(retryable, retryableFound);
assertSameCollections(streams, toClassCollection(streamsFound));
assertSameCollections(retryListeners, toClassCollection(retryListenersFound));
assertSameCollections(stepListeners, toClassCollection(stepListenersFound));
@@ -491,15 +493,11 @@ public class StepParserTests {
StepParserStepFactoryBean<?, ?> fb = (StepParserStepFactoryBean<?, ?>) ctx
.getBean("&stepWithListsOverrideWithEmpty");
assertEquals(0, getExceptionList(fb, "skippableExceptionClasses").size());
assertEquals(0, getExceptionList(fb, "fatalExceptionClasses").size());
assertEquals(0, getExceptionList(fb, "retryableExceptionClasses").size());
// TODO BATCH-1357:
// assertEquals(0, ((ItemStream[]) ReflectionTestUtils.getField(fb, "streams")).length);
// TODO BATCH-1357:
// assertEquals(0, ((RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners")).length);
// TODO BATCH-1357:
// assertEquals(0, ((StepListener[]) ReflectionTestUtils.getField(fb, "listeners")).length);
assertEquals(0, getExceptionMap(fb, "skippableExceptionClasses").size());
assertEquals(0, getExceptionMap(fb, "retryableExceptionClasses").size());
assertEquals(0, ((ItemStream[]) ReflectionTestUtils.getField(fb, "streams")).length);
assertEquals(0, ((RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners")).length);
assertEquals(0, ((StepListener[]) ReflectionTestUtils.getField(fb, "listeners")).length);
assertEquals(0, getExceptionList(fb, "noRollbackExceptionClasses").size());
}
@@ -509,11 +507,25 @@ public class StepParserTests {
return (Collection<Class<? extends Throwable>>) ReflectionTestUtils.getField(fb, propertyName);
}
@SuppressWarnings("unchecked")
private Map<Class<? extends Throwable>, Boolean> getExceptionMap(StepParserStepFactoryBean<?, ?> fb,
String propertyName) {
return (Map<Class<? extends Throwable>, Boolean>) ReflectionTestUtils.getField(fb, propertyName);
}
private <T, S extends T> void assertSameCollections(Collection<S> expected, Collection<T> actual) {
assertEquals(expected.size(), actual.size());
assertTrue(expected.containsAll(actual));
}
private <T, S> void assertSameMaps(Map<T, S> expected, Map<T, S> actual) {
assertEquals(expected.size(), actual.size());
for (Entry<T, S> e : expected.entrySet()) {
assertTrue(actual.containsKey(e.getKey()));
assertEquals(e.getValue(), actual.get(e.getKey()));
}
}
private <T> Collection<Class<? extends T>> toClassCollection(T[] in) throws Exception {
return toClassCollection(Arrays.asList(in));
}

View File

@@ -143,7 +143,7 @@ public class DefaultJobParametersConverterTests extends TestCase {
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
assertNotNull(props);
assertEquals((double) 1.0, props.getDouble("value"), Double.MIN_VALUE);
assertEquals(1.0, props.getDouble("value"), Double.MIN_VALUE);
}
public void testGetProperties() throws Exception {

View File

@@ -467,7 +467,7 @@ public class SimpleJobTests {
private void checkRepository(BatchStatus status, ExitStatus exitStatus) {
assertEquals(jobInstance, jobInstanceDao.getJobInstance(job.getName(), jobParameters));
// because map dao stores in memory, it can be checked directly
JobExecution jobExecution = (JobExecution) jobExecutionDao.findJobExecutions(jobInstance).get(0);
JobExecution jobExecution = jobExecutionDao.findJobExecutions(jobInstance).get(0);
assertEquals(jobInstance.getId(), jobExecution.getJobId());
assertEquals(status, jobExecution.getStatus());
if (exitStatus != null) {

View File

@@ -548,7 +548,7 @@ public class FlowJobTests {
private void checkRepository(BatchStatus status, ExitStatus exitStatus) {
// because map dao stores in memory, it can be checked directly
JobInstance jobInstance = jobExecution.getJobInstance();
JobExecution other = (JobExecution) jobExecutionDao.findJobExecutions(jobInstance).get(0);
JobExecution other = jobExecutionDao.findJobExecutions(jobInstance).get(0);
assertEquals(jobInstance.getId(), other.getJobId());
assertEquals(status, other.getStatus());
if (exitStatus != null) {

View File

@@ -272,8 +272,7 @@ public class StepListenerFactoryBeanTests {
public void testNonListener() throws Exception {
Object delegate = new Object();
factoryBean.setDelegate(delegate);
StepListener listener = (StepListener) factoryBean.getObject();
assertTrue(listener instanceof StepListener);
assertTrue(factoryBean.getObject() instanceof StepListener);
}
@Test

View File

@@ -6,6 +6,7 @@ import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
@@ -38,7 +39,8 @@ public class BatchRetryTemplateTests {
String result = template.execute(new RetryCallback<String>() {
public String doWithRetry(RetryContext context) throws Exception {
assertTrue("Wrong context type: " + context.getClass().getSimpleName(), context.getClass().getSimpleName().contains("Batch"));
assertTrue("Wrong context type: " + context.getClass().getSimpleName(), context.getClass()
.getSimpleName().contains("Batch"));
return "2";
}
}, Arrays.<RetryState> asList(new DefaultRetryState("1")));
@@ -80,7 +82,8 @@ public class BatchRetryTemplateTests {
public void testExhaustedRetry() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(1));
template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)));
RetryCallback<String[]> retryCallback = new RetryCallback<String[]>() {
public String[] doWithRetry(RetryContext context) throws Exception {
@@ -108,7 +111,8 @@ public class BatchRetryTemplateTests {
public void testExhaustedRetryAfterShuffle() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(1));
template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)));
RetryCallback<String[]> retryCallback = new RetryCallback<String[]>() {
public String[] doWithRetry(RetryContext context) throws Exception {
@@ -161,7 +165,8 @@ public class BatchRetryTemplateTests {
public void testExhaustedRetryWithRecovery() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(1));
template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)));
RetryCallback<String[]> retryCallback = new RetryCallback<String[]>() {
public String[] doWithRetry(RetryContext context) throws Exception {
@@ -171,12 +176,12 @@ public class BatchRetryTemplateTests {
return outputs.toArray(new String[0]);
}
};
RecoveryCallback<String[]> recoveryCallback = new RecoveryCallback<String[]>() {
public String[] recover(RetryContext context) throws Exception {
List<String> recovered = new ArrayList<String>();
for (String item : outputs) {
recovered.add("r:"+item);
recovered.add("r:" + item);
}
return recovered.toArray(new String[0]);
}

View File

@@ -36,9 +36,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
public class FaultTolerantExceptionClassesTests implements ApplicationContextAware {
//
// TODO BATCH-1318: Commented out tests are related to this issue
//
@Autowired
private JobRepository jobRepository;

View File

@@ -9,8 +9,9 @@ import static org.junit.Assert.assertFalse;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -36,10 +37,6 @@ public class FaultTolerantStepFactoryBeanNonBufferingTests {
private FaultTolerantStepFactoryBean<String, String> factory = new FaultTolerantStepFactoryBean<String, String>();
@SuppressWarnings("unchecked")
private Collection<Class<? extends Throwable>> skippableExceptions = new HashSet<Class<? extends Throwable>>(Arrays
.<Class<? extends Throwable>> asList(SkippableException.class, SkippableRuntimeException.class));
private List<String> items = Arrays.asList(new String[] { "1", "2", "3", "4", "5" });
private ListItemReader<String> reader = new ListItemReader<String>(TransactionAwareProxyFactory
@@ -61,6 +58,9 @@ public class FaultTolerantStepFactoryBeanNonBufferingTests {
factory.setCommitInterval(2);
factory.setItemReader(reader);
factory.setItemWriter(writer);
Map<Class<? extends Throwable>, Boolean> skippableExceptions = new HashMap<Class<? extends Throwable>, Boolean>();
skippableExceptions.put(SkippableException.class, true);
skippableExceptions.put(SkippableRuntimeException.class, true);
factory.setSkippableExceptionClasses(skippableExceptions);
factory.setSkipLimit(2);
factory.setIsReaderTransactionalQueue(true);

View File

@@ -20,10 +20,11 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -89,6 +90,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
}
};
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
@@ -103,17 +105,10 @@ public class FaultTolerantStepFactoryBeanRetryTests {
factory.setItemWriter(writer);
factory.setJobRepository(repository);
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.setRetryableExceptionClasses(new HashSet<Class<? extends Throwable>>() {
{
add(Exception.class);
}
});
factory.setRetryableExceptionClasses(getExceptionMap(Exception.class));
factory.setCommitInterval(1); // trivial by default
@SuppressWarnings("unchecked")
Collection<Class<? extends Throwable>> skippableExceptions = Arrays
.<Class<? extends Throwable>> asList(Exception.class);
factory.setSkippableExceptionClasses(skippableExceptions);
factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique")
.toJobParameters();
@@ -140,6 +135,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
*
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void testSuccessfulRetryWithReadFailure() throws Exception {
ItemReader<String> provider = new ListItemReader<String>(Arrays.asList("a", "b", "c")) {
@@ -155,7 +151,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
};
factory.setItemReader(provider);
factory.setRetryLimit(10);
factory.setSkippableExceptionClasses(new HashSet<Class<? extends Throwable>>());
factory.setSkippableExceptionClasses(getExceptionMap());
Step step = (Step) factory.getObject();
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
@@ -263,6 +259,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
assertEquals(4, stepExecution.getReadCount());
}
@SuppressWarnings("unchecked")
@Test
public void testSkipAndRetryWithWriteFailure() throws Exception {
@@ -296,11 +293,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
factory.setItemReader(provider);
factory.setItemWriter(itemWriter);
factory.setRetryLimit(5);
factory.setRetryableExceptionClasses(new HashSet<Class<? extends Throwable>>() {
{
add(RuntimeException.class);
}
});
factory.setRetryableExceptionClasses(getExceptionMap(RuntimeException.class));
AbstractStep step = (AbstractStep) factory.getObject();
step.setName("mytest");
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
@@ -319,6 +312,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
assertEquals("[b, d]", recovered.toString());
}
@SuppressWarnings("unchecked")
@Test
public void testSkipAndRetryWithWriteFailureAndNonTrivialCommitInterval() throws Exception {
@@ -353,11 +347,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
factory.setItemReader(provider);
factory.setItemWriter(itemWriter);
factory.setRetryLimit(5);
factory.setRetryableExceptionClasses(new HashSet<Class<? extends Throwable>>() {
{
add(RuntimeException.class);
}
});
factory.setRetryableExceptionClasses(getExceptionMap(RuntimeException.class));
AbstractStep step = (AbstractStep) factory.getObject();
step.setName("mytest");
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
@@ -425,17 +415,14 @@ public class FaultTolerantStepFactoryBeanRetryTests {
assertEquals(1, stepExecution.getReadCount());
}
@SuppressWarnings("unchecked")
@Test
public void testNonSkippableException() throws Exception {
// Very specific skippable exception
factory.setSkippableExceptionClasses(new HashSet<Class<? extends Throwable>>() {
{
add(UnsupportedOperationException.class);
}
});
factory.setSkippableExceptionClasses(getExceptionMap(UnsupportedOperationException.class));
// ...which is not retryable...
factory.setRetryableExceptionClasses(new HashSet<Class<? extends Throwable>>());
factory.setRetryableExceptionClasses(getExceptionMap());
factory.setSkipLimit(1);
ItemReader<String> provider = new ListItemReader<String>(Arrays.asList("b")) {
@@ -479,7 +466,8 @@ public class FaultTolerantStepFactoryBeanRetryTests {
@Test
public void testRetryPolicy() throws Exception {
factory.setRetryPolicy(new SimpleRetryPolicy(4));
factory.setRetryPolicy(new SimpleRetryPolicy(4, Collections
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)));
factory.setSkipLimit(0);
ItemReader<String> provider = new ListItemReader<String>(Arrays.asList("b")) {
public String read() {
@@ -564,4 +552,12 @@ public class FaultTolerantStepFactoryBeanRetryTests {
// []
assertEquals(0, recovered.size());
}
private Map<Class<? extends Throwable>, Boolean> getExceptionMap(Class<? extends Throwable>... args) {
Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
for (Class<? extends Throwable> arg : args) {
map.put(arg, true);
}
return map;
}
}

View File

@@ -6,8 +6,9 @@ import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -55,6 +56,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
writer = new SkipWriterStub<String>();
}
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
factory = new FaultTolerantStepFactoryBean<String, String>();
@@ -73,7 +75,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
factory.setSkipLimit(2);
factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
MapJobRepositoryFactoryBean.clear();
MapJobRepositoryFactoryBean repositoryFactory = new MapJobRepositoryFactoryBean();
@@ -137,6 +139,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
/**
* Scenario: Exception in reader that should not cause rollback
*/
@SuppressWarnings("unchecked")
@Test
public void testReaderAttributesOverrideSkippableNoRollback() throws Exception {
reader.setFailures("2", "3");
@@ -144,7 +147,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
reader.setExceptionType(SkippableException.class);
// No skips by default
factory.setSkippableExceptionClasses(new HashSet<Class<? extends Throwable>>());
factory.setSkippableExceptionClasses(getExceptionMap());
// But this one is explicit in the tx-attrs so it should be skipped
factory.setNoRollbackExceptionClasses(getExceptionList(SkippableException.class));
@@ -416,4 +419,12 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
return Arrays.<Class<? extends Throwable>> asList(arg);
}
private Map<Class<? extends Throwable>, Boolean> getExceptionMap(Class<? extends Throwable>... args) {
Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
for (Class<? extends Throwable> arg : args) {
map.put(arg, true);
}
return map;
}
}

View File

@@ -6,9 +6,9 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -81,6 +81,7 @@ public class FaultTolerantStepFactoryBeanTests {
writer = new SkipWriterStub<String>();
}
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
factory = new FaultTolerantStepFactoryBean<String, String>();
@@ -99,10 +100,8 @@ public class FaultTolerantStepFactoryBeanTests {
factory.setSkipLimit(2);
@SuppressWarnings("unchecked")
Collection<Class<? extends Throwable>> skippableExceptions = Arrays.<Class<? extends Throwable>> asList(
SkippableException.class, SkippableRuntimeException.class);
factory.setSkippableExceptionClasses(skippableExceptions);
factory
.setSkippableExceptionClasses(getExceptionMap(SkippableException.class, SkippableRuntimeException.class));
MapJobRepositoryFactoryBean.clear();
MapJobRepositoryFactoryBean repositoryFactory = new MapJobRepositoryFactoryBean();
@@ -118,15 +117,16 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Non-skippable (and non-fatal) exception causes failure immediately.
*
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void testNonSkippableExceptionOnRead() throws Exception {
reader.setFailures("2");
// nothing is skippable
Collection<Class<? extends Throwable>> empty = Collections.emptySet();
factory.setSkippableExceptionClasses(empty);
factory.setSkippableExceptionClasses(getExceptionMap());
Step step = (Step) factory.getObject();
@@ -139,11 +139,11 @@ public class FaultTolerantStepFactoryBeanTests {
.getName()));
}
@SuppressWarnings("unchecked")
@Test
public void testNonSkippableException() throws Exception {
// nothing is skippable
Collection<Class<? extends Throwable>> empty = Collections.emptySet();
factory.setSkippableExceptionClasses(empty);
factory.setSkippableExceptionClasses(getExceptionMap());
factory.setCommitInterval(1);
// no failures on read
@@ -287,7 +287,11 @@ public class FaultTolerantStepFactoryBeanTests {
public void testFatalException() throws Exception {
reader.setFailures("2");
factory.setFatalExceptionClasses(getExceptionList(FatalRuntimeException.class));
Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
map.put(SkippableException.class, true);
map.put(SkippableRuntimeException.class, true);
map.put(FatalRuntimeException.class, false);
factory.setSkippableExceptionClasses(map);
factory.setItemWriter(new ItemWriter<String>() {
public void write(List<? extends String> items) {
throw new FatalRuntimeException("Ouch!");
@@ -298,7 +302,7 @@ public class FaultTolerantStepFactoryBeanTests {
step.execute(stepExecution);
String message = stepExecution.getFailureExceptions().get(0).getCause().getMessage();
assertTrue("Wrong message: " + message, message.equals("Ouch!"));
assertEquals("Wrong message: ", "Ouch!", message);
assertStepExecutionsAreEqual(stepExecution, repository.getLastStepExecution(jobExecution.getJobInstance(), step
.getName()));
}
@@ -333,6 +337,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
@SuppressWarnings("unchecked")
@Test
public void testSkipOverLimitOnRead() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"));
@@ -341,7 +346,7 @@ public class FaultTolerantStepFactoryBeanTests {
writer.setFailures("4");
factory.setSkipLimit(3);
factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -366,6 +371,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
@SuppressWarnings("unchecked")
@Test
public void testSkipListenerFailsOnRead() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"));
@@ -380,7 +386,7 @@ public class FaultTolerantStepFactoryBeanTests {
throw new RuntimeException("oops");
}
} });
factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -401,6 +407,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
@SuppressWarnings("unchecked")
@Test
public void testSkipListenerFailsOnWrite() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"));
@@ -414,7 +421,7 @@ public class FaultTolerantStepFactoryBeanTests {
throw new RuntimeException("oops");
}
} });
factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -485,12 +492,13 @@ public class FaultTolerantStepFactoryBeanTests {
.getName()));
}
@SuppressWarnings("unchecked")
@Test
public void testDefaultSkipPolicy() throws Exception {
reader.setItems("a", "b", "c");
reader.setFailures("b");
factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
factory.setSkipLimit(1);
Step step = (Step) factory.getObject();
@@ -506,6 +514,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
@SuppressWarnings("unchecked")
@Test
public void testSkipOverLimitOnReadWithAllSkipsAtEnd() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"));
@@ -515,7 +524,7 @@ public class FaultTolerantStepFactoryBeanTests {
factory.setCommitInterval(5);
factory.setSkipLimit(3);
factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -826,11 +835,11 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* condition: skippable < fatal; exception is skippable
*
* expected: false; fatal overrides skippable
* expected: true
*/
@Test
public void testSkippableSubset_skippable() throws Exception {
assertFalse(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
assertTrue(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
}
/**
@@ -874,34 +883,34 @@ public class FaultTolerantStepFactoryBeanTests {
}
private SkipPolicy getSkippableSubsetSkipPolicy() throws Exception {
List<Class<? extends Throwable>> skippableExceptions = new ArrayList<Class<? extends Throwable>>();
skippableExceptions.add(WriteFailedException.class);
List<Class<? extends Throwable>> fatalExceptions = new ArrayList<Class<? extends Throwable>>();
fatalExceptions.add(ItemWriterException.class);
Map<Class<? extends Throwable>, Boolean> skippableExceptions = new HashMap<Class<? extends Throwable>, Boolean>();
skippableExceptions.put(WriteFailedException.class, true);
skippableExceptions.put(ItemWriterException.class, false);
factory.setSkippableExceptionClasses(skippableExceptions);
factory.setFatalExceptionClasses(fatalExceptions);
return getSkipPolicy(factory);
}
private SkipPolicy getFatalSubsetSkipPolicy() throws Exception {
List<Class<? extends Throwable>> skippableExceptions = new ArrayList<Class<? extends Throwable>>();
skippableExceptions.add(ItemWriterException.class);
List<Class<? extends Throwable>> fatalExceptions = new ArrayList<Class<? extends Throwable>>();
fatalExceptions.add(WriteFailedException.class);
Map<Class<? extends Throwable>, Boolean> skippableExceptions = new HashMap<Class<? extends Throwable>, Boolean>();
skippableExceptions.put(ItemWriterException.class, true);
skippableExceptions.put(WriteFailedException.class, false);
factory.setSkippableExceptionClasses(skippableExceptions);
factory.setFatalExceptionClasses(fatalExceptions);
return getSkipPolicy(factory);
}
private SkipPolicy getSkipPolicy(FactoryBean stepFactoryBean) throws Exception {
private SkipPolicy getSkipPolicy(FactoryBean factory) throws Exception {
Object step = factory.getObject();
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
return (SkipPolicy) ReflectionTestUtils.getField(chunkProvider, "skipPolicy");
}
@SuppressWarnings("unchecked")
private Collection<Class<? extends Throwable>> getExceptionList(Class<? extends Throwable> args) {
return Arrays.<Class<? extends Throwable>> asList(args);
private Map<Class<? extends Throwable>, Boolean> getExceptionMap(Class<? extends Throwable>... args) {
Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
for (Class<? extends Throwable> arg : args) {
map.put(arg, true);
}
return map;
}
}

View File

@@ -20,8 +20,8 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
@@ -41,10 +41,9 @@ public class LimitCheckingItemSkipPolicyTests {
@Before
public void setUp() throws Exception {
List<Class<? extends Throwable>> skippableExceptions = new ArrayList<Class<? extends Throwable>>();
skippableExceptions.add(FlatFileParseException.class);
List<Class<? extends Throwable>> fatalExceptions = new ArrayList<Class<? extends Throwable>>();
failurePolicy = new LimitCheckingItemSkipPolicy(1, skippableExceptions, fatalExceptions);
Map<Class<? extends Throwable>, Boolean> skippableExceptions = new HashMap<Class<? extends Throwable>, Boolean>();
skippableExceptions.put(FlatFileParseException.class, true);
failurePolicy = new LimitCheckingItemSkipPolicy(1, skippableExceptions);
}
@Test
@@ -68,11 +67,10 @@ public class LimitCheckingItemSkipPolicyTests {
}
private LimitCheckingItemSkipPolicy getSkippableSubsetSkipPolicy() {
List<Class<? extends Throwable>> skippableExceptions = new ArrayList<Class<? extends Throwable>>();
skippableExceptions.add(WriteFailedException.class);
List<Class<? extends Throwable>> fatalExceptions = new ArrayList<Class<? extends Throwable>>();
fatalExceptions.add(ItemWriterException.class);
return new LimitCheckingItemSkipPolicy(1, skippableExceptions, fatalExceptions);
Map<Class<? extends Throwable>, Boolean> skippableExceptions = new HashMap<Class<? extends Throwable>, Boolean>();
skippableExceptions.put(WriteFailedException.class, true);
skippableExceptions.put(ItemWriterException.class, false);
return new LimitCheckingItemSkipPolicy(1, skippableExceptions);
}
/**
@@ -88,11 +86,11 @@ public class LimitCheckingItemSkipPolicyTests {
/**
* condition: skippable < fatal; exception is skippable
*
* expected: false; fatal overrides skippable
* expected: true
*/
@Test
public void testSkippableSubset_skippable() {
assertFalse(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
assertTrue(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
}
/**
@@ -106,11 +104,10 @@ public class LimitCheckingItemSkipPolicyTests {
}
private LimitCheckingItemSkipPolicy getFatalSubsetSkipPolicy() {
List<Class<? extends Throwable>> skippableExceptions = new ArrayList<Class<? extends Throwable>>();
skippableExceptions.add(ItemWriterException.class);
List<Class<? extends Throwable>> fatalExceptions = new ArrayList<Class<? extends Throwable>>();
fatalExceptions.add(WriteFailedException.class);
return new LimitCheckingItemSkipPolicy(1, skippableExceptions, fatalExceptions);
Map<Class<? extends Throwable>, Boolean> skippableExceptions = new HashMap<Class<? extends Throwable>, Boolean>();
skippableExceptions.put(WriteFailedException.class, false);
skippableExceptions.put(ItemWriterException.class, true);
return new LimitCheckingItemSkipPolicy(1, skippableExceptions);
}
/**