From c9efdb0493f8e973c27074bcce6d9997fdafd14e Mon Sep 17 00:00:00 2001 From: robokaso Date: Tue, 7 Oct 2008 09:04:31 +0000 Subject: [PATCH] IN PROGRESS - BATCH-863: introduce LineMapper interface to encapsulate string-to-item mapping removed FFIR --- .../batch/item/file/FlatFileItemReader.java | 336 ---------------- .../file/FlatFileItemReaderAdvancedTests.java | 217 ---------- .../file/FlatFileItemReaderBasicTests.java | 370 ------------------ .../file/FlatFileItemReaderCommonTests.java | 46 --- .../sample/support/HeaderCopyCallback.java | 5 +- .../jobs/beanWrapperMapperSampleJob.xml | 23 +- .../jobs/compositeItemWriterSampleJob.xml | 10 +- .../src/main/resources/jobs/footballJob.xml | 48 ++- .../resources/jobs/headerFooterSample.xml | 26 +- .../main/resources/jobs/multiResourceJob.xml | 10 +- .../src/main/resources/jobs/multilineJob.xml | 15 +- .../main/resources/jobs/multilineOrderIo.xml | 14 +- .../src/main/resources/jobs/parallelJob.xml | 10 +- .../src/main/resources/jobs/restartSample.xml | 10 +- .../src/main/resources/jobs/tradeJobIo.xml | 14 +- .../FixedLengthImportJobFunctionalTests.java | 14 +- 16 files changed, 124 insertions(+), 1044 deletions(-) delete mode 100644 spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java delete mode 100644 spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderAdvancedTests.java delete mode 100644 spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderBasicTests.java delete mode 100644 spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderCommonTests.java diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java deleted file mode 100644 index 025ef3056..000000000 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.item.file; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.Charset; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemStreamException; -import org.springframework.batch.item.ReaderNotOpenException; -import org.springframework.batch.item.UnexpectedInputException; -import org.springframework.batch.item.file.mapping.FieldSet; -import org.springframework.batch.item.file.mapping.FieldSetMapper; -import org.springframework.batch.item.file.separator.DefaultRecordSeparatorPolicy; -import org.springframework.batch.item.file.separator.RecordSeparatorPolicy; -import org.springframework.batch.item.file.transform.AbstractLineTokenizer; -import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; -import org.springframework.batch.item.file.transform.LineTokenizer; -import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * This class represents a {@link ItemReader}, that reads lines from text file, - * tokenizes them to structured tuples ({@link FieldSet}s) instances and maps - * the {@link FieldSet}s to domain objects. The location of the file is defined - * by the resource property. To separate the structure of the file, - * {@link LineTokenizer} is used to parse data obtained from the file.
- * - * A {@link FlatFileItemReader} is not thread safe because it maintains state in - * instance variables.
- * - *

- * This class supports restart, skipping invalid lines and storing statistics. - * It can be configured to setup {@link FieldSet} column names from the file - * header, skip given number of lines at the beginning of the file. - *

- * - * The implementation is *not* thread-safe. - * - * @author Waseem Malik - * @author Tomas Slanina - * @author Robert Kasanicky - * @author Dave Syer - */ -public class FlatFileItemReader extends AbstractItemCountingItemStreamItemReader implements - ResourceAwareItemReaderItemStream, InitializingBean { - - private static Log log = LogFactory.getLog(FlatFileItemReader.class); - - // default encoding for input files - public static final String DEFAULT_CHARSET = Charset.defaultCharset().name(); - - private String encoding = DEFAULT_CHARSET; - - private Resource resource; - - private RecordSeparatorPolicy recordSeparatorPolicy = new DefaultRecordSeparatorPolicy(); - - private String[] comments = new String[] { "#" }; - - private int linesToSkip = 0; - - private boolean firstLineIsHeader = false; - - private LineTokenizer tokenizer = new DelimitedLineTokenizer(); - - private FieldSetMapper fieldSetMapper; - - private int lineCount = 0; - - private BufferedReader reader; - - private LineCallbackHandler headerCallback; - - private boolean noInput; - - public FlatFileItemReader() { - setName(ClassUtils.getShortName(FlatFileItemReader.class)); - } - - /** - * headerCallback will be passed the header line before any items are read. - */ - public void setHeaderCallback(LineCallbackHandler headerCallback) { - this.headerCallback = headerCallback; - } - - /** - * Setter for resource property. The location of an input stream that can be - * read. - * - * @param resource - */ - public void setResource(Resource resource) { - this.resource = resource; - } - - /** - * Public setter for the recordSeparatorPolicy. Used to determine where the - * line endings are and do things like continue over a line ending if inside - * a quoted string. - * - * @param recordSeparatorPolicy the recordSeparatorPolicy to set - */ - public void setRecordSeparatorPolicy(RecordSeparatorPolicy recordSeparatorPolicy) { - this.recordSeparatorPolicy = recordSeparatorPolicy; - } - - /** - * Setter for comment prefixes. Can be used to ignore header lines as well - * by using e.g. the first couple of column names as a prefix. - * - * @param comments an array of comment line prefixes. - */ - public void setComments(String[] comments) { - this.comments = new String[comments.length]; - System.arraycopy(comments, 0, this.comments, 0, comments.length); - } - - /** - * Indicates whether first line is a header. If the tokenizer is an - * {@link AbstractLineTokenizer} and the column names haven't been set - * already then the header will be used to setup column names. Default is - * false. - */ - public void setFirstLineIsHeader(boolean firstLineIsHeader) { - this.firstLineIsHeader = firstLineIsHeader; - } - - /** - * @param lineTokenizer tokenizes each line from file into {@link FieldSet}. - */ - public void setLineTokenizer(LineTokenizer lineTokenizer) { - this.tokenizer = lineTokenizer; - } - - /** - * Set the FieldSetMapper to be used for each line. - * - * @param fieldSetMapper - */ - public void setFieldSetMapper(FieldSetMapper fieldSetMapper) { - this.fieldSetMapper = fieldSetMapper; - } - - /** - * Public setter for the number of lines to skip at the start of a file. Can - * be used if the file contains a header without useful (column name) - * information, and without a comment delimiter at the beginning of the - * lines. - * - * @param linesToSkip the number of lines to skip - */ - public void setLinesToSkip(int linesToSkip) { - this.linesToSkip = linesToSkip; - } - - /** - * Setter for the encoding for this input source. Default value is - * {@link #DEFAULT_CHARSET}. - * - * @param encoding a properties object which possibly contains the encoding - * for this input file; - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(fieldSetMapper, "FieldSetMapper must not be null."); - } - - /** - * Close the {@link BufferedReader} and reset internal state. - */ - protected void doClose() throws Exception { - if (reader == null) { - return; - } - try { - reader.close(); - } - catch (IOException e) { - throw new ItemStreamException("Could not close reader", e); - } - finally { - lineCount = 0; - } - } - - /** - * Initialize the {@link BufferedReader} and skip - * {@link #setLinesToSkip(int)} number of lines. Setup column names if - * {@link #setFirstLineIsHeader(boolean)} is true. - */ - protected void doOpen() throws Exception { - Assert.notNull(resource, "Input resource must not be null"); - - noInput = false; - if (!resource.exists()) { - noInput = true; - log.warn("Input resource does not exist"); - return; - } - try { - reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding)); - } - catch (IOException e) { - throw new ItemStreamException("Could not open resource", e); - } - - log.debug("Opening flat file for reading: " + resource); - - for (int i = 0; i < linesToSkip; i++) { - readRecord(); - } - - if (firstLineIsHeader) { - // skip the header - String firstLine = readRecord(); - // set names in tokenizer if they haven't been set already - if (tokenizer instanceof AbstractLineTokenizer && !((AbstractLineTokenizer) tokenizer).hasNames()) { - String[] names = tokenizer.process(firstLine).getValues(); - ((AbstractLineTokenizer) tokenizer).setNames(names); - } - if (headerCallback != null) { - headerCallback.handleLine(firstLine); - } - } - - } - - /** - * Reads a line from input, tokenizes is it using the - * {@link #setLineTokenizer(LineTokenizer)} and maps to domain object using - * {@link #setFieldSetMapper(FieldSetMapper)}. - */ - protected T doRead() throws Exception { - if (noInput) { - return null; - } - String record = readRecord(); - - if (record != null) { - try { - FieldSet tokenizedLine = tokenizer.process(record); - return fieldSetMapper.process(tokenizedLine); - } - catch (Exception ex) { - // add current line count to message and re-throw - throw new FlatFileParseException("Parsing error at line: " + lineCount + " in resource=" - + resource.getDescription() + ", input=[" + record + "]", ex, record, lineCount); - } - } - return null; - } - - /** - * @return next line (skip comments). - */ - private String readLine() { - - if (reader == null) { - throw new ReaderNotOpenException("Reader must be open before it can be read."); - } - - String line = null; - - try { - line = this.reader.readLine(); - if (line == null) { - return null; - } - lineCount++; - while (isComment(line)) { - line = reader.readLine(); - if (line == null) { - return null; - } - lineCount++; - } - } - catch (IOException e) { - throw new UnexpectedInputException("Unable to read from resource '" + resource + "' at line " + lineCount, - e); - } - return line; - } - - /** - * @return string corresponding to logical record according to - * {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} (might span - * multiple lines in file). - */ - private String readRecord() { - String line = readLine(); - String record = line; - if (line != null) { - while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) { - record = recordSeparatorPolicy.preProcess(record) + (line = readLine()); - } - } - return recordSeparatorPolicy.postProcess(record); - } - - private boolean isComment(String line) { - for (String prefix : comments) { - if (line.startsWith(prefix)) { - return true; - } - } - return false; - } - -} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderAdvancedTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderAdvancedTests.java deleted file mode 100644 index f7a7448c5..000000000 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderAdvancedTests.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.item.file; - -import junit.framework.TestCase; - -import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.item.file.mapping.DefaultFieldSet; -import org.springframework.batch.item.file.mapping.FieldSet; -import org.springframework.batch.item.file.mapping.FieldSetMapper; -import org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper; -import org.springframework.batch.item.file.separator.RecordSeparatorPolicy; -import org.springframework.batch.item.file.transform.LineTokenizer; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; -import org.springframework.util.ClassUtils; - -/** - * Tests for {@link FlatFileItemReader} - skip and restart functionality. - * - * @see FlatFileItemReaderBasicTests - */ -public class FlatFileItemReaderAdvancedTests extends TestCase { - - // object under test - private FlatFileItemReader
reader = new FlatFileItemReader
(); - - // common value used for writing to a file - private String TEST_STRING = "FlatFileInputTemplate-TestData"; - - private ExecutionContext executionContext; - - // simple stub instead of a realistic tokenizer - private LineTokenizer tokenizer = new LineTokenizer() { - public FieldSet process(String line) { - return new DefaultFieldSet(new String[] { line }); - } - }; - - private FieldSetMapper
fieldSetMapper = new PassThroughFieldSetMapper(); - - /** - * Create inputFile, inject mock/stub dependencies for tested object, initialize the tested object - */ - protected void setUp() throws Exception { - - reader.setResource(getInputResource(TEST_STRING)); - reader.setLineTokenizer(tokenizer); - reader.setFieldSetMapper(fieldSetMapper); - reader.setSaveState(true); - // context argument is necessary only for the FileLocator, which - // is mocked - executionContext = new ExecutionContext(); - } - - /** - * Release resources and delete the temporary file - */ - protected void tearDown() throws Exception { - reader.close(null); - } - - private Resource getInputResource(String input) { - return new ByteArrayResource(input.getBytes()); - } - - public void testRestart() throws Exception { - - reader.close(null); - reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - reader.open(executionContext); - - // read some records - reader.read(); - reader.read(); - reader.read(); - reader.read(); - - // get restart data - reader.update(executionContext); - assertEquals(4, executionContext.getLong(ClassUtils.getShortName(FlatFileItemReader.class) - + ".read.count")); - // close input - reader.close(executionContext); - - reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - - // init for restart - reader.open(executionContext); - - // read remaining records - assertEquals("[testLine5]", reader.read().toString()); - assertEquals("[testLine6]", reader.read().toString()); - - reader.update(executionContext); - assertEquals(6, executionContext.getLong(ClassUtils.getShortName(FlatFileItemReader.class) - + ".read.count")); - } - - public void testRestartWithCustomRecordSeparatorPolicy() throws Exception { - reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { - // 1 record = 2 lines - boolean pair = true; - - public boolean isEndOfRecord(String line) { - pair = !pair; - return pair; - } - - public String postProcess(String record) { - return record; - } - - public String preProcess(String record) { - return record; - } - }); - - reader.open(executionContext); - - assertEquals("[testLine1testLine2]", reader.read().toString()); - assertEquals("[testLine3testLine4]", reader.read().toString()); - - reader.update(executionContext); - - reader.close(executionContext); - - reader.open(executionContext); - - assertEquals("[testLine5testLine6]", reader.read().toString()); - } - - public void testRestartWithHeader() throws Exception { - - reader.close(null); - reader.setResource(getInputResource("header\ntestLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - reader.setFirstLineIsHeader(true); - reader.open(executionContext); - - // read some records - reader.read(); - reader.read(); - // get restart data - reader.update(executionContext); - // read next two records - reader.read(); - reader.read(); - - assertEquals(2, executionContext.getLong(ClassUtils.getShortName(FlatFileItemReader.class) - + ".read.count")); - // close input - reader.close(executionContext); - - reader.setResource(getInputResource("header\ntestLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - - // init for restart - reader.open(executionContext); - - // read remaining records - assertEquals("[testLine3]", reader.read().toString()); - assertEquals("[testLine4]", reader.read().toString()); - - reader.update(executionContext); - assertEquals(4, executionContext.getLong(ClassUtils.getShortName(FlatFileItemReader.class) - + ".read.count")); - } - - public void testRestartWithSkippedLines() throws Exception { - - reader.close(null); - reader.setResource(getInputResource("header\nignoreme\n\ntestLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - reader.setLinesToSkip(2); - reader.open(executionContext); - - // read some records - reader.read(); - reader.read(); - // get restart data - reader.update(executionContext); - // read next two records - reader.read(); - reader.read(); - - assertEquals(2, executionContext.getLong(ClassUtils.getShortName(FlatFileItemReader.class) - + ".read.count")); - // close input - reader.close(executionContext); - - reader.setResource(getInputResource("header\nignoreme\ntestLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - - // init for restart - reader.open(executionContext); - - // read remaining records - assertEquals("[testLine3]", reader.read().toString()); - assertEquals("[testLine4]", reader.read().toString()); - - reader.update(executionContext); - assertEquals(4, executionContext.getLong(ClassUtils.getShortName(FlatFileItemReader.class) - + ".read.count")); - } -} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderBasicTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderBasicTests.java deleted file mode 100644 index 83f034bc7..000000000 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderBasicTests.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -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 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; -import org.springframework.batch.item.file.mapping.DefaultFieldSet; -import org.springframework.batch.item.file.mapping.FieldSet; -import org.springframework.batch.item.file.mapping.FieldSetMapper; -import org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper; -import org.springframework.batch.item.file.separator.DefaultRecordSeparatorPolicy; -import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; -import org.springframework.batch.item.file.transform.LineTokenizer; -import org.springframework.core.io.AbstractResource; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; - -/** - * Tests for {@link FlatFileItemReader} - the fundamental item reading functionality. - * - * @see FlatFileItemReaderAdvancedTests - * @author Dave Syer - */ -public class FlatFileItemReaderBasicTests { - - // object under test - private FlatFileItemReader
itemReader = new FlatFileItemReader
(); - - // common value used for writing to a file - private String TEST_STRING = "FlatFileInputTemplate-TestData"; - private String TEST_OUTPUT = "[FlatFileInputTemplate-TestData]"; - - private ExecutionContext executionContext; - - // simple stub instead of a realistic tokenizer - private LineTokenizer tokenizer = new LineTokenizer() { - public FieldSet process(String line) { - return new DefaultFieldSet(new String[] { line }); - } - }; - - private FieldSetMapper
fieldSetMapper = new PassThroughFieldSetMapper(); - - /** - * Create inputFile, inject mock/stub dependencies for tested object, initialize the tested object - */ - @Before - public void setUp() throws Exception { - - itemReader.setResource(getInputResource(TEST_STRING)); - itemReader.setLineTokenizer(tokenizer); - itemReader.setFieldSetMapper(fieldSetMapper); - itemReader.afterPropertiesSet(); - - executionContext = new ExecutionContext(); - } - - /** - * Release resources. - */ - @After - public void tearDown() throws Exception { - itemReader.close(null); - } - - private Resource getInputResource(String input) { - return new ByteArrayResource(input.getBytes()); - } - - /** - * Regular usage of read method - */ - @Test - public void testRead() throws Exception { - itemReader.open(executionContext); - assertEquals("[FlatFileInputTemplate-TestData]", itemReader.read().toString()); - } - - /** - * Regular usage of read method - */ - @Test - public void testReadExhausted() throws Exception { - itemReader.open(executionContext); - assertEquals("[FlatFileInputTemplate-TestData]", itemReader.read().toString()); - assertEquals(null, itemReader.read()); - } - - /** - * Regular usage of read method - */ - @Test - public void testReadWithTokenizerError() throws Exception { - itemReader.setLineTokenizer(new LineTokenizer() { - public FieldSet process(String line) { - throw new RuntimeException("foo"); - } - }); - try { - itemReader.open(executionContext); - itemReader.read(); - fail("Expected ParsingException"); - } catch (FlatFileParseException e) { - assertEquals(e.getInput(), TEST_STRING); - assertEquals(e.getLineNumber(), 1); - } - } - - @Test - public void testReadWithMapperError() throws Exception { - itemReader.setFieldSetMapper(new FieldSetMapper
() { - public FieldSet process(FieldSet fs) { - throw new RuntimeException("foo"); - } - }); - - try { - itemReader.open(executionContext); - itemReader.read(); - fail("Expected ParsingException"); - } catch (FlatFileParseException e) { - assertEquals(e.getInput(), TEST_STRING); - assertEquals(e.getLineNumber(), 1); - } - } - - @Test - public void testReadBeforeOpen() throws Exception { - itemReader = new FlatFileItemReader
(); - itemReader.setResource(getInputResource(TEST_STRING)); - itemReader.setFieldSetMapper(fieldSetMapper); - try { - itemReader.read(); - fail("Expected ReaderNotOpenException"); - } catch (ReaderNotOpenException e) { - assertTrue(contains(e.getMessage(), "open")); - } - } - - @Test - public void testCloseBeforeOpen() throws Exception { - itemReader = new FlatFileItemReader
(); - itemReader.setResource(getInputResource(TEST_STRING)); - itemReader.setFieldSetMapper(fieldSetMapper); - itemReader.close(null); - // The open does not happen automatically on a read... - itemReader.open(executionContext); - assertEquals("[FlatFileInputTemplate-TestData]", itemReader.read().toString()); - } - - @Test - public void testInitializationWithNullResource() throws Exception { - itemReader = new FlatFileItemReader
(); - try { - itemReader.afterPropertiesSet(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } - } - - @Test - public void testOpenTwiceHasNoEffect() throws Exception { - itemReader.open(executionContext); - testRead(); - } - - @Test - public void testSetValidEncoding() throws Exception { - itemReader = new FlatFileItemReader
(); - itemReader.setEncoding("UTF-8"); - itemReader.setResource(getInputResource(TEST_STRING)); - itemReader.setFieldSetMapper(fieldSetMapper); - itemReader.open(executionContext); - testRead(); - } - - @Test - public void testSetNullEncoding() throws Exception { - itemReader = new FlatFileItemReader
(); - itemReader.setEncoding(null); - itemReader.setResource(getInputResource(TEST_STRING)); - try { - itemReader.open(executionContext); - fail("Expected IllegalArgumentException"); - } catch (ItemStreamException e) { - // expected - } - } - - @Test - public void testSetInvalidEncoding() throws Exception { - itemReader = new FlatFileItemReader
(); - itemReader.setEncoding("foo"); - itemReader.setResource(getInputResource(TEST_STRING)); - try { - itemReader.open(executionContext); - fail("Expected BatchEnvironmentException"); - } catch (ItemStreamException e) { - // expected - assertEquals("Failed to initialize the reader", e.getMessage()); - assertEquals("foo", e.getCause().getCause().getMessage()); - } - } - - @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[] { "%" }); - testRead(); - } - - /** - * 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"; - - LineCallbackHandler headerCallback = createStrictMock(LineCallbackHandler.class); - headerCallback.handleLine("name1|name2"); - replay(headerCallback); - - itemReader = new FlatFileItemReader
(); - itemReader.setResource(getInputResource(INPUT)); - itemReader.setLineTokenizer(new DelimitedLineTokenizer('|')); - itemReader.setFieldSetMapper(fieldSetMapper); - itemReader.setFirstLineIsHeader(true); - itemReader.setHeaderCallback(headerCallback); - itemReader.afterPropertiesSet(); - itemReader.open(executionContext); - - FieldSet fs = itemReader.read(); - assertEquals("value1", fs.readString("name1")); - assertEquals("value2", fs.readString("name2")); - - fs = itemReader.read(); - assertEquals("value3", fs.readString("name1")); - assertEquals("value4", fs.readString("name2")); - - verify(headerCallback); - } - - /** - * 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"; - - itemReader = new FlatFileItemReader
(); - itemReader.setResource(getInputResource(INPUT)); - itemReader.setLineTokenizer(new DelimitedLineTokenizer(' ')); - itemReader.setFieldSetMapper(fieldSetMapper); - itemReader.setLinesToSkip(1); - itemReader.afterPropertiesSet(); - itemReader.open(executionContext); - - FieldSet fs = itemReader.read(); - assertEquals("one", fs.readString(0)); - assertEquals("two", fs.readString(1)); - - fs = itemReader.read(); - assertEquals("three", fs.readString(0)); - assertEquals("four", fs.readString(1)); - } - - @Test - public void testNonExistantResource() throws Exception { - - Resource resource = new NonExistentResource(); - - FlatFileItemReader
testReader = new FlatFileItemReader
(); - testReader.setResource(resource); - testReader.setLineTokenizer(tokenizer); - testReader.setFieldSetMapper(fieldSetMapper); - testReader.setResource(resource); - - // afterPropertiesSet should only throw an exception if the Resource is null - testReader.afterPropertiesSet(); - - testReader.open(executionContext); - assertNull(testReader.read()); - - } - - @Test - public void testRuntimeFileCreation() throws Exception { - - Resource resource = new NonExistentResource(); - - FlatFileItemReader
testReader = new FlatFileItemReader
(); - testReader.setResource(resource); - testReader.setLineTokenizer(tokenizer); - testReader.setFieldSetMapper(fieldSetMapper); - testReader.setResource(resource); - - // afterPropertiesSet should only throw an exception if the Resource is null - testReader.afterPropertiesSet(); - - // replace the resource to simulate runtime resource creation - testReader.setResource(getInputResource(TEST_STRING)); - testReader.open(executionContext); - assertEquals(TEST_OUTPUT, testReader.read().toString()); - } - - private boolean contains(String str, String searchStr) { - return str.indexOf(searchStr) != -1; - } - - private static class NonExistentResource extends AbstractResource { - - public NonExistentResource() { - } - - public boolean exists() { - return false; - } - - public String getDescription() { - return "NonExistantResource"; - } - - public InputStream getInputStream() throws IOException { - return null; - } - } -} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderCommonTests.java deleted file mode 100644 index fc23f9166..000000000 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderCommonTests.java +++ /dev/null @@ -1,46 +0,0 @@ -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; -import org.springframework.batch.item.sample.Foo; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; -import org.junit.runner.RunWith; -import org.junit.internal.runners.JUnit4ClassRunner; - -@RunWith(JUnit4ClassRunner.class) -public class FlatFileItemReaderCommonTests extends CommonItemStreamItemReaderTests { - - private static final String FOOS = "1 \n 2 \n 3 \n 4 \n 5 \n"; - - protected ItemReader getItemReader() throws Exception { - FlatFileItemReader tested = new FlatFileItemReader(); - Resource resource = new ByteArrayResource(FOOS.getBytes()); - tested.setResource(resource); - tested.setFieldSetMapper(new FieldSetMapper() { - public Foo process(FieldSet fs) { - Foo foo = new Foo(); - foo.setValue(fs.readInt(0)); - return foo; - } - }); - - tested.setSaveState(true); - tested.afterPropertiesSet(); - 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()); - } - -} diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java index 23340ac68..ec0f4c4d9 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java @@ -3,15 +3,14 @@ package org.springframework.batch.sample.support; import java.io.IOException; import java.io.Writer; - import org.springframework.batch.item.file.FileWriterCallback; -import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.FlatFileItemWriter; import org.springframework.batch.item.file.LineCallbackHandler; +import org.springframework.batch.item.file.ResourceLineReader; import org.springframework.util.Assert; /** - * Designed to be registered with both {@link FlatFileItemReader} and + * Designed to be registered with both {@link ResourceLineReader} and * {@link FlatFileItemWriter} and copy header line from input file to output * file. */ diff --git a/spring-batch-samples/src/main/resources/jobs/beanWrapperMapperSampleJob.xml b/spring-batch-samples/src/main/resources/jobs/beanWrapperMapperSampleJob.xml index a92d27f4f..caab7f61c 100644 --- a/spring-batch-samples/src/main/resources/jobs/beanWrapperMapperSampleJob.xml +++ b/spring-batch-samples/src/main/resources/jobs/beanWrapperMapperSampleJob.xml @@ -35,20 +35,27 @@ - - + + - - + + + + + + - + - - - + + + + + + diff --git a/spring-batch-samples/src/main/resources/jobs/compositeItemWriterSampleJob.xml b/spring-batch-samples/src/main/resources/jobs/compositeItemWriterSampleJob.xml index 4e5ba7b11..680d90d7c 100644 --- a/spring-batch-samples/src/main/resources/jobs/compositeItemWriterSampleJob.xml +++ b/spring-batch-samples/src/main/resources/jobs/compositeItemWriterSampleJob.xml @@ -45,11 +45,15 @@ + class="org.springframework.batch.item.file.ResourceLineReader"> - - + + + + + + + class="org.springframework.batch.item.file.ResourceLineReader"> - - - + + + + + + + + + + - - - + class="org.springframework.batch.item.file.ResourceLineReader"> - - - + + + + + + + + + + - - - - + - - - + + + + + + + + + + - - - - - + + diff --git a/spring-batch-samples/src/main/resources/jobs/multiResourceJob.xml b/spring-batch-samples/src/main/resources/jobs/multiResourceJob.xml index 5b29923ad..4233ea0ad 100644 --- a/spring-batch-samples/src/main/resources/jobs/multiResourceJob.xml +++ b/spring-batch-samples/src/main/resources/jobs/multiResourceJob.xml @@ -42,11 +42,15 @@ autowire-candidate="false" /> + class="org.springframework.batch.item.file.ResourceLineReader"> - - + + + + + + + class="org.springframework.batch.item.file.ResourceLineReader"> - - - - + + + + + + + + - - - - - - + + + + + + + + + diff --git a/spring-batch-samples/src/main/resources/jobs/parallelJob.xml b/spring-batch-samples/src/main/resources/jobs/parallelJob.xml index 2eb0b42af..25e43fb85 100644 --- a/spring-batch-samples/src/main/resources/jobs/parallelJob.xml +++ b/spring-batch-samples/src/main/resources/jobs/parallelJob.xml @@ -66,11 +66,15 @@ + class="org.springframework.batch.item.file.ResourceLineReader"> - - + + + + + + + class="org.springframework.batch.item.file.ResourceLineReader"> - - + + + + + + diff --git a/spring-batch-samples/src/main/resources/jobs/tradeJobIo.xml b/spring-batch-samples/src/main/resources/jobs/tradeJobIo.xml index 04455ec3f..962be6b84 100644 --- a/spring-batch-samples/src/main/resources/jobs/tradeJobIo.xml +++ b/spring-batch-samples/src/main/resources/jobs/tradeJobIo.xml @@ -38,13 +38,17 @@ - - - - + + + + + + + diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/sample/FixedLengthImportJobFunctionalTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/sample/FixedLengthImportJobFunctionalTests.java index 672a88057..7140fcddf 100644 --- a/spring-batch-samples/src/test/java/org/springframework/batch/sample/FixedLengthImportJobFunctionalTests.java +++ b/spring-batch-samples/src/test/java/org/springframework/batch/sample/FixedLengthImportJobFunctionalTests.java @@ -29,7 +29,8 @@ import javax.sql.DataSource; import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.item.file.FlatFileItemReader; +import org.springframework.batch.item.file.ResourceLineReader; +import org.springframework.batch.item.file.mapping.DefaultLineMapper; import org.springframework.batch.item.file.mapping.FieldSetMapper; import org.springframework.batch.item.file.transform.LineTokenizer; import org.springframework.batch.sample.domain.trade.Trade; @@ -52,7 +53,7 @@ public class FixedLengthImportJobFunctionalTests extends AbstractValidatingBatch //auto-injected attributes private SimpleJdbcTemplate simpleJdbcTemplate; private Resource fileLocator; - private FlatFileItemReader inputSource; + private ResourceLineReader inputSource; private LineTokenizer lineTokenizer; @Autowired @@ -70,12 +71,15 @@ public class FixedLengthImportJobFunctionalTests extends AbstractValidatingBatch public void onSetUp() throws Exception { simpleJdbcTemplate.update("delete from TRADE"); fileLocator = new ClassPathResource("data/fixedLengthImportJob/input/20070122.teststream.ImportTradeDataStep.txt"); - inputSource = new FlatFileItemReader(); + inputSource = new ResourceLineReader(); FieldSetMapper mapper = new TradeFieldSetMapper(); - inputSource.setFieldSetMapper(mapper); + DefaultLineMapper lineMapper = new DefaultLineMapper(); + lineMapper.setLineTokenizer(lineTokenizer); + lineMapper.setFieldSetMapper(mapper); + inputSource.setLineMapper(lineMapper); + - inputSource.setLineTokenizer(lineTokenizer); inputSource.setResource(fileLocator); }