IN PROGRESS - BATCH-414: consistent handling of empty input by ItemReaders

empty input handled gracefully by all readers + tests
This commit is contained in:
robokaso
2008-06-26 13:51:01 +00:00
parent 4e247e7577
commit 9df6431654
14 changed files with 225 additions and 95 deletions

View File

@@ -45,12 +45,13 @@ public abstract class CommonItemReaderTests extends TestCase {
}
/**
* Rollback scenario - reader resets to last marked point.
* Rollback scenario - reader resets to last marked point. Note the commit
* interval can change dynamically.
*/
public void testReset() throws Exception {
Foo foo1 = (Foo) tested.read();
assertEquals(1, foo1.getValue());
tested.mark();
Foo foo2 = (Foo) tested.read();
@@ -62,31 +63,48 @@ public abstract class CommonItemReaderTests extends TestCase {
tested.reset();
assertEquals(foo2, tested.read());
// TODO handle shortening the commit interval on the fly
tested.mark();
assertEquals(foo3, tested.read());
tested.reset();
assertEquals(foo3, tested.read());
Foo foo4 = (Foo) tested.read();
assertEquals(4, foo4.getValue());
tested.mark();
Foo foo5 = (Foo) tested.read();
assertEquals(5, foo5.getValue());
tested.reset();
assertEquals(foo5, tested.read());
assertNull(tested.read());
}
/**
* Empty input should be handled gracefully - null is returned on first
* read.
*/
public void testEmptyInput() throws Exception {
pointToEmptyInput(tested);
assertNull(tested.read());
}
/**
* Point the reader to empty input (close and open if necessary for the new
* settings to apply).
*
* @param tested
* the reader
*/
protected abstract void pointToEmptyInput(ItemReader tested)
throws Exception;
}

View File

@@ -7,7 +7,8 @@ import org.springframework.batch.item.sample.Foo;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
public class MultiResourceItemReaderFlatFileTests extends CommonItemStreamItemReaderTests {
public class MultiResourceItemReaderFlatFileTests extends
CommonItemStreamItemReaderTests {
protected ItemReader getItemReader() throws Exception {
@@ -37,4 +38,14 @@ public class MultiResourceItemReaderFlatFileTests extends CommonItemStreamItemRe
return multiReader;
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
MultiResourceItemReader multiReader = (MultiResourceItemReader) tested;
multiReader.close(new ExecutionContext());
multiReader.setResources(new Resource[] { new ByteArrayResource(""
.getBytes()) });
multiReader.afterPropertiesSet();
multiReader.open(new ExecutionContext());
}
}

View File

@@ -50,5 +50,15 @@ public class MultiResourceItemReaderXmlTests extends CommonItemStreamItemReaderT
return multiReader;
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
MultiResourceItemReader multiReader = (MultiResourceItemReader) tested;
multiReader.close(new ExecutionContext());
multiReader.setResources(new Resource[] { new ByteArrayResource("<foos />"
.getBytes()) });
multiReader.afterPropertiesSet();
multiReader.open(new ExecutionContext());
}
}

View File

@@ -9,36 +9,34 @@ import junit.framework.TestCase;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.NoWorkFoundException;
import org.springframework.batch.item.sample.Foo;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
public class DrivingQueryItemReaderTests extends TestCase {
DrivingQueryItemReader itemReader;
static {
TransactionSynchronizationManager.initSynchronization();
}
protected void setUp() throws Exception {
super.setUp();
itemReader = createItemReader();
}
private DrivingQueryItemReader createItemReader() throws Exception{
private DrivingQueryItemReader createItemReader() throws Exception {
DrivingQueryItemReader inputSource = new DrivingQueryItemReader();
inputSource.setKeyCollector(new MockKeyGenerator());
inputSource.setSaveState(true);
return inputSource;
}
/**
* Regular scenario - read all rows and eventually return null.
*/
@@ -66,14 +64,15 @@ public class DrivingQueryItemReaderTests extends TestCase {
/**
* Restart scenario.
*
* @throws Exception
*/
public void testRestart() throws Exception {
ExecutionContext executionContext = new ExecutionContext();
getAsItemStream(itemReader).open(executionContext);
Foo foo1 = (Foo) itemReader.read();
assertEquals(1, foo1.getValue());
@@ -97,9 +96,9 @@ public class DrivingQueryItemReaderTests extends TestCase {
public void testInvalidRestore() throws Exception {
ExecutionContext executionContext = new ExecutionContext();
getAsItemStream(itemReader).open(executionContext);
Foo foo1 = (Foo) itemReader.read();
assertEquals(1, foo1.getValue());
@@ -118,15 +117,15 @@ public class DrivingQueryItemReaderTests extends TestCase {
try {
getAsItemStream(itemReader).open(executionContext);
fail();
}
catch (IllegalStateException ex) {
} catch (IllegalStateException ex) {
// expected
}
}
/**
* Empty restart data should be handled gracefully.
* @throws Exception
*
* @throws Exception
*/
public void testRestoreFromEmptyData() throws Exception {
ExecutionContext streamContext = new ExecutionContext(new Properties());
@@ -139,7 +138,8 @@ public class DrivingQueryItemReaderTests extends TestCase {
/**
* Rollback scenario.
* @throws Exception
*
* @throws Exception
*/
public void testRollback() throws Exception {
getAsItemStream(itemReader).open(new ExecutionContext());
@@ -157,27 +157,25 @@ public class DrivingQueryItemReaderTests extends TestCase {
assertEquals(foo2, itemReader.read());
}
public void testRetriveZeroKeys(){
itemReader.setKeyCollector(new KeyCollector(){
public void testRetriveZeroKeys() {
itemReader.setKeyCollector(new KeyCollector() {
public List retrieveKeys(ExecutionContext executionContext) {
return new ArrayList();
}
public void updateContext(Object key, ExecutionContext executionContext) {
}});
try{
itemReader.open(new ExecutionContext());
fail();
}
catch(NoWorkFoundException ex){
//expected
}
}
public void updateContext(Object key,
ExecutionContext executionContext) {
}
});
itemReader.open(new ExecutionContext());
assertNull(itemReader.read());
}
private void commit() {
itemReader.mark();
@@ -186,7 +184,7 @@ public class DrivingQueryItemReaderTests extends TestCase {
private void rollback() {
itemReader.reset();
}
private InitializingBean getAsInitializingBean(ItemReader source) {
return (InitializingBean) source;
}
@@ -194,46 +192,45 @@ public class DrivingQueryItemReaderTests extends TestCase {
private ItemStream getAsItemStream(ItemReader source) {
return (ItemStream) source;
}
private static class MockKeyGenerator implements KeyCollector{
private static class MockKeyGenerator implements KeyCollector {
static ExecutionContext streamContext;
List keys;
List restartKeys;
static final String RESTART_KEY = "restart.keys";
static{
static {
Properties props = new Properties();
//restart data properties cannot be empty.
// restart data properties cannot be empty.
props.setProperty("", "");
streamContext = new ExecutionContext(props);
}
public MockKeyGenerator() {
keys = new ArrayList();
keys.add(new Foo(1, "1", 1));
keys.add(new Foo(2, "2", 2));
keys.add(new Foo(3, "3", 3));
keys.add(new Foo(4, "4", 4));
keys.add(new Foo(5, "5", 5));
restartKeys = new ArrayList();
restartKeys.add(new Foo(3, "3", 3));
restartKeys.add(new Foo(4, "4", 4));
restartKeys.add(new Foo(5, "5", 5));
}
public ExecutionContext saveState(Object key) {
return streamContext;
}
public List retrieveKeys(ExecutionContext executionContext) {
if(executionContext.containsKey(RESTART_KEY)){
if (executionContext.containsKey(RESTART_KEY)) {
return restartKeys;
}
else{
} else {
return keys;
}
}
@@ -241,7 +238,7 @@ public class DrivingQueryItemReaderTests extends TestCase {
public void updateContext(Object key, ExecutionContext executionContext) {
executionContext.put(RESTART_KEY, restartKeys);
}
}
}

View File

@@ -9,17 +9,21 @@ import org.springframework.jdbc.core.JdbcTemplate;
class FooItemReader implements ItemStream, ItemReader, DisposableBean, InitializingBean {
DrivingQueryItemReader inputSource;
DrivingQueryItemReader itemReader;
public void setItemReader(DrivingQueryItemReader itemReader) {
this.itemReader = itemReader;
}
FooDao fooDao = new SingleKeyFooDao();
public FooItemReader(DrivingQueryItemReader inputSource, JdbcTemplate jdbcTemplate) {
this.inputSource = inputSource;
this.itemReader = inputSource;
fooDao.setJdbcTemplate(jdbcTemplate);
}
public Object read() {
Object key = inputSource.read();
Object key = itemReader.read();
if (key != null) {
return fooDao.getFoo(key);
}
@@ -29,11 +33,11 @@ class FooItemReader implements ItemStream, ItemReader, DisposableBean, Initializ
}
public void update(ExecutionContext executionContext) {
inputSource.update(executionContext);
itemReader.update(executionContext);
}
public void destroy() throws Exception {
inputSource.close(null);
itemReader.close(null);
}
public void setFooDao(FooDao fooDao) {
@@ -44,11 +48,11 @@ class FooItemReader implements ItemStream, ItemReader, DisposableBean, Initializ
}
public void open(ExecutionContext executionContext) {
inputSource.open(executionContext);
itemReader.open(executionContext);
};
public void close(ExecutionContext executionContext) {
inputSource.close(executionContext);
itemReader.close(executionContext);
}
/*
@@ -56,7 +60,7 @@ class FooItemReader implements ItemStream, ItemReader, DisposableBean, Initializ
* @see org.springframework.batch.item.ItemStream#mark(org.springframework.batch.item.StreamContext)
*/
public void mark() {
inputSource.mark();
itemReader.mark();
}
/*
@@ -64,6 +68,6 @@ class FooItemReader implements ItemStream, ItemReader, DisposableBean, Initializ
* @see org.springframework.batch.item.ItemStream#reset(org.springframework.batch.item.StreamContext)
*/
public void reset() {
inputSource.reset();
itemReader.reset();
};
}

View File

@@ -1,6 +1,7 @@
package org.springframework.batch.item.database;
import org.hibernate.SessionFactory;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -9,12 +10,8 @@ import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
public class HibernateCursorItemReaderCommonTests extends CommonDatabaseItemStreamItemReaderTests {
protected ItemReader getItemReader() throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(getDataSource());
factoryBean.setMappingLocations(new Resource[] { new ClassPathResource("Foo.hbm.xml", getClass()) });
factoryBean.afterPropertiesSet();
SessionFactory sessionFactory = (SessionFactory) factoryBean.getObject();
SessionFactory sessionFactory = createSessionFactory();
String hsqlQuery = "from Foo";
@@ -27,5 +24,23 @@ public class HibernateCursorItemReaderCommonTests extends CommonDatabaseItemStre
return reader;
}
private SessionFactory createSessionFactory() throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(getDataSource());
factoryBean.setMappingLocations(new Resource[] { new ClassPathResource("Foo.hbm.xml", getClass()) });
factoryBean.afterPropertiesSet();
return (SessionFactory) factoryBean.getObject();
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
HibernateCursorItemReader reader = (HibernateCursorItemReader) tested;
reader.close(new ExecutionContext());
reader.setQueryString("from Foo foo where foo.id = -1");
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
}
}

View File

@@ -1,5 +1,6 @@
package org.springframework.batch.item.database;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.support.IbatisKeyCollector;
import org.springframework.core.io.ClassPathResource;
@@ -14,7 +15,7 @@ public class IbatisItemReaderCommonTests extends CommonDatabaseItemStreamItemRea
factory.setConfigLocation(new ClassPathResource("ibatis-config.xml", getClass()));
factory.setDataSource(getDataSource());
factory.afterPropertiesSet();
SqlMapClient sqlMapClient = (SqlMapClient) factory.getObject();
SqlMapClient sqlMapClient = createSqlMapClient();
IbatisDrivingQueryItemReader reader = new IbatisDrivingQueryItemReader();
IbatisKeyCollector keyGenerator = new IbatisKeyCollector();
@@ -28,5 +29,27 @@ public class IbatisItemReaderCommonTests extends CommonDatabaseItemStreamItemRea
return reader;
}
private SqlMapClient createSqlMapClient() throws Exception {
SqlMapClientFactoryBean factory = new SqlMapClientFactoryBean();
factory.setConfigLocation(new ClassPathResource("ibatis-config.xml", getClass()));
factory.setDataSource(getDataSource());
factory.afterPropertiesSet();
return (SqlMapClient) factory.getObject();
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
IbatisDrivingQueryItemReader reader = (IbatisDrivingQueryItemReader) tested;
reader.close(new ExecutionContext());
IbatisKeyCollector keyCollector = new IbatisKeyCollector();
keyCollector.setDrivingQueryId("getNoFoos");
keyCollector.setSqlMapClient(createSqlMapClient());
reader.setKeyCollector(keyCollector);
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
}
}

View File

@@ -1,5 +1,6 @@
package org.springframework.batch.item.database;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
public class JdbcCursorItemReaderCommonTests extends CommonDatabaseItemStreamItemReaderTests {
@@ -30,4 +31,12 @@ public class JdbcCursorItemReaderCommonTests extends CommonDatabaseItemStreamIte
testRestart();
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
JdbcCursorItemReader reader = (JdbcCursorItemReader) tested;
reader.close(new ExecutionContext());
reader.setSql("select ID from T_FOOS where ID < 0");
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
}
}

View File

@@ -1,5 +1,6 @@
package org.springframework.batch.item.database;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.support.SingleColumnJdbcKeyCollector;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -8,13 +9,32 @@ public class SingleColumnJdbcDrivingQueryItemReaderCommonTests extends CommonDat
protected ItemReader getItemReader() throws Exception {
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
SingleColumnJdbcKeyCollector keyStrategy = new SingleColumnJdbcKeyCollector(jdbcTemplate,
SingleColumnJdbcKeyCollector keyCollector = new SingleColumnJdbcKeyCollector(jdbcTemplate,
"SELECT ID from T_FOOS order by ID");
keyStrategy.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");
keyCollector.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");
DrivingQueryItemReader reader = new DrivingQueryItemReader();
reader.setKeyCollector(keyStrategy);
reader.setKeyCollector(keyCollector);
reader.setSaveState(true);
return new FooItemReader(reader, jdbcTemplate);
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
FooItemReader fooReader = (FooItemReader) tested;
fooReader.close(new ExecutionContext());
DrivingQueryItemReader reader = new DrivingQueryItemReader();
reader.close(new ExecutionContext());
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
SingleColumnJdbcKeyCollector keyCollector = new SingleColumnJdbcKeyCollector(jdbcTemplate,
"SELECT ID from T_FOOS where ID < 0");
reader.setKeyCollector(keyCollector);
reader.afterPropertiesSet();
fooReader.setItemReader(reader);
fooReader.open(new ExecutionContext());
}
}

View File

@@ -1,6 +1,7 @@
package org.springframework.batch.item.file;
import org.springframework.batch.item.CommonItemStreamItemReaderTests;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.file.mapping.FieldSet;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
@@ -29,4 +30,14 @@ public class FlatFileItemReaderCommonTests extends CommonItemStreamItemReaderTes
return tested;
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
FlatFileItemReader reader = (FlatFileItemReader) tested;
reader.close(new ExecutionContext());
reader.setResource(new ByteArrayResource("".getBytes()));
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
}
}

View File

@@ -6,6 +6,7 @@ import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import org.springframework.batch.item.CommonItemStreamItemReaderTests;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.sample.Foo;
import org.springframework.core.io.ByteArrayResource;
@@ -40,4 +41,14 @@ public class StaxEventItemReaderCommonTests extends CommonItemStreamItemReaderTe
return reader;
}
protected void pointToEmptyInput(ItemReader tested) throws Exception {
StaxEventItemReader reader = (StaxEventItemReader) tested;
reader.close(new ExecutionContext());
reader.setResource(new ByteArrayResource("<foos />".getBytes()));
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
}
}