From ad85f5517576a685cf7216dd9809a9d663e21c8a Mon Sep 17 00:00:00 2001 From: dsyer Date: Thu, 22 Nov 2007 07:57:30 +0000 Subject: [PATCH] RESOLVED - issue BATCH-211: Specify column names in flat file on first line http://opensource.atlassian.com/projects/spring/browse/BATCH-211 Patch applied with some modifications. --- .../batch/io/file/FieldSet.java | 7 + .../support/DefaultFlatFileInputSource.java | 1 - .../support/SimpleFlatFileInputSource.java | 482 +++++----- .../transform/AbstractLineTokenizer.java | 150 +-- .../file/support/transform/LineTokenizer.java | 2 +- .../batch/io/file/FieldSetTests.java | 854 +++++++++--------- .../SimpleFlatFileInputSourceTests.java | 542 ++++++----- .../transform/CommonLineTokenizerTests.java | 37 + .../src/main/resources/jobs/hibernateJob.xml | 4 + 9 files changed, 1121 insertions(+), 958 deletions(-) create mode 100644 infrastructure/src/test/java/org/springframework/batch/io/file/support/transform/CommonLineTokenizerTests.java diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java b/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java index 03d8a3069..ea299b7f0 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java @@ -74,6 +74,13 @@ public final class FieldSet { return (String[]) names.toArray(); } + /** + * @return fields wrapped by this 'FieldSet' instance as String values. + */ + public String[] getValues() { + return tokens; + } + /** * Read the {@link String} value at index 'index'. * diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSource.java b/infrastructure/src/main/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSource.java index 6206e31e5..24d0b9e28 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSource.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSource.java @@ -77,7 +77,6 @@ public class DefaultFlatFileInputSource extends SimpleFlatFileInputSource implem */ public void restoreFrom(RestartData data) { - //TODO this does not look very nice... if (data==null || data.getProperties() == null || data.getProperties().getProperty(READ_STATISTICS_NAME) == null || diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSource.java b/infrastructure/src/main/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSource.java index ff6853592..0728e185d 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSource.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSource.java @@ -1,217 +1,265 @@ -/* - * 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.io.file.support; - -import java.io.IOException; - -import org.springframework.batch.io.InputSource; -import org.springframework.batch.io.exception.FlatFileParsingException; -import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.FieldSetMapper; -import org.springframework.batch.io.file.support.separator.RecordSeparatorPolicy; -import org.springframework.batch.io.file.support.transform.DelimitedLineTokenizer; -import org.springframework.batch.io.file.support.transform.LineTokenizer; -import org.springframework.batch.item.ResourceLifecycle; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; - -/** - * This class represents a basic input source, that reads data from the file and - * returns it as structured tuples in the form of{@link FieldSet} instances. - * 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 SimpleFlatFileInputSource} is not thread safe because it maintains - * state in the form of a {@link ResourceLineReader}. Be careful to configure a - * {@link SimpleFlatFileInputSource} using an appropriate factory or scope so - * that it is not shared between threads.
- * - * @see FieldSetInputSource - * - * @author Dave Syer - */ -public class SimpleFlatFileInputSource implements InputSource, InitializingBean, DisposableBean { - - // default encoding for input files - set to ISO-8859-1 - public static final String DEFAULT_CHARSET = "ISO-8859-1"; - - private Resource resource; - - /** - * Encapsulates the state of the input source. If it is null then we are - * uninitialized. - */ - private ResourceLineReader reader; - - private RecordSeparatorPolicy recordSeparatorPolicy; - - private String[] comments; - - private LineTokenizer tokenizer = new DelimitedLineTokenizer(); - - private FieldSetMapper fieldSetMapper; - - private String encoding = DEFAULT_CHARSET; - - /** - * Setter for resource property. The location of an input stream that can be - * read. - * @param resource - * @throws IOException - */ - public void setResource(Resource resource) throws IOException { - 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); - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(resource); - Assert.state(resource.exists(), "Resource must exist: [" + resource + "]"); - Assert.notNull(fieldSetMapper, "FieldSetMapper must not be null."); - } - - /** - * Initialize the reader if necessary. - */ - public void open() { - if (reader == null) { - reader = new ResourceLineReader(resource, encoding); - if (recordSeparatorPolicy!=null) { - reader.setRecordSeparatorPolicy(recordSeparatorPolicy); - } - if (comments!=null) { - reader.setComments(comments); - } - reader.open(); - } - } - - /** - * Close and null out the reader. - * - * @see ResourceLifecycle - */ - public void close() { - try { - if (reader != null) { - reader.close(); - } - } - finally { - reader = null; - } - } - - /** - * Calls close to ensure that bean factories can close and always release - * resources. - * - * @see org.springframework.beans.factory.DisposableBean#destroy() - */ - public void destroy() throws Exception { - close(); - } - - // Reads first valid line. - protected String readLine() { - return (String) getReader().read(); - } - - /** - * A wrapper for {@link #readFieldSet()} to make this into a real - * {@link InputSource}. - * - * @see org.springframework.batch.io.InputSource#read() - */ - public Object read() { - String line = readLine(); - - if (line != null) { - try { - FieldSet tokenizedLine = tokenizer.tokenize(line); - return fieldSetMapper.mapLine(tokenizedLine); - } - catch (RuntimeException ex) { - // add current line count to message and re-throw - throw new FlatFileParsingException("Parsing error", ex, line, - getReader().getCurrentLineCount()); - } - } - return null; - } - - /** - * Setter for the encoding for this input source. Default value is - * {@value #DEFAULT_CHARSET}. - * - * @param encoding a properties object which possibly contains the encoding - * for this input file; - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - /** - * Sets descriptor for this input template. - */ - public void setTokenizer(LineTokenizer lineTokenizer) { - this.tokenizer = lineTokenizer; - } - - /** - * Set the FieldSetMapper to be used for each line. - * - * @param fieldSetMapper - */ - public void setFieldSetMapper(FieldSetMapper fieldSetMapper) { - this.fieldSetMapper = fieldSetMapper; - } - - // Returns object representing state of the input template. - protected ResourceLineReader getReader() { - if (reader == null) { - open(); - // reader is now not null, or else an exception is thrown - } - return reader; - } - -} +/* + * 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.io.file.support; + +import java.io.IOException; + +import org.springframework.batch.io.InputSource; +import org.springframework.batch.io.exception.FlatFileParsingException; +import org.springframework.batch.io.file.FieldSet; +import org.springframework.batch.io.file.FieldSetMapper; +import org.springframework.batch.io.file.support.separator.RecordSeparatorPolicy; +import org.springframework.batch.io.file.support.transform.AbstractLineTokenizer; +import org.springframework.batch.io.file.support.transform.DelimitedLineTokenizer; +import org.springframework.batch.io.file.support.transform.LineTokenizer; +import org.springframework.batch.item.ResourceLifecycle; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; + +/** + * This class represents a basic input source, that reads data from the file and + * returns it as structured tuples in the form of{@link FieldSet} instances. + * 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 SimpleFlatFileInputSource} is not thread safe because it maintains + * state in the form of a {@link ResourceLineReader}. Be careful to configure a + * {@link SimpleFlatFileInputSource} using an appropriate factory or scope so + * that it is not shared between threads.
+ * + * @see FieldSetInputSource + * + * @author Dave Syer + */ +public class SimpleFlatFileInputSource implements InputSource, + InitializingBean, DisposableBean { + + // default encoding for input files - set to ISO-8859-1 + public static final String DEFAULT_CHARSET = "ISO-8859-1"; + + private Resource resource; + + /** + * Encapsulates the state of the input source. If it is null then we are + * uninitialized. + */ + private ResourceLineReader reader; + + private RecordSeparatorPolicy recordSeparatorPolicy; + + private String[] comments; + + private LineTokenizer tokenizer = new DelimitedLineTokenizer(); + + private FieldSetMapper fieldSetMapper; + + private String encoding = DEFAULT_CHARSET; + + private boolean firstLineIsHeader = false; + + private int linesToSkip = 0; + + /** + * Setter for resource property. The location of an input stream that can be + * read. + * + * @param resource + * @throws IOException + */ + public void setResource(Resource resource) throws IOException { + 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); + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(resource); + Assert.state(resource.exists(), "Resource must exist: [" + resource + + "]"); + Assert.notNull(fieldSetMapper, "FieldSetMapper must not be null."); + } + + /** + * Initialize the reader if necessary. + */ + public void open() { + if (reader == null) { + reader = new ResourceLineReader(resource, encoding); + if (recordSeparatorPolicy != null) { + reader.setRecordSeparatorPolicy(recordSeparatorPolicy); + } + if (comments != null) { + reader.setComments(comments); + } + reader.open(); + } + + for (int i = 0; i < linesToSkip; i++) { + readLine(); + } + + if (firstLineIsHeader) { + // skip the header + String firstLine = readLine(); + // set names in tokenizer if they haven't been set already + if (tokenizer instanceof AbstractLineTokenizer + && !((AbstractLineTokenizer) tokenizer).hasNames()) { + String[] names = tokenizer.tokenize(firstLine).getValues(); + ((AbstractLineTokenizer) tokenizer).setNames(names); + } + } + } + + /** + * Close and null out the reader. + * + * @see ResourceLifecycle + */ + public void close() { + try { + if (reader != null) { + reader.close(); + } + } finally { + reader = null; + } + } + + /** + * Calls close to ensure that bean factories can close and always release + * resources. + * + * @see org.springframework.beans.factory.DisposableBean#destroy() + */ + public void destroy() throws Exception { + close(); + } + + // Reads first valid line. + protected String readLine() { + return (String) getReader().read(); + } + + /** + * A wrapper for {@link #readFieldSet()} to make this into a real + * {@link InputSource}. + * + * @see org.springframework.batch.io.InputSource#read() + */ + public Object read() { + String line = readLine(); + + if (line != null) { + try { + FieldSet tokenizedLine = tokenizer.tokenize(line); + return fieldSetMapper.mapLine(tokenizedLine); + } catch (RuntimeException ex) { + // add current line count to message and re-throw + throw new FlatFileParsingException("Parsing error", ex, line, + getReader().getCurrentLineCount()); + } + } + return null; + } + + /** + * Setter for the encoding for this input source. Default value is + * {@value #DEFAULT_CHARSET}. + * + * @param encoding + * a properties object which possibly contains the encoding for + * this input file; + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * Sets descriptor for this input template. + */ + public void setTokenizer(LineTokenizer lineTokenizer) { + this.tokenizer = lineTokenizer; + } + + /** + * Set the FieldSetMapper to be used for each line. + * + * @param fieldSetMapper + */ + public void setFieldSetMapper(FieldSetMapper fieldSetMapper) { + this.fieldSetMapper = fieldSetMapper; + } + + // Returns object representing state of the input template. + protected ResourceLineReader getReader() { + if (reader == null) { + open(); + // reader is now not null, or else an exception is thrown + } + return reader; + } + + /** + * 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; + } + + /** + * 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; + } + +} diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/AbstractLineTokenizer.java b/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/AbstractLineTokenizer.java index 636ef2977..e1f943140 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/AbstractLineTokenizer.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/AbstractLineTokenizer.java @@ -1,67 +1,83 @@ -/* - * 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.io.file.support.transform; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.batch.io.file.FieldSet; - - -public abstract class AbstractLineTokenizer implements LineTokenizer { - - protected String[] names = new String[0]; - - /** - * Setter for column names. Optional, but if set, then all lines must have - * as many or fewer tokens. - * - * @param names - */ - public void setNames(String[] names) { - this.names = names; - } - - /** - * Yields the tokens resulting from the splitting of the supplied - * line. - * - * @param line the line to be tokenised (can be null) - * - * @return the resulting tokens - */ - public FieldSet tokenize(String line) { - - if (line == null || line.length()==0) { - return new FieldSet(new String[0]); - } - - List tokens = new ArrayList(doTokenize(line)); - for (int i=tokens.size(); itrue if column names have been specified + * @see #setNames(String[]) + */ + public boolean hasNames() { + if (names != null && names.length > 0) { + return true; + } + return false; + } + + /** + * Yields the tokens resulting from the splitting of the supplied + * line. + * + * @param line the line to be tokenised (can be null) + * + * @return the resulting tokens + */ + public FieldSet tokenize(String line) { + + if (line == null || line.length()==0) { + return new FieldSet(new String[0]); + } + + List tokens = new ArrayList(doTokenize(line)); + for (int i=tokens.size(); iline. * - * @param line the line to be tokenised (can be null) + * @param line the line to be tokenized (can be null) * * @return the resulting tokens */ diff --git a/infrastructure/src/test/java/org/springframework/batch/io/file/FieldSetTests.java b/infrastructure/src/test/java/org/springframework/batch/io/file/FieldSetTests.java index f351fb673..19b7c7b00 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/file/FieldSetTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/file/FieldSetTests.java @@ -1,423 +1,431 @@ -/* - * 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.io.file; - -import java.math.BigDecimal; -import java.text.ParseException; - -import junit.framework.TestCase; - -import org.springframework.batch.io.file.FieldSet; - -public class FieldSetTests extends TestCase { - FieldSet fieldSet; - - String[] tokens; - - String[] names; - - protected void setUp() throws Exception { - super.setUp(); - - tokens = new String[] { "TestString", "true", "C", "10", "-472", "354224", "543", "124.3", "424.3", "324", - null, "2007-10-12", "12-10-2007", "" }; - names = new String[] { "String", "Boolean", "Char", "Byte", "Short", "Integer", "Long", "Float", "Double", - "BigDecimal", "Null", "Date", "DatePattern", "BlankInput" }; - - fieldSet = new FieldSet(tokens, names); - assertEquals(14, fieldSet.getFieldCount()); - - } - - public void testNames() throws Exception { - assertEquals(fieldSet.getFieldCount(), fieldSet.getNames().length); - } - - public void testNamesNotKnown() throws Exception { - fieldSet = new FieldSet(new String[]{"foo"}); - try { - fieldSet.getNames(); - fail("Expected IllegalStateException"); - } catch (IllegalStateException e) { - // expected - } - } - - public void testReadString() throws ParseException { - - assertEquals(fieldSet.readString(0), "TestString"); - assertEquals(fieldSet.readString("String"), "TestString"); - - } - - public void testReadChar() throws Exception { - - assertTrue(fieldSet.readChar(2) == 'C'); - assertTrue(fieldSet.readChar("Char") == 'C'); - - } - - public void testReadBooleanTrue() throws Exception { - - assertTrue(fieldSet.readBoolean(1)); - assertTrue(fieldSet.readBoolean("Boolean")); - - } - - public void testReadByte() throws Exception { - - assertTrue(fieldSet.readByte(3) == 10); - assertTrue(fieldSet.readByte("Byte") == 10); - - } - - public void testReadShort() throws Exception { - - assertTrue(fieldSet.readShort(4) == -472); - assertTrue(fieldSet.readShort("Short") == -472); - - } - - public void testReadFloat() throws Exception { - - assertTrue(fieldSet.readFloat(7) == 124.3F); - assertTrue(fieldSet.readFloat("Float") == 124.3F); - - } - - public void testReadDouble() throws Exception { - - assertTrue(fieldSet.readDouble(8) == 424.3); - assertTrue(fieldSet.readDouble("Double") == 424.3); - - } - - public void testReadBigDecimal() throws Exception { - - BigDecimal bd = new BigDecimal(324); - assertEquals(fieldSet.readBigDecimal(9), bd); - assertEquals(fieldSet.readBigDecimal("BigDecimal"), bd); - - } - - public void testReadBigDecimalWithDefaultvalue() throws Exception { - - BigDecimal bd = new BigDecimal(324); - assertEquals(bd, fieldSet.readBigDecimal(10, bd)); - assertEquals(bd, fieldSet.readBigDecimal("Null", bd)); - - } - - public void testReadNonExistentField() throws Exception { - - try { - fieldSet.readString("something"); - fail("field set returns value even value was never put in!"); - } - catch (IllegalArgumentException e) { - assertTrue(e.getMessage().indexOf("something") > 0); - } - - } - - public void testReadIndexOutOfRange() throws Exception { - - try { - fieldSet.readShort(-1); - fail("field set returns value even index is out of range!"); - } - catch (IndexOutOfBoundsException e) { - assertTrue(true); - } - - try { - fieldSet.readShort(99); - fail("field set returns value even index is out of range!"); - } - catch (Exception e) { - assertTrue(true); - } - } - - public void testReadBooleanWithTrueValue() { - assertTrue(fieldSet.readBoolean(1, "true")); - assertFalse(fieldSet.readBoolean(1, "incorrect trueValue")); - - assertTrue(fieldSet.readBoolean("Boolean", "true")); - assertFalse(fieldSet.readBoolean("Boolean", "incorrect trueValue")); - } - - public void testReadBooleanFalse() { - fieldSet = new FieldSet(new String[] { "false" }); - assertFalse(fieldSet.readBoolean(0)); - } - - public void testReadCharException() { - try { - fieldSet.readChar(1); - fail("the value read was not a character, exception expected"); - } - catch (IllegalArgumentException expected) { - assertTrue(true); - } - - try { - fieldSet.readChar("Boolean"); - fail("the value read was not a character, exception expected"); - } - catch (IllegalArgumentException expected) { - assertTrue(true); - } - } - - public void testReadInt() throws Exception { - assertEquals(354224, fieldSet.readInt(5)); - assertEquals(354224, fieldSet.readInt("Integer")); - } - - public void testReadBlankInt(){ - - //Trying to parse a blank field as an integer, but without a default - //value should throw a NumberFormatException - try{ - fieldSet.readInt(13); - fail(); - } - catch(NumberFormatException ex){ - //expected - } - - try{ - fieldSet.readInt("BlankInput"); - fail(); - } - catch(NumberFormatException ex){ - //expected - } - - } - - public void testReadLong() throws Exception { - assertEquals(543, fieldSet.readLong(6)); - assertEquals(543, fieldSet.readLong("Long")); - } - - public void testReadIntWithNullValue() { - assertEquals(5, fieldSet.readInt(10, 5)); - assertEquals(5, fieldSet.readInt("Null", 5)); - } - - public void testReadIntWithDefaultAndNotNull() throws Exception { - assertEquals(354224, fieldSet.readInt(5, 5)); - assertEquals(354224, fieldSet.readInt("Integer", 5)); - } - - public void testReadLongWithNullValue() { - int defaultValue = 5; - int indexOfNull = 10; - int indexNotNull = 6; - String nameNull = "Null"; - String nameNotNull = "Long"; - long longValueAtIndex = 543; - - assertEquals(fieldSet.readLong(indexOfNull, defaultValue), defaultValue); - assertEquals(fieldSet.readLong(indexNotNull, defaultValue), longValueAtIndex); - - assertEquals(fieldSet.readLong(nameNull, defaultValue), defaultValue); - assertEquals(fieldSet.readLong(nameNotNull, defaultValue), longValueAtIndex); - } - - public void testReadBigDecimalInvalid() { - int index = 0; - - try { - fieldSet.readBigDecimal(index); - fail("field value is not a number, exception expected"); - } - catch (IllegalArgumentException e) { - assertTrue(e.getMessage().indexOf("TestString") > 0); - } - - } - - public void testReadBigDecimalByNameInvalid() throws Exception { - try { - fieldSet.readBigDecimal("String"); - fail("field value is not a number, exception expected"); - } - catch (IllegalArgumentException e) { - assertTrue(e.getMessage().indexOf("TestString") > 0); - assertTrue(e.getMessage().indexOf("name: [String]") > 0); - } - } - - public void testReadDate() throws Exception { - assertNotNull(fieldSet.readDate(11)); - assertNotNull(fieldSet.readDate("Date")); - } - - public void testReadDateInvalid() throws Exception { - - try { - fieldSet.readDate(0); - fail("field value is not a date, exception expected"); - } - catch (IllegalArgumentException e) { - assertTrue(e.getMessage().indexOf("TestString") > 0); - } - - } - - public void testReadDateInvalidByName() throws Exception { - - try { - fieldSet.readDate("String"); - fail("field value is not a date, exception expected"); - } - catch (IllegalArgumentException e) { - assertTrue(e.getMessage().indexOf("name: [String]") > 0); - } - - } - - public void testReadDateInvalidWithPattern() throws Exception { - - try { - fieldSet.readDate(0, "dd-MM-yyyy"); - fail("field value is not a date, exception expected"); - } - catch (IllegalArgumentException e) { - assertTrue(e.getMessage().indexOf("dd-MM-yyyy") > 0); - } - } - - public void testReadDateByNameInvalidWithPattern() throws Exception { - - try { - fieldSet.readDate("String", "dd-MM-yyyy"); - fail("field value is not a date, exception expected"); - } - catch (IllegalArgumentException e) { - assertTrue(e.getMessage().indexOf("dd-MM-yyyy") > 0); - assertTrue(e.getMessage().indexOf("String") > 0); - } - } - - public void testEquals() { - - assertEquals(fieldSet, fieldSet); - assertEquals(fieldSet, new FieldSet(tokens)); - - String[] tokens1 = new String[] { "token1" }; - String[] tokens2 = new String[] { "token1" }; - FieldSet fs1 = new FieldSet(tokens1); - FieldSet fs2 = new FieldSet(tokens2); - assertEquals(fs1, fs2); - } - - public void testNullField() { - assertEquals(null, fieldSet.readString(10)); - } - - public void testEqualsNull() { - assertFalse(fieldSet.equals(null)); - } - - public void testEqualsNullTokens() { - assertFalse(new FieldSet(null).equals(fieldSet)); - } - - public void testEqualsNotEqual() throws Exception { - - String[] tokens1 = new String[] { "token1" }; - String[] tokens2 = new String[] { "token1", "token2" }; - FieldSet fs1 = new FieldSet(tokens1); - FieldSet fs2 = new FieldSet(tokens2); - assertFalse(fs1.equals(fs2)); - - } - - public void testHashCode() throws Exception { - assertEquals(fieldSet.hashCode(), new FieldSet(tokens).hashCode()); - } - - public void testHashCodeWithNullTokens() throws Exception { - assertEquals(0, new FieldSet(null).hashCode()); - } - - public void testConstructor() throws Exception { - try { - new FieldSet(new String[] { "1", "2" }, new String[] { "a" }); - fail("Expected IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // expected - } - } - - public void testToStringWithNames() throws Exception { - fieldSet = new FieldSet(new String[] { "foo", "bar" }, new String[] { "Foo", "Bar" }); - assertTrue(fieldSet.toString().indexOf("Foo=foo") >= 0); - } - - public void testToStringWithoutNames() throws Exception { - fieldSet = new FieldSet(new String[] { "foo", "bar" }); - assertTrue(fieldSet.toString().indexOf("foo") >= 0); - } - - public void testToStringNullTokens() throws Exception { - fieldSet = new FieldSet(null); - assertEquals("", fieldSet.toString()); - } - - public void testProperties() throws Exception { - assertEquals("foo", new FieldSet(new String[] { "foo", "bar" }, new String[] { "Foo", "Bar" }).getProperties() - .getProperty("Foo")); - } - - public void testPropertiesWithNoNames() throws Exception { - try { - new FieldSet(new String[] { "foo", "bar" }).getProperties(); - fail("Expected IllegalStateException"); - } - catch (IllegalStateException e) { - // expected - } - } - - public void testPropertiesWithWhiteSpace() throws Exception{ - - assertEquals("bar", new FieldSet(new String[] { "foo", "bar " }, new String[] { "Foo", "Bar"}).getProperties().getProperty("Bar")); - } - - public void testPropertiesWithNullValues() throws Exception{ - - fieldSet = new FieldSet(new String[] { null, "bar" }, new String[] { "Foo", "Bar"}); - assertEquals("bar", fieldSet.getProperties().getProperty("Bar")); - assertEquals(null, fieldSet.getProperties().getProperty("Foo")); - } - - public void testAccessByNameWhenNamesMissing() throws Exception { - try { - new FieldSet(new String[] { "1", "2" }).readInt("a"); - fail("Expected IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // expected - } - } -} +/* + * 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.io.file; + +import java.math.BigDecimal; +import java.text.ParseException; + +import junit.framework.TestCase; + +import org.springframework.batch.io.file.FieldSet; + +public class FieldSetTests extends TestCase { + FieldSet fieldSet; + + String[] tokens; + + String[] names; + + protected void setUp() throws Exception { + super.setUp(); + + tokens = new String[] { "TestString", "true", "C", "10", "-472", "354224", "543", "124.3", "424.3", "324", + null, "2007-10-12", "12-10-2007", "" }; + names = new String[] { "String", "Boolean", "Char", "Byte", "Short", "Integer", "Long", "Float", "Double", + "BigDecimal", "Null", "Date", "DatePattern", "BlankInput" }; + + fieldSet = new FieldSet(tokens, names); + assertEquals(14, fieldSet.getFieldCount()); + + } + + public void testNames() throws Exception { + assertEquals(fieldSet.getFieldCount(), fieldSet.getNames().length); + } + + public void testNamesNotKnown() throws Exception { + fieldSet = new FieldSet(new String[]{"foo"}); + try { + fieldSet.getNames(); + fail("Expected IllegalStateException"); + } catch (IllegalStateException e) { + // expected + } + } + + public void testReadString() throws ParseException { + + assertEquals(fieldSet.readString(0), "TestString"); + assertEquals(fieldSet.readString("String"), "TestString"); + + } + + public void testReadChar() throws Exception { + + assertTrue(fieldSet.readChar(2) == 'C'); + assertTrue(fieldSet.readChar("Char") == 'C'); + + } + + public void testReadBooleanTrue() throws Exception { + + assertTrue(fieldSet.readBoolean(1)); + assertTrue(fieldSet.readBoolean("Boolean")); + + } + + public void testReadByte() throws Exception { + + assertTrue(fieldSet.readByte(3) == 10); + assertTrue(fieldSet.readByte("Byte") == 10); + + } + + public void testReadShort() throws Exception { + + assertTrue(fieldSet.readShort(4) == -472); + assertTrue(fieldSet.readShort("Short") == -472); + + } + + public void testReadFloat() throws Exception { + + assertTrue(fieldSet.readFloat(7) == 124.3F); + assertTrue(fieldSet.readFloat("Float") == 124.3F); + + } + + public void testReadDouble() throws Exception { + + assertTrue(fieldSet.readDouble(8) == 424.3); + assertTrue(fieldSet.readDouble("Double") == 424.3); + + } + + public void testReadBigDecimal() throws Exception { + + BigDecimal bd = new BigDecimal(324); + assertEquals(fieldSet.readBigDecimal(9), bd); + assertEquals(fieldSet.readBigDecimal("BigDecimal"), bd); + + } + + public void testReadBigDecimalWithDefaultvalue() throws Exception { + + BigDecimal bd = new BigDecimal(324); + assertEquals(bd, fieldSet.readBigDecimal(10, bd)); + assertEquals(bd, fieldSet.readBigDecimal("Null", bd)); + + } + + public void testReadNonExistentField() throws Exception { + + try { + fieldSet.readString("something"); + fail("field set returns value even value was never put in!"); + } + catch (IllegalArgumentException e) { + assertTrue(e.getMessage().indexOf("something") > 0); + } + + } + + public void testReadIndexOutOfRange() throws Exception { + + try { + fieldSet.readShort(-1); + fail("field set returns value even index is out of range!"); + } + catch (IndexOutOfBoundsException e) { + assertTrue(true); + } + + try { + fieldSet.readShort(99); + fail("field set returns value even index is out of range!"); + } + catch (Exception e) { + assertTrue(true); + } + } + + public void testReadBooleanWithTrueValue() { + assertTrue(fieldSet.readBoolean(1, "true")); + assertFalse(fieldSet.readBoolean(1, "incorrect trueValue")); + + assertTrue(fieldSet.readBoolean("Boolean", "true")); + assertFalse(fieldSet.readBoolean("Boolean", "incorrect trueValue")); + } + + public void testReadBooleanFalse() { + fieldSet = new FieldSet(new String[] { "false" }); + assertFalse(fieldSet.readBoolean(0)); + } + + public void testReadCharException() { + try { + fieldSet.readChar(1); + fail("the value read was not a character, exception expected"); + } + catch (IllegalArgumentException expected) { + assertTrue(true); + } + + try { + fieldSet.readChar("Boolean"); + fail("the value read was not a character, exception expected"); + } + catch (IllegalArgumentException expected) { + assertTrue(true); + } + } + + public void testReadInt() throws Exception { + assertEquals(354224, fieldSet.readInt(5)); + assertEquals(354224, fieldSet.readInt("Integer")); + } + + public void testReadBlankInt(){ + + //Trying to parse a blank field as an integer, but without a default + //value should throw a NumberFormatException + try{ + fieldSet.readInt(13); + fail(); + } + catch(NumberFormatException ex){ + //expected + } + + try{ + fieldSet.readInt("BlankInput"); + fail(); + } + catch(NumberFormatException ex){ + //expected + } + + } + + public void testReadLong() throws Exception { + assertEquals(543, fieldSet.readLong(6)); + assertEquals(543, fieldSet.readLong("Long")); + } + + public void testReadIntWithNullValue() { + assertEquals(5, fieldSet.readInt(10, 5)); + assertEquals(5, fieldSet.readInt("Null", 5)); + } + + public void testReadIntWithDefaultAndNotNull() throws Exception { + assertEquals(354224, fieldSet.readInt(5, 5)); + assertEquals(354224, fieldSet.readInt("Integer", 5)); + } + + public void testReadLongWithNullValue() { + int defaultValue = 5; + int indexOfNull = 10; + int indexNotNull = 6; + String nameNull = "Null"; + String nameNotNull = "Long"; + long longValueAtIndex = 543; + + assertEquals(fieldSet.readLong(indexOfNull, defaultValue), defaultValue); + assertEquals(fieldSet.readLong(indexNotNull, defaultValue), longValueAtIndex); + + assertEquals(fieldSet.readLong(nameNull, defaultValue), defaultValue); + assertEquals(fieldSet.readLong(nameNotNull, defaultValue), longValueAtIndex); + } + + public void testReadBigDecimalInvalid() { + int index = 0; + + try { + fieldSet.readBigDecimal(index); + fail("field value is not a number, exception expected"); + } + catch (IllegalArgumentException e) { + assertTrue(e.getMessage().indexOf("TestString") > 0); + } + + } + + public void testReadBigDecimalByNameInvalid() throws Exception { + try { + fieldSet.readBigDecimal("String"); + fail("field value is not a number, exception expected"); + } + catch (IllegalArgumentException e) { + assertTrue(e.getMessage().indexOf("TestString") > 0); + assertTrue(e.getMessage().indexOf("name: [String]") > 0); + } + } + + public void testReadDate() throws Exception { + assertNotNull(fieldSet.readDate(11)); + assertNotNull(fieldSet.readDate("Date")); + } + + public void testReadDateInvalid() throws Exception { + + try { + fieldSet.readDate(0); + fail("field value is not a date, exception expected"); + } + catch (IllegalArgumentException e) { + assertTrue(e.getMessage().indexOf("TestString") > 0); + } + + } + + public void testReadDateInvalidByName() throws Exception { + + try { + fieldSet.readDate("String"); + fail("field value is not a date, exception expected"); + } + catch (IllegalArgumentException e) { + assertTrue(e.getMessage().indexOf("name: [String]") > 0); + } + + } + + public void testReadDateInvalidWithPattern() throws Exception { + + try { + fieldSet.readDate(0, "dd-MM-yyyy"); + fail("field value is not a date, exception expected"); + } + catch (IllegalArgumentException e) { + assertTrue(e.getMessage().indexOf("dd-MM-yyyy") > 0); + } + } + + public void testReadDateByNameInvalidWithPattern() throws Exception { + + try { + fieldSet.readDate("String", "dd-MM-yyyy"); + fail("field value is not a date, exception expected"); + } + catch (IllegalArgumentException e) { + assertTrue(e.getMessage().indexOf("dd-MM-yyyy") > 0); + assertTrue(e.getMessage().indexOf("String") > 0); + } + } + + public void testEquals() { + + assertEquals(fieldSet, fieldSet); + assertEquals(fieldSet, new FieldSet(tokens)); + + String[] tokens1 = new String[] { "token1" }; + String[] tokens2 = new String[] { "token1" }; + FieldSet fs1 = new FieldSet(tokens1); + FieldSet fs2 = new FieldSet(tokens2); + assertEquals(fs1, fs2); + } + + public void testNullField() { + assertEquals(null, fieldSet.readString(10)); + } + + public void testEqualsNull() { + assertFalse(fieldSet.equals(null)); + } + + public void testEqualsNullTokens() { + assertFalse(new FieldSet(null).equals(fieldSet)); + } + + public void testEqualsNotEqual() throws Exception { + + String[] tokens1 = new String[] { "token1" }; + String[] tokens2 = new String[] { "token1", "token2" }; + FieldSet fs1 = new FieldSet(tokens1); + FieldSet fs2 = new FieldSet(tokens2); + assertFalse(fs1.equals(fs2)); + + } + + public void testHashCode() throws Exception { + assertEquals(fieldSet.hashCode(), new FieldSet(tokens).hashCode()); + } + + public void testHashCodeWithNullTokens() throws Exception { + assertEquals(0, new FieldSet(null).hashCode()); + } + + public void testConstructor() throws Exception { + try { + new FieldSet(new String[] { "1", "2" }, new String[] { "a" }); + fail("Expected IllegalArgumentException"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testToStringWithNames() throws Exception { + fieldSet = new FieldSet(new String[] { "foo", "bar" }, new String[] { "Foo", "Bar" }); + assertTrue(fieldSet.toString().indexOf("Foo=foo") >= 0); + } + + public void testToStringWithoutNames() throws Exception { + fieldSet = new FieldSet(new String[] { "foo", "bar" }); + assertTrue(fieldSet.toString().indexOf("foo") >= 0); + } + + public void testToStringNullTokens() throws Exception { + fieldSet = new FieldSet(null); + assertEquals("", fieldSet.toString()); + } + + public void testProperties() throws Exception { + assertEquals("foo", new FieldSet(new String[] { "foo", "bar" }, new String[] { "Foo", "Bar" }).getProperties() + .getProperty("Foo")); + } + + public void testPropertiesWithNoNames() throws Exception { + try { + new FieldSet(new String[] { "foo", "bar" }).getProperties(); + fail("Expected IllegalStateException"); + } + catch (IllegalStateException e) { + // expected + } + } + + public void testPropertiesWithWhiteSpace() throws Exception{ + + assertEquals("bar", new FieldSet(new String[] { "foo", "bar " }, new String[] { "Foo", "Bar"}).getProperties().getProperty("Bar")); + } + + public void testPropertiesWithNullValues() throws Exception{ + + fieldSet = new FieldSet(new String[] { null, "bar" }, new String[] { "Foo", "Bar"}); + assertEquals("bar", fieldSet.getProperties().getProperty("Bar")); + assertEquals(null, fieldSet.getProperties().getProperty("Foo")); + } + + public void testAccessByNameWhenNamesMissing() throws Exception { + try { + new FieldSet(new String[] { "1", "2" }).readInt("a"); + fail("Expected IllegalArgumentException"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testGetValues() { + String[] values = fieldSet.getValues(); + assertEquals(tokens.length, values.length); + for (int i = 0; i < tokens.length; i++) { + assertEquals(tokens[i], values[i]); + } + } +} diff --git a/infrastructure/src/test/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSourceTests.java b/infrastructure/src/test/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSourceTests.java index 7d83fbd37..cac08570d 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSourceTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/file/support/SimpleFlatFileInputSourceTests.java @@ -1,249 +1,293 @@ -/* - * 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.io.file.support; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.springframework.batch.io.exception.BatchEnvironmentException; -import org.springframework.batch.io.exception.FlatFileParsingException; -import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.FieldSetMapper; -import org.springframework.batch.io.file.support.separator.DefaultRecordSeparatorPolicy; -import org.springframework.batch.io.file.support.transform.LineTokenizer; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - -/** - * Tests for {@link SimpleFlatFileInputSourceTests} - * - * @author Dave Syer - * - */ -public class SimpleFlatFileInputSourceTests extends TestCase { - - // object under test - private SimpleFlatFileInputSource inputSource = new SimpleFlatFileInputSource(); - - // common value used for writing to a file - private String TEST_STRING = "FlatFileInputTemplate-TestData"; - - // simple stub instead of a realistic tokenizer - private LineTokenizer tokenizer = new LineTokenizer() { - public FieldSet tokenize(String line) { - return new FieldSet(new String[] { line }); - } - }; - - private FieldSetMapper fieldSetMapper = new FieldSetMapper(){ - public Object mapLine(FieldSet fs) { - return fs; - } - }; - - /** - * Create inputFile, inject mock/stub dependencies for tested object, - * initialize the tested object - */ - protected void setUp() throws Exception { - - inputSource.setResource(getInputResource(TEST_STRING)); - inputSource.setTokenizer(tokenizer); - inputSource.setFieldSetMapper(fieldSetMapper); - inputSource.afterPropertiesSet(); - - // context argument is necessary only for the FileLocator, which - // is mocked - inputSource.open(); - } - - /** - * Release resources. - */ - protected void tearDown() throws Exception { - inputSource.close(); - } - - private Resource getInputResource(String input) { - return new ByteArrayResource(input.getBytes()); - } - - /** - * Regular usage of read method - */ - public void testRead() throws IOException { - assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); - } - - /** - * Regular usage of read method - */ - public void testReadExhausted() throws IOException { - assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); - assertEquals(null, inputSource.read()); - } - - /** - * Regular usage of read method - */ - public void testReadWithTokenizerError() throws IOException { - inputSource.setTokenizer(new LineTokenizer() { - public FieldSet tokenize(String line) { - throw new RuntimeException("foo"); - } - }); - try { - inputSource.read(); - fail("Expected ParsingException"); - } catch (FlatFileParsingException e) { - assertEquals(e.getInput(), TEST_STRING); - assertEquals(e.getLineNumber(), 1); - } - } - - public void testReadWithMapperError() throws IOException { - inputSource.setFieldSetMapper(new FieldSetMapper(){ - public Object mapLine(FieldSet fs) { - throw new RuntimeException("foo"); - } - }); - - try { - inputSource.read(); - fail("Expected ParsingException"); - } catch (FlatFileParsingException e) { - assertEquals(e.getInput(), TEST_STRING); - assertEquals(e.getLineNumber(), 1); - } - } - - public void testReadBeforeOpen() throws Exception { - inputSource = new SimpleFlatFileInputSource(); - inputSource.setResource(getInputResource(TEST_STRING)); - inputSource.setFieldSetMapper(fieldSetMapper); - assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); - } - - public void testCloseBeforeOpen() throws Exception { - inputSource = new SimpleFlatFileInputSource(); - inputSource.setResource(getInputResource(TEST_STRING)); - inputSource.setFieldSetMapper(fieldSetMapper); - inputSource.close(); - // The open still happens automatically on a read... - assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); - } - - public void testCloseOnDestroy() throws Exception { - final List list = new ArrayList(); - inputSource = new SimpleFlatFileInputSource() { - public void close() { - list.add("close"); - } - }; - inputSource.destroy(); - assertEquals(1, list.size()); - } - - public void testInitializationWithNullResource() throws Exception { - inputSource = new SimpleFlatFileInputSource(); - try { - inputSource.afterPropertiesSet(); - fail("Expected IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // expected - } - } - - public void testOpenTwiceHasNoEffect() throws Exception { - inputSource.open(); - testRead(); - } - - public void testSetValidEncoding() throws Exception { - inputSource = new SimpleFlatFileInputSource(); - inputSource.setEncoding("UTF-8"); - inputSource.setResource(getInputResource(TEST_STRING)); - inputSource.setFieldSetMapper(fieldSetMapper); - testRead(); - } - - public void testSetNullEncoding() throws Exception { - inputSource = new SimpleFlatFileInputSource(); - inputSource.setEncoding(null); - inputSource.setResource(getInputResource(TEST_STRING)); - try { - inputSource.open(); - fail("Expected IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // expected - } - } - - public void testSetInvalidEncoding() throws Exception { - inputSource = new SimpleFlatFileInputSource(); - inputSource.setEncoding("foo"); - inputSource.setResource(getInputResource(TEST_STRING)); - try { - inputSource.open(); - fail("Expected BatchEnvironmentException"); - } - catch (BatchEnvironmentException e) { - // expected - assertEquals("foo", e.getCause().getMessage()); - } - } - - public void testEncoding() throws Exception { - inputSource.setEncoding("UTF-8"); - testRead(); - } - - public void testRecordSeparator() throws Exception { - inputSource.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); - testRead(); - } - - public void testComments() throws Exception { - inputSource.setResource(getInputResource("% Comment\n"+TEST_STRING)); - inputSource.setComments(new String[] {"%"}); - testRead(); - } - - public void testInvalidFile() throws IOException { - DefaultFlatFileInputSource ffit = new DefaultFlatFileInputSource(); - - FileSystemResource resource = new FileSystemResource("FooDummy.txt"); - assertTrue(!resource.exists()); - ffit.setResource(resource); - - try { - ffit.open(); - fail("File is not existing but exception was not thrown."); - } - catch (BatchEnvironmentException e) { - assertEquals("FooDummy", e.getCause().getMessage().substring(0,8)); - } - - } - -} +/* + * 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.io.file.support; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.batch.io.exception.BatchEnvironmentException; +import org.springframework.batch.io.exception.FlatFileParsingException; +import org.springframework.batch.io.file.FieldSet; +import org.springframework.batch.io.file.FieldSetMapper; +import org.springframework.batch.io.file.support.separator.DefaultRecordSeparatorPolicy; +import org.springframework.batch.io.file.support.transform.DelimitedLineTokenizer; +import org.springframework.batch.io.file.support.transform.LineTokenizer; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +/** + * Tests for {@link SimpleFlatFileInputSourceTests} + * + * @author Dave Syer + * + */ +public class SimpleFlatFileInputSourceTests extends TestCase { + + // object under test + private SimpleFlatFileInputSource inputSource = new SimpleFlatFileInputSource(); + + // common value used for writing to a file + private String TEST_STRING = "FlatFileInputTemplate-TestData"; + + // simple stub instead of a realistic tokenizer + private LineTokenizer tokenizer = new LineTokenizer() { + public FieldSet tokenize(String line) { + return new FieldSet(new String[] { line }); + } + }; + + private FieldSetMapper fieldSetMapper = new FieldSetMapper(){ + public Object mapLine(FieldSet fs) { + return fs; + } + }; + + /** + * Create inputFile, inject mock/stub dependencies for tested object, + * initialize the tested object + */ + protected void setUp() throws Exception { + + inputSource.setResource(getInputResource(TEST_STRING)); + inputSource.setTokenizer(tokenizer); + inputSource.setFieldSetMapper(fieldSetMapper); + inputSource.afterPropertiesSet(); + + inputSource.open(); + } + + /** + * Release resources. + */ + protected void tearDown() throws Exception { + inputSource.close(); + } + + private Resource getInputResource(String input) { + return new ByteArrayResource(input.getBytes()); + } + + /** + * Regular usage of read method + */ + public void testRead() throws IOException { + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); + } + + /** + * Regular usage of read method + */ + public void testReadExhausted() throws IOException { + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); + assertEquals(null, inputSource.read()); + } + + /** + * Regular usage of read method + */ + public void testReadWithTokenizerError() throws IOException { + inputSource.setTokenizer(new LineTokenizer() { + public FieldSet tokenize(String line) { + throw new RuntimeException("foo"); + } + }); + try { + inputSource.read(); + fail("Expected ParsingException"); + } catch (FlatFileParsingException e) { + assertEquals(e.getInput(), TEST_STRING); + assertEquals(e.getLineNumber(), 1); + } + } + + public void testReadWithMapperError() throws IOException { + inputSource.setFieldSetMapper(new FieldSetMapper(){ + public Object mapLine(FieldSet fs) { + throw new RuntimeException("foo"); + } + }); + + try { + inputSource.read(); + fail("Expected ParsingException"); + } catch (FlatFileParsingException e) { + assertEquals(e.getInput(), TEST_STRING); + assertEquals(e.getLineNumber(), 1); + } + } + + public void testReadBeforeOpen() throws Exception { + inputSource = new SimpleFlatFileInputSource(); + inputSource.setResource(getInputResource(TEST_STRING)); + inputSource.setFieldSetMapper(fieldSetMapper); + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); + } + + public void testCloseBeforeOpen() throws Exception { + inputSource = new SimpleFlatFileInputSource(); + inputSource.setResource(getInputResource(TEST_STRING)); + inputSource.setFieldSetMapper(fieldSetMapper); + inputSource.close(); + // The open still happens automatically on a read... + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); + } + + public void testCloseOnDestroy() throws Exception { + final List list = new ArrayList(); + inputSource = new SimpleFlatFileInputSource() { + public void close() { + list.add("close"); + } + }; + inputSource.destroy(); + assertEquals(1, list.size()); + } + + public void testInitializationWithNullResource() throws Exception { + inputSource = new SimpleFlatFileInputSource(); + try { + inputSource.afterPropertiesSet(); + fail("Expected IllegalArgumentException"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testOpenTwiceHasNoEffect() throws Exception { + inputSource.open(); + testRead(); + } + + public void testSetValidEncoding() throws Exception { + inputSource = new SimpleFlatFileInputSource(); + inputSource.setEncoding("UTF-8"); + inputSource.setResource(getInputResource(TEST_STRING)); + inputSource.setFieldSetMapper(fieldSetMapper); + testRead(); + } + + public void testSetNullEncoding() throws Exception { + inputSource = new SimpleFlatFileInputSource(); + inputSource.setEncoding(null); + inputSource.setResource(getInputResource(TEST_STRING)); + try { + inputSource.open(); + fail("Expected IllegalArgumentException"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testSetInvalidEncoding() throws Exception { + inputSource = new SimpleFlatFileInputSource(); + inputSource.setEncoding("foo"); + inputSource.setResource(getInputResource(TEST_STRING)); + try { + inputSource.open(); + fail("Expected BatchEnvironmentException"); + } + catch (BatchEnvironmentException e) { + // expected + assertEquals("foo", e.getCause().getMessage()); + } + } + + public void testEncoding() throws Exception { + inputSource.setEncoding("UTF-8"); + testRead(); + } + + public void testRecordSeparator() throws Exception { + inputSource.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); + testRead(); + } + + public void testComments() throws Exception { + inputSource.setResource(getInputResource("% Comment\n"+TEST_STRING)); + inputSource.setComments(new String[] {"%"}); + testRead(); + } + + public void testInvalidFile() throws IOException { + DefaultFlatFileInputSource ffit = new DefaultFlatFileInputSource(); + + FileSystemResource resource = new FileSystemResource("FooDummy.txt"); + assertTrue(!resource.exists()); + ffit.setResource(resource); + + try { + ffit.open(); + fail("File is not existing but exception was not thrown."); + } + catch (BatchEnvironmentException e) { + assertEquals("FooDummy", e.getCause().getMessage().substring(0,8)); + } + + } + + /** + * Header line is skipped and used to setup fieldSet column names. + */ + public void testColumnNamesInHeader() throws Exception { + final String INPUT = "name1|name2\nvalue1|value2\nvalue3|value4"; + + inputSource = new SimpleFlatFileInputSource(); + inputSource.setResource(getInputResource(INPUT)); + inputSource.setTokenizer(new DelimitedLineTokenizer('|')); + inputSource.setFieldSetMapper(fieldSetMapper); + inputSource.setFirstLineIsHeader(true); + inputSource.afterPropertiesSet(); + inputSource.open(); + + FieldSet fs = (FieldSet) inputSource.read(); + assertEquals("value1", fs.readString("name1")); + assertEquals("value2", fs.readString("name2")); + + fs = (FieldSet) inputSource.read(); + assertEquals("value3", fs.readString("name1")); + assertEquals("value4", fs.readString("name2")); + } + + /** + * Header line is skipped and used to setup fieldSet column names. + */ + public void testLinesToSkip() throws Exception { + final String INPUT = "foo bar spam\none two\nthree four"; + + inputSource = new SimpleFlatFileInputSource(); + inputSource.setResource(getInputResource(INPUT)); + inputSource.setTokenizer(new DelimitedLineTokenizer(' ')); + inputSource.setFieldSetMapper(fieldSetMapper); + inputSource.setLinesToSkip(1); + inputSource.afterPropertiesSet(); + inputSource.open(); + + FieldSet fs = (FieldSet) inputSource.read(); + assertEquals("one", fs.readString(0)); + assertEquals("two", fs.readString(1)); + + fs = (FieldSet) inputSource.read(); + assertEquals("three", fs.readString(0)); + assertEquals("four", fs.readString(1)); + } +} diff --git a/infrastructure/src/test/java/org/springframework/batch/io/file/support/transform/CommonLineTokenizerTests.java b/infrastructure/src/test/java/org/springframework/batch/io/file/support/transform/CommonLineTokenizerTests.java new file mode 100644 index 000000000..2de6a2f49 --- /dev/null +++ b/infrastructure/src/test/java/org/springframework/batch/io/file/support/transform/CommonLineTokenizerTests.java @@ -0,0 +1,37 @@ +package org.springframework.batch.io.file.support.transform; + +import java.util.List; + +import junit.framework.TestCase; + +/** + * Tests for {@link AbstractLineTokenizer}. + * + * @author Robert Kasanicky + * @author Dave Syer + */ +public class CommonLineTokenizerTests extends TestCase { + + /** + * Columns names are considered to be specified if they are not null or empty. + */ + public void testHasNames() { + AbstractLineTokenizer tokenizer = new AbstractLineTokenizer() { + protected List doTokenize(String line) { + return null; + } + }; + + assertFalse(tokenizer.hasNames()); + + tokenizer.setNames(null); + assertFalse(tokenizer.hasNames()); + + tokenizer.setNames(new String[0]); + assertFalse(tokenizer.hasNames()); + + tokenizer.setNames(new String[]{"name1", "name2"}); + assertTrue(tokenizer.hasNames()); + } + +} diff --git a/samples/src/main/resources/jobs/hibernateJob.xml b/samples/src/main/resources/jobs/hibernateJob.xml index 188db095c..557e050bc 100644 --- a/samples/src/main/resources/jobs/hibernateJob.xml +++ b/samples/src/main/resources/jobs/hibernateJob.xml @@ -42,6 +42,10 @@ + + +