RESOLVED - BATCH-828: org.springframework.batch.item.file.MultiResourceItemReader should allow for no resources

graceful handling for non-existing input resources
This commit is contained in:
robokaso
2008-09-12 13:15:39 +00:00
parent f32ea26c67
commit 06141963be
5 changed files with 93 additions and 30 deletions

View File

@@ -92,6 +92,8 @@ public class FlatFileItemReader<T> extends AbstractItemReaderItemStream<T> imple
private LineCallbackHandler headerCallback;
private boolean noInput;
public FlatFileItemReader() {
setName(ClassUtils.getShortName(FlatFileItemReader.class));
}
@@ -213,8 +215,13 @@ public class FlatFileItemReader<T> extends AbstractItemReaderItemStream<T> imple
*/
protected void doOpen() throws Exception {
Assert.notNull(resource, "Input resource must not be null");
Assert.state(resource.exists(), "Resource must exist: [" + resource + "]");
noInput = false;
if (!resource.exists()) {
noInput = true;
log.warn("Input resource does not exist");
return;
}
try {
reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding));
}
@@ -249,6 +256,9 @@ public class FlatFileItemReader<T> extends AbstractItemReaderItemStream<T> imple
* {@link #setFieldSetMapper(FieldSetMapper)}.
*/
protected T doRead() throws Exception {
if (noInput) {
return null;
}
String record = readRecord();
if (record != null) {

View File

@@ -45,7 +45,7 @@ public class MultiResourceItemReader<T> implements ItemReader<T>, ItemStream {
private boolean saveState = true;
// signals there are no resources to read -> just return null on first read
private boolean emptyInput;
private boolean noInput;
private Comparator<Resource> comparator = new Comparator<Resource>() {
@@ -67,7 +67,7 @@ public class MultiResourceItemReader<T> implements ItemReader<T>, ItemStream {
*/
public T read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException {
if (emptyInput) {
if (noInput) {
return null;
}
@@ -112,7 +112,7 @@ public class MultiResourceItemReader<T> implements ItemReader<T>, ItemStream {
public void close(ExecutionContext executionContext) throws ItemStreamException {
index = new MultiResourceIndex();
delegate.close(new ExecutionContext());
emptyInput = false;
noInput = false;
}
/**
@@ -123,10 +123,10 @@ public class MultiResourceItemReader<T> implements ItemReader<T>, ItemStream {
Assert.notNull(resources, "Resources must be set");
emptyInput = false;
noInput = false;
if (resources.length == 0) {
logger.info("No resources to read");
emptyInput = true;
logger.warn("No resources to read");
noInput = true;
return;
}

View File

@@ -8,6 +8,8 @@ import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream;
import org.springframework.batch.item.support.AbstractItemReaderItemStream;
import org.springframework.batch.item.xml.stax.DefaultFragmentEventReader;
@@ -35,6 +37,8 @@ import org.springframework.xml.transform.StaxSource;
public class StaxEventItemReader<T> extends AbstractItemReaderItemStream<T> implements
ResourceAwareItemReaderItemStream<T>, InitializingBean {
private static final Log logger = LogFactory.getLog(StaxEventItemReader.class);
private FragmentEventReader fragmentReader;
private XMLEventReader eventReader;
@@ -47,6 +51,8 @@ public class StaxEventItemReader<T> extends AbstractItemReaderItemStream<T> impl
private String fragmentRootElementName;
private boolean noInput;
public StaxEventItemReader() {
setName(ClassUtils.getShortName(StaxEventItemReader.class));
}
@@ -137,7 +143,13 @@ public class StaxEventItemReader<T> extends AbstractItemReaderItemStream<T> impl
protected void doOpen() throws Exception {
Assert.notNull(resource, "The Resource must not be null.");
Assert.state(resource.exists(), "Input resource does not exist: [" + resource + "]");
noInput = false;
if (!resource.exists()) {
noInput = true;
logger.warn("Input resource does not exist");
return;
}
inputStream = resource.getInputStream();
eventReader = XMLInputFactory.newInstance().createXMLEventReader(inputStream);
@@ -149,6 +161,11 @@ public class StaxEventItemReader<T> extends AbstractItemReaderItemStream<T> impl
* Move to next fragment and map it to item.
*/
protected T doRead() throws Exception {
if (noInput) {
return null;
}
T item = null;
if (moveCursorToNextFragment(fragmentReader)) {

View File

@@ -16,12 +16,20 @@
package org.springframework.batch.item.file;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStream;
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ReaderNotOpenException;
@@ -42,7 +50,7 @@ import org.springframework.core.io.Resource;
* @see FlatFileItemReaderAdvancedTests
* @author Dave Syer
*/
public class FlatFileItemReaderBasicTests extends TestCase {
public class FlatFileItemReaderBasicTests {
// object under test
private FlatFileItemReader<FieldSet> itemReader = new FlatFileItemReader<FieldSet>();
@@ -65,7 +73,8 @@ public class FlatFileItemReaderBasicTests extends TestCase {
/**
* Create inputFile, inject mock/stub dependencies for tested object, initialize the tested object
*/
protected void setUp() throws Exception {
@Before
public void setUp() throws Exception {
itemReader.setResource(getInputResource(TEST_STRING));
itemReader.setLineTokenizer(tokenizer);
@@ -78,7 +87,8 @@ public class FlatFileItemReaderBasicTests extends TestCase {
/**
* Release resources.
*/
protected void tearDown() throws Exception {
@After
public void tearDown() throws Exception {
itemReader.close(null);
}
@@ -89,6 +99,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
/**
* Regular usage of <code>read</code> method
*/
@Test
public void testRead() throws Exception {
itemReader.open(executionContext);
assertEquals("[FlatFileInputTemplate-TestData]", itemReader.read().toString());
@@ -97,6 +108,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
/**
* Regular usage of <code>read</code> method
*/
@Test
public void testReadExhausted() throws Exception {
itemReader.open(executionContext);
assertEquals("[FlatFileInputTemplate-TestData]", itemReader.read().toString());
@@ -106,6 +118,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
/**
* Regular usage of <code>read</code> method
*/
@Test
public void testReadWithTokenizerError() throws Exception {
itemReader.setLineTokenizer(new LineTokenizer() {
public FieldSet tokenize(String line) {
@@ -122,6 +135,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
}
}
@Test
public void testReadWithMapperError() throws Exception {
itemReader.setFieldSetMapper(new FieldSetMapper<FieldSet>() {
public FieldSet mapLine(FieldSet fs) {
@@ -139,6 +153,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
}
}
@Test
public void testReadBeforeOpen() throws Exception {
itemReader = new FlatFileItemReader<FieldSet>();
itemReader.setResource(getInputResource(TEST_STRING));
@@ -151,6 +166,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
}
}
@Test
public void testCloseBeforeOpen() throws Exception {
itemReader = new FlatFileItemReader<FieldSet>();
itemReader.setResource(getInputResource(TEST_STRING));
@@ -161,6 +177,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
assertEquals("[FlatFileInputTemplate-TestData]", itemReader.read().toString());
}
@Test
public void testInitializationWithNullResource() throws Exception {
itemReader = new FlatFileItemReader<FieldSet>();
try {
@@ -171,11 +188,13 @@ public class FlatFileItemReaderBasicTests extends TestCase {
}
}
@Test
public void testOpenTwiceHasNoEffect() throws Exception {
itemReader.open(executionContext);
testRead();
}
@Test
public void testSetValidEncoding() throws Exception {
itemReader = new FlatFileItemReader<FieldSet>();
itemReader.setEncoding("UTF-8");
@@ -185,6 +204,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
testRead();
}
@Test
public void testSetNullEncoding() throws Exception {
itemReader = new FlatFileItemReader<FieldSet>();
itemReader.setEncoding(null);
@@ -197,6 +217,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
}
}
@Test
public void testSetInvalidEncoding() throws Exception {
itemReader = new FlatFileItemReader<FieldSet>();
itemReader.setEncoding("foo");
@@ -211,16 +232,19 @@ public class FlatFileItemReaderBasicTests extends TestCase {
}
}
@Test
public void testEncoding() throws Exception {
itemReader.setEncoding("UTF-8");
testRead();
}
@Test
public void testRecordSeparator() throws Exception {
itemReader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy());
testRead();
}
@Test
public void testComments() throws Exception {
itemReader.setResource(getInputResource("% Comment\n" + TEST_STRING));
itemReader.setComments(new String[] { "%" });
@@ -231,6 +255,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
* Header line is skipped and used to setup fieldSet column names.
* It is also passed to header callback.
*/
@Test
public void testColumnNamesInHeader() throws Exception {
final String INPUT = "name1|name2\nvalue1|value2\nvalue3|value4";
@@ -261,6 +286,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
/**
* Header line is skipped and used to setup fieldSet column names.
*/
@Test
public void testLinesToSkip() throws Exception {
final String INPUT = "foo bar spam\none two\nthree four";
@@ -281,6 +307,7 @@ public class FlatFileItemReaderBasicTests extends TestCase {
assertEquals("four", fs.readString(1));
}
@Test
public void testNonExistantResource() throws Exception {
Resource resource = new NonExistentResource();
@@ -294,15 +321,12 @@ public class FlatFileItemReaderBasicTests extends TestCase {
// afterPropertiesSet should only throw an exception if the Resource is null
testReader.afterPropertiesSet();
try {
testReader.open(executionContext);
fail();
} catch (ItemStreamException ex) {
// expected
}
testReader.open(executionContext);
assertNull(testReader.read());
}
@Test
public void testRuntimeFileCreation() throws Exception {
Resource resource = new NonExistentResource();

View File

@@ -13,8 +13,10 @@ import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Source;
import junit.framework.TestCase;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.core.io.AbstractResource;
@@ -30,7 +32,7 @@ import org.springframework.xml.transform.StaxSource;
*
* @author Robert Kasanicky
*/
public class StaxEventItemReaderTests extends TestCase {
public class StaxEventItemReaderTests {
// object under test
private StaxEventItemReader<List<XMLEvent>> source;
@@ -44,15 +46,18 @@ public class StaxEventItemReaderTests extends TestCase {
private ExecutionContext executionContext;
protected void setUp() throws Exception {
@Before
public void setUp() throws Exception {
this.executionContext = new ExecutionContext();
source = createNewInputSouce();
}
@Test
public void testAfterPropertiesSet() throws Exception {
source.afterPropertiesSet();
}
@Test
public void testAfterPropertesSetException() throws Exception {
source = createNewInputSouce();
@@ -80,6 +85,7 @@ public class StaxEventItemReaderTests extends TestCase {
* Regular usage scenario. ItemReader should pass XML fragments to
* unmarshaller wrapped with StartDocument and EndDocument events.
*/
@Test
public void testFragmentWrapping() throws Exception {
source.afterPropertiesSet();
source.open(executionContext);
@@ -94,6 +100,7 @@ public class StaxEventItemReaderTests extends TestCase {
/**
* Cursor is moved before beginning of next fragment.
*/
@Test
public void testMoveCursorToNextFragment() throws XMLStreamException, FactoryConfigurationError, IOException {
Resource resource = new ByteArrayResource(xml.getBytes());
XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(resource.getInputStream());
@@ -110,6 +117,7 @@ public class StaxEventItemReaderTests extends TestCase {
/**
* Save restart data and restore from it.
*/
@Test
public void testRestart() throws Exception {
source.open(executionContext);
@@ -126,6 +134,7 @@ public class StaxEventItemReaderTests extends TestCase {
}
@Test
public void testRestoreWorksFromClosedStream() throws Exception {
source.close(executionContext);
source.update(executionContext);
@@ -135,6 +144,7 @@ public class StaxEventItemReaderTests extends TestCase {
* Statistics return the current record count. Calling read after end of
* input does not increase the counter.
*/
@Test
public void testExecutionContext() throws Exception {
final int NUMBER_OF_RECORDS = 2;
source.open(executionContext);
@@ -156,11 +166,13 @@ public class StaxEventItemReaderTests extends TestCase {
return executionContext.getLong(ClassUtils.getShortName(StaxEventItemReader.class) + ".read.count");
}
@Test
public void testCloseWithoutOpen() throws Exception {
source.close(null);
// No error!
}
@Test
public void testClose() throws Exception {
MockStaxEventItemReader newSource = new MockStaxEventItemReader();
Resource resource = new ByteArrayResource(xml.getBytes());
@@ -187,6 +199,7 @@ public class StaxEventItemReaderTests extends TestCase {
}
}
@Test
public void testOpenBadIOInput() {
source.setResource(new AbstractResource() {
@@ -212,20 +225,19 @@ public class StaxEventItemReaderTests extends TestCase {
}
@Test
public void testNonExistentResource() throws Exception {
source.setResource(new NonExistentResource());
source.afterPropertiesSet();
try {
source.open(executionContext);
fail();
}
catch (ItemStreamException ex) {
// expected
}
source.open(executionContext);
assertNull(source.read());
}
@Test
public void testRuntimeFileCreation() throws Exception {
source.setResource(new NonExistentResource());