From 4b24ef866c4adebf05932dab70ba01a98dbabd74 Mon Sep 17 00:00:00 2001 From: lucasward Date: Mon, 8 Oct 2007 04:28:31 +0000 Subject: [PATCH] BATCH-140: Modified file input sources to no longer implemented FieldSet and now accept an injected mapper. --- .../exception/FlatFileParsingException.java | 62 +++++ .../ParsingException.java} | 73 +++--- .../support/DefaultFlatFileInputSource.java | 19 +- .../support/SimpleFlatFileInputSource.java | 55 ++--- .../AbstractFieldSetItemProvider.java | 74 ------ .../item/provider/FlatFileItemProvider.java | 116 ---------- .../provider/InputSourceItemProvider.java | 35 +-- .../item/provider/ValidatingItemProvider.java | 59 +++++ .../DefaultFlatFileInputSourceTests.java | 103 +++++---- .../SimpleFlatFileInputSourceTests.java | 118 ++++++---- .../AbstractFieldSetItemProviderTests.java | 59 ----- .../provider/FieldSetItemProviderTests.java | 54 ----- .../provider/FlatFileItemProviderTests.java | 217 ------------------ .../InputSourceItemProviderTests.java | 21 +- .../provider/ValidatingItemProviderTests.java | 114 +++++++++ .../support/AbstractTradeBatchTests.java | 24 +- 16 files changed, 488 insertions(+), 715 deletions(-) create mode 100644 infrastructure/src/main/java/org/springframework/batch/io/exception/FlatFileParsingException.java rename infrastructure/src/main/java/org/springframework/batch/io/{file/FieldSetInputSource.java => exception/ParsingException.java} (54%) delete mode 100644 infrastructure/src/main/java/org/springframework/batch/item/provider/AbstractFieldSetItemProvider.java delete mode 100644 infrastructure/src/main/java/org/springframework/batch/item/provider/FlatFileItemProvider.java create mode 100644 infrastructure/src/main/java/org/springframework/batch/item/provider/ValidatingItemProvider.java delete mode 100644 infrastructure/src/test/java/org/springframework/batch/item/provider/AbstractFieldSetItemProviderTests.java delete mode 100644 infrastructure/src/test/java/org/springframework/batch/item/provider/FieldSetItemProviderTests.java delete mode 100644 infrastructure/src/test/java/org/springframework/batch/item/provider/FlatFileItemProviderTests.java create mode 100644 infrastructure/src/test/java/org/springframework/batch/item/provider/ValidatingItemProviderTests.java diff --git a/infrastructure/src/main/java/org/springframework/batch/io/exception/FlatFileParsingException.java b/infrastructure/src/main/java/org/springframework/batch/io/exception/FlatFileParsingException.java new file mode 100644 index 000000000..c3cf23adf --- /dev/null +++ b/infrastructure/src/main/java/org/springframework/batch/io/exception/FlatFileParsingException.java @@ -0,0 +1,62 @@ +/* + * 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.exception; + +/** + * Exception thrown when errors are encountered + * parsing flat files. The original input, typically + * a line, can be passed in, so that latter catches + * can write out the original input to a log, or + * an error table. + * + * @author Lucas Ward + * + */ +public class FlatFileParsingException extends ParsingException { + + private String input; + private int lineNumber; + + public FlatFileParsingException(String message, String input) { + super(message); + this.input = input; + } + + public FlatFileParsingException(String message, String input, int lineNumber) { + super(message); + this.input = input; + this.lineNumber = lineNumber; + } + + public FlatFileParsingException(String message, Throwable cause, String input, int lineNumber) { + super(message, cause); + this.input = input; + this.lineNumber = lineNumber; + } + + public FlatFileParsingException(Throwable cause, String input) { + super(cause); + this.input = input; + } + + public String getInput() { + return input; + } + + public int getLineNumber() { + return lineNumber; + } +} diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSetInputSource.java b/infrastructure/src/main/java/org/springframework/batch/io/exception/ParsingException.java similarity index 54% rename from infrastructure/src/main/java/org/springframework/batch/io/file/FieldSetInputSource.java rename to infrastructure/src/main/java/org/springframework/batch/io/exception/ParsingException.java index fea876ef7..9bf5c3271 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSetInputSource.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/exception/ParsingException.java @@ -1,35 +1,38 @@ -/* - * 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 org.springframework.batch.io.InputSource; - -/** - * Common interface for reading input e.g. from a file or other stream-based - * resource. Providers are expected to use this interface to access an input - * source.
- * - * If we had generics this would be a parameterised input source, but - * for type safety with the current constraints we are going to use this - * interface. - * - */ -public interface FieldSetInputSource extends InputSource { - - public FieldSet readFieldSet(); - -} +/* + * 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.exception; + +/** + * Exception indicating that an error has been encountered + * parsing io, typically from a file. + * + * @author Lucas Ward + * + */ +public class ParsingException extends RuntimeException { + + public ParsingException(String message) { + super(message); + } + + public ParsingException(String message, Throwable cause) { + super(message, cause); + } + + public ParsingException(Throwable cause) { + super(cause); + } +} 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 2c4e3802a..6206e31e5 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 @@ -23,7 +23,6 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.io.Skippable; -import org.springframework.batch.io.file.FieldSetInputSource; import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager; import org.springframework.batch.restart.GenericRestartData; import org.springframework.batch.restart.RestartData; @@ -37,7 +36,7 @@ import org.springframework.transaction.support.TransactionSynchronizationAdapter * This class is a {@link FieldSetInputSource} that supports restart, * skipping invalid lines and storing statistics. *

- * + * * @author Waseem Malik * @author Tomas Slanina * @author Robert Kasanicky @@ -49,13 +48,13 @@ public class DefaultFlatFileInputSource extends SimpleFlatFileInputSource implem public static final String READ_STATISTICS_NAME = "lines.read.count"; public static final String SKIPPED_STATISTICS_NAME = "skipped.lines.count"; - + private Set skippedLines = new HashSet(); private TransactionSynchronization transactionSynchronization = new ResourceLineReaderTransactionSynchronization(); - + private Properties statistics = new Properties(); - + /** * Initialize the input source. */ @@ -73,14 +72,14 @@ public class DefaultFlatFileInputSource extends SimpleFlatFileInputSource implem * This method initialises the Input Source for Restart. It opens the input * file and position the buffer reader according to information provided by * the restart data - * + * * @param restartData restartData information */ public void restoreFrom(RestartData data) { - + //TODO this does not look very nice... - if (data==null || - data.getProperties() == null || + if (data==null || + data.getProperties() == null || data.getProperties().getProperty(READ_STATISTICS_NAME) == null || getReader()==null) { // do nothing @@ -173,7 +172,7 @@ public class DefaultFlatFileInputSource extends SimpleFlatFileInputSource implem /** * TransactionSynchronization method indicating that a transaction has * completed. - * + * * @param status indicates whether it was a rollback or commit */ public void afterCompletion(int status) { 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 19bef828a..17ea0994c 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 @@ -19,9 +19,10 @@ 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.exception.ValidationException; import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.FieldSetInputSource; +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; @@ -37,17 +38,17 @@ import org.springframework.util.Assert; * 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 ResourceLifecycle, FieldSetInputSource, InitializingBean, DisposableBean { +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"; @@ -64,6 +65,8 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp private LineTokenizer tokenizer = new DelimitedLineTokenizer(); + private FieldSetMapper fieldSetMapper; + private String encoding = DEFAULT_CHARSET; /** @@ -80,7 +83,7 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp * 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) { @@ -90,6 +93,7 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp public void afterPropertiesSet() throws Exception { Assert.notNull(resource); Assert.state(resource.exists(), "Resource must exist: [" + resource + "]"); + Assert.notNull(fieldSetMapper, "FieldSetMapper must not be null."); } /** @@ -107,7 +111,7 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp /** * Close and null out the reader. - * + * * @see ResourceLifecycle */ public void close() { @@ -124,7 +128,7 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp /** * 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 { @@ -139,31 +143,21 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp /** * A wrapper for {@link #readFieldSet()} to make this into a real * {@link InputSource}. - * + * * @see org.springframework.batch.io.InputSource#read() */ - public final Object read() { - return readFieldSet(); - } - - /** - * Get the next {@link FieldSet} from the input. - * - * @see org.springframework.batch.io.file.FieldSetInputSource#readFieldSet() - */ - public FieldSet readFieldSet() { + public Object read() { String line = readLine(); if (line != null) { try { - return this.tokenizer.tokenize(line); + FieldSet tokenizedLine = tokenizer.tokenize(line); + return fieldSetMapper.mapLine(tokenizedLine); } - catch (RuntimeException ve) { + catch (RuntimeException ex) { // add current line count to message and re-throw - // TODO: wrap the exception more carefully to preserve type etc. - ValidationException newVe = new ValidationException("Validation error at line " - + getReader().getCurrentLineCount() + ": " + ve.getMessage()); - throw newVe; + throw new FlatFileParsingException("Parsing error", ex, line, + getReader().getCurrentLineCount()); } } return null; @@ -172,7 +166,7 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp /** * 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; */ @@ -187,6 +181,15 @@ public class SimpleFlatFileInputSource implements ResourceLifecycle, FieldSetInp 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) { diff --git a/infrastructure/src/main/java/org/springframework/batch/item/provider/AbstractFieldSetItemProvider.java b/infrastructure/src/main/java/org/springframework/batch/item/provider/AbstractFieldSetItemProvider.java deleted file mode 100644 index 2976fd313..000000000 --- a/infrastructure/src/main/java/org/springframework/batch/item/provider/AbstractFieldSetItemProvider.java +++ /dev/null @@ -1,74 +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.provider; - -import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.FieldSetInputSource; -import org.springframework.batch.item.ItemProvider; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - -/** - * {@link ItemProvider} based on {@link FieldSetInputSource}. Not restartable - * or transaction aware, but can be used by multiple concurrent threads, so - * useful as a base class or for testing. - * - * @author Rob Harrop - * @author Dave Syer - */ -public abstract class AbstractFieldSetItemProvider extends AbstractItemProvider implements InitializingBean { - - protected FieldSetInputSource source; - - private Object mutex = new Object(); - - /** - * Make sure mandatory properties are set. - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - public void afterPropertiesSet() throws Exception { - Assert.notNull(source); - } - - /** - * Setter for the input source. Mandatory with no default. - * @param source - */ - public void setSource(FieldSetInputSource source) { - this.source = source; - } - - /** - * Get the next field set from the input source, and then call - * {@link #transform(FieldSet)} on the result. Synchronizes access to the - * input source using an internal mutex as a lock. - * - * @see org.springframework.batch.item.ItemProvider#next() - */ - public final Object next() { - FieldSet fieldSet; - synchronized (mutex) { - fieldSet = this.source.readFieldSet(); - if (fieldSet != null) { - return transform(fieldSet); - } - } - return null; - } - - protected abstract Object transform(FieldSet fieldSet); -} diff --git a/infrastructure/src/main/java/org/springframework/batch/item/provider/FlatFileItemProvider.java b/infrastructure/src/main/java/org/springframework/batch/item/provider/FlatFileItemProvider.java deleted file mode 100644 index 69f48d79f..000000000 --- a/infrastructure/src/main/java/org/springframework/batch/item/provider/FlatFileItemProvider.java +++ /dev/null @@ -1,116 +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.provider; - -import java.util.Properties; - -import org.springframework.batch.io.Skippable; -import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.FieldSetMapper; -import org.springframework.batch.item.validator.Validator; -import org.springframework.batch.restart.RestartData; -import org.springframework.batch.restart.Restartable; -import org.springframework.batch.statistics.StatisticsProvider; - -/** - * - * Uses a {@link FieldSetMapper} to convert each line from an input source. Also - * adds {@link Restartable} as mandatory behaviour, delegating to the parent - * provider's input source. - * - * @author Dave Syer - */ -public class FlatFileItemProvider extends AbstractFieldSetItemProvider implements Restartable, - StatisticsProvider, Skippable { - - private FieldSetMapper mapper; - private Validator validator; - - /* - * (non-Javadoc) - * @see org.springframework.batch.item.provider.AbstractFieldSetItemProvider#doNext(org.springframework.batch.io.line.FieldSet) - */ - protected Object transform(FieldSet fieldSet) { - Object value = mapper.mapLine(fieldSet); - if (validator!=null) { - validator.validate(value); - } - return value; - } - - /** - * @param mapper the mapper to set - */ - public void setMapper(FieldSetMapper mapper) { - this.mapper = mapper; - } - - /** - * @param validator the validator to set - */ - public void setValidator(Validator validator) { - this.validator = validator; - } - - /** - * @see Restartable#getRestartData() - * @throws IllegalStateException if the parent template is not itself - * {@link Restartable}. - */ - public RestartData getRestartData() { - if (!(source instanceof Restartable)) { - throw new IllegalStateException("Input Template is not Restartable"); - } - return ((Restartable) source).getRestartData(); - } - - /** - * @see Restartable#restoreFrom(RestartData) - * @throws IllegalStateException if the parent template is not itself - * {@link Restartable}. - */ - public void restoreFrom(RestartData data) { - if (!(source instanceof Restartable)) { - throw new IllegalStateException("Input Template is not Restartable"); - } - ((Restartable) source).restoreFrom(data); - } - - /** - * @return delegates to the parent template of it is a - * {@link StatisticsProvider}, otherwise returns an empty - * {@link Properties} instance. - * @see StatisticsProvider#getStatistics() - */ - public Properties getStatistics() { - if (!(source instanceof StatisticsProvider)) { - return new Properties(); - } - return ((StatisticsProvider) source).getStatistics(); - } - - /** - * @return delegates to the input source if it is a - * {@link Skippable}. - * @see Skippable#skip() - */ - public void skip() { - if (source instanceof Skippable) { - ((Skippable) source).skip(); - } - } -} diff --git a/infrastructure/src/main/java/org/springframework/batch/item/provider/InputSourceItemProvider.java b/infrastructure/src/main/java/org/springframework/batch/item/provider/InputSourceItemProvider.java index 9eec73921..502cdc25f 100644 --- a/infrastructure/src/main/java/org/springframework/batch/item/provider/InputSourceItemProvider.java +++ b/infrastructure/src/main/java/org/springframework/batch/item/provider/InputSourceItemProvider.java @@ -23,24 +23,29 @@ import org.springframework.batch.io.Skippable; import org.springframework.batch.restart.RestartData; import org.springframework.batch.restart.Restartable; import org.springframework.batch.statistics.StatisticsProvider; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; /** * Simple wrapper around {@link InputSource}. The input source is expected to * take care of open and close operations. If necessary it should be registered * as a step scoped bean to ensure that the lifecycle methods are called. - * + * * @author Dave Syer */ -public class InputSourceItemProvider extends AbstractItemProvider implements Restartable, StatisticsProvider, Skippable { +public class InputSourceItemProvider extends AbstractItemProvider implements Restartable, StatisticsProvider, Skippable, InitializingBean{ - private InputSource source; + private InputSource inputSource; + public void afterPropertiesSet() throws Exception { + Assert.notNull(inputSource, "InputSource must not be null."); + } /** * Get the next object from the input source. * @see org.springframework.batch.item.ItemProvider#next() */ public Object next() { - Object value = source.read(); + Object value = inputSource.read(); return value; } @@ -50,10 +55,10 @@ public class InputSourceItemProvider extends AbstractItemProvider implements Res * {@link Restartable}. */ public RestartData getRestartData() { - if (!(source instanceof Restartable)) { + if (!(inputSource instanceof Restartable)) { throw new IllegalStateException("Input Template is not Restartable"); } - return ((Restartable) source).getRestartData(); + return ((Restartable) inputSource).getRestartData(); } /** @@ -62,10 +67,10 @@ public class InputSourceItemProvider extends AbstractItemProvider implements Res * {@link Restartable}. */ public void restoreFrom(RestartData data) { - if (!(source instanceof Restartable)) { + if (!(inputSource instanceof Restartable)) { throw new IllegalStateException("Input Template is not Restartable"); } - ((Restartable) source).restoreFrom(data); + ((Restartable) inputSource).restoreFrom(data); } /** @@ -75,10 +80,10 @@ public class InputSourceItemProvider extends AbstractItemProvider implements Res * @see StatisticsProvider#getStatistics() */ public Properties getStatistics() { - if (!(source instanceof StatisticsProvider)) { + if (!(inputSource instanceof StatisticsProvider)) { return new Properties(); } - return ((StatisticsProvider) source).getStatistics(); + return ((StatisticsProvider) inputSource).getStatistics(); } /** @@ -86,12 +91,16 @@ public class InputSourceItemProvider extends AbstractItemProvider implements Res * @param source */ public void setInputSource(InputSource source) { - this.source = source; + this.inputSource = source; + } + + public InputSource getInputSource() { + return inputSource; } public void skip() { - if (source instanceof Skippable) { - ((Skippable)source).skip(); + if (inputSource instanceof Skippable) { + ((Skippable)inputSource).skip(); } } } diff --git a/infrastructure/src/main/java/org/springframework/batch/item/provider/ValidatingItemProvider.java b/infrastructure/src/main/java/org/springframework/batch/item/provider/ValidatingItemProvider.java new file mode 100644 index 000000000..6acab044a --- /dev/null +++ b/infrastructure/src/main/java/org/springframework/batch/item/provider/ValidatingItemProvider.java @@ -0,0 +1,59 @@ +/* + * 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.provider; + +import org.springframework.batch.item.validator.Validator; +import org.springframework.util.Assert; + +/** + * Simple extension of InputsourceItemProvider that provides for + * validation before returning input. + * + * @author Lucas Ward + * + */ +public class ValidatingItemProvider extends InputSourceItemProvider { + + private Validator validator; + + /* (non-Javadoc) + * @see org.springframework.batch.item.provider.InputSourceItemProvider#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + super.afterPropertiesSet(); + Assert.notNull(validator, "Validator must not be null."); + } + + /* (non-Javadoc) + * @see org.springframework.batch.item.provider.InputSourceItemProvider#next() + */ + public Object next() { + Object input = super.next(); + if(input != null){ + validator.validate(input); + } + return input; + } + + /** + * Set the validator used to validate each item. + * + * @param validator + */ + public void setValidator(Validator validator) { + this.validator = validator; + } +} diff --git a/infrastructure/src/test/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSourceTests.java b/infrastructure/src/test/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSourceTests.java index abdda38f6..cd8789c7a 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSourceTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/file/support/DefaultFlatFileInputSourceTests.java @@ -21,6 +21,7 @@ import java.io.IOException; import junit.framework.TestCase; import org.springframework.batch.io.file.FieldSet; +import org.springframework.batch.io.file.FieldSetMapper; import org.springframework.batch.io.file.support.DefaultFlatFileInputSource; import org.springframework.batch.io.file.support.transform.LineTokenizer; import org.springframework.batch.restart.RestartData; @@ -30,16 +31,16 @@ import org.springframework.transaction.support.TransactionSynchronization; /** * Tests for {@link DefaultFlatFileInputSource} - * + * * @author robert.kasanicky - * + * * TODO only regular reading is tested currently, add exception cases, restart, * skip, validation... */ public class DefaultFlatFileInputSourceTests extends TestCase { // object under test - private DefaultFlatFileInputSource template = new DefaultFlatFileInputSource(); + private DefaultFlatFileInputSource inputSource = new DefaultFlatFileInputSource(); // common value used for writing to a file private String TEST_STRING = "FlatFileInputTemplate-TestData"; @@ -51,25 +52,31 @@ public class DefaultFlatFileInputSourceTests extends TestCase { } }; + 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 { - template.setResource(getInputResource(TEST_STRING)); - template.setTokenizer(tokenizer); - + inputSource.setResource(getInputResource(TEST_STRING)); + inputSource.setTokenizer(tokenizer); + inputSource.setFieldSetMapper(fieldSetMapper); // context argument is necessary only for the FileLocator, which // is mocked - template.open(); + inputSource.open(); } /** * Release resources and delete the temporary file */ protected void tearDown() throws Exception { - template.close(); + inputSource.close(); } private Resource getInputResource(String input) { @@ -82,25 +89,25 @@ public class DefaultFlatFileInputSourceTests extends TestCase { */ public void testSkip() throws IOException { - template.close(); - template.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - template.open(); + inputSource.close(); + inputSource.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); + inputSource.open(); // read some records - template.readFieldSet(); // #1 - template.readFieldSet(); // #2 + inputSource.read(); // #1 + inputSource.read(); // #2 // commit them - template.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + inputSource.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_COMMITTED); // read next record - template.readFieldSet(); // # 3 + inputSource.read(); // # 3 // mark record as skipped - template.skip(); + inputSource.skip(); // read next records - template.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); + inputSource.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); // we should now process all records after first commit point, that are // not marked as skipped - assertEquals("[testLine4]", template.readFieldSet().toString()); + assertEquals("[testLine4]", inputSource.read().toString()); // TODO update // Map statistics = template.getStatistics(); @@ -117,14 +124,14 @@ public class DefaultFlatFileInputSourceTests extends TestCase { */ public void testTransactionSynchronizationUnknown() throws IOException { - template.close(); - template.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - template.open(); + inputSource.close(); + inputSource.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); + inputSource.open(); // read some records - template.readFieldSet(); - template.skip(); - template.readFieldSet(); + inputSource.read(); + inputSource.skip(); + inputSource.read(); // TODO // statistics = template.getStatistics(); // skipped = (String) @@ -134,7 +141,7 @@ public class DefaultFlatFileInputSourceTests extends TestCase { // call unknown, which has no influence and therefore statistics should // be the same - template.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); + inputSource.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); // TODO // statistics = template.getStatistics(); // assertEquals(skipped, (String) @@ -142,51 +149,51 @@ public class DefaultFlatFileInputSourceTests extends TestCase { // assertEquals(read, (String) // statistics.get(FlatFileInputTemplate.READ_STATISTICS_NAME)); } - + public void testRestartFromNullData() throws Exception { - template.restoreFrom(null); - assertEquals("[FlatFileInputTemplate-TestData]", template.readFieldSet().toString()); + inputSource.restoreFrom(null); + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); } - + public void testRestartWithNullReader() throws Exception { - template = new DefaultFlatFileInputSource(); - template.setResource(getInputResource(TEST_STRING)); + inputSource = new DefaultFlatFileInputSource(); + inputSource.setResource(getInputResource(TEST_STRING)); // do not open the template... - template.restoreFrom(template.getRestartData()); - assertEquals("[FlatFileInputTemplate-TestData]", template.readFieldSet().toString()); + inputSource.restoreFrom(inputSource.getRestartData()); + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); } public void testRestart() throws IOException { - template.close(); - template.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - template.open(); + inputSource.close(); + inputSource.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); + inputSource.open(); // read some records - template.readFieldSet(); - template.readFieldSet(); + inputSource.read(); + inputSource.read(); // commit them - template.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_COMMITTED); + inputSource.getTransactionSynchronization().afterCompletion(TransactionSynchronization.STATUS_COMMITTED); // read next two records - template.readFieldSet(); - template.readFieldSet(); + inputSource.read(); + inputSource.read(); // get restart data - RestartData restartData = template.getRestartData(); + RestartData restartData = inputSource.getRestartData(); // TODO // assertEquals("4", (String) restartData); // close input - template.close(); + inputSource.close(); - template.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); + inputSource.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); // init for restart - template.open(); - template.restoreFrom(restartData); + inputSource.open(); + inputSource.restoreFrom(restartData); // read remaining records - assertEquals("[testLine5]", template.readFieldSet().toString()); - assertEquals("[testLine6]", template.readFieldSet().toString()); + assertEquals("[testLine5]", inputSource.read().toString()); + assertEquals("[testLine6]", inputSource.read().toString()); // TODO // Map statistics = template.getStatistics(); 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 50b770561..191f6a51f 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 @@ -23,8 +23,10 @@ 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.exception.ValidationException; 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; @@ -33,14 +35,14 @@ import org.springframework.core.io.Resource; /** * Tests for {@link SimpleFlatFileInputSourceTests} - * + * * @author Dave Syer - * + * */ public class SimpleFlatFileInputSourceTests extends TestCase { // object under test - private SimpleFlatFileInputSource template = new SimpleFlatFileInputSource(); + private SimpleFlatFileInputSource inputSource = new SimpleFlatFileInputSource(); // common value used for writing to a file private String TEST_STRING = "FlatFileInputTemplate-TestData"; @@ -52,101 +54,117 @@ public class SimpleFlatFileInputSourceTests extends TestCase { } }; + 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 { - template.setResource(getInputResource(TEST_STRING)); - template.setTokenizer(tokenizer); - template.afterPropertiesSet(); + inputSource.setResource(getInputResource(TEST_STRING)); + inputSource.setTokenizer(tokenizer); + inputSource.setFieldSetMapper(fieldSetMapper); + inputSource.afterPropertiesSet(); // context argument is necessary only for the FileLocator, which // is mocked - template.open(); + inputSource.open(); } /** * Release resources. */ protected void tearDown() throws Exception { - template.close(); + inputSource.close(); } private Resource getInputResource(String input) { return new ByteArrayResource(input.getBytes()); } - /** - * Regular usage of read method - */ - public void testReadFieldSet() throws IOException { - assertEquals("[FlatFileInputTemplate-TestData]", template.readFieldSet().toString()); - } - /** * Regular usage of read method */ public void testRead() throws IOException { - assertEquals("[FlatFileInputTemplate-TestData]", template.read().toString()); + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); } /** * Regular usage of read method */ public void testReadExhausted() throws IOException { - assertEquals("[FlatFileInputTemplate-TestData]", template.read().toString()); - assertEquals(null, template.read()); + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); + assertEquals(null, inputSource.read()); } /** * Regular usage of read method */ - public void testReadWithError() throws IOException { - template.setTokenizer(new LineTokenizer() { + public void testReadWithTokenizerError() throws IOException { + inputSource.setTokenizer(new LineTokenizer() { public FieldSet tokenize(String line) { throw new RuntimeException("foo"); } }); try { - template.read(); - fail("Expected ValidationException"); - } catch (ValidationException e) { - assertTrue(e.getMessage().indexOf("at line")>=0); - assertTrue(e.getMessage().indexOf("at line 1")>=0); + 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 { - template = new SimpleFlatFileInputSource(); - template.setResource(getInputResource(TEST_STRING)); - assertEquals("[FlatFileInputTemplate-TestData]", template.readFieldSet().toString()); + inputSource = new SimpleFlatFileInputSource(); + inputSource.setResource(getInputResource(TEST_STRING)); + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); } public void testCloseBeforeOpen() throws Exception { - template = new SimpleFlatFileInputSource(); - template.setResource(getInputResource(TEST_STRING)); - template.close(); + inputSource = new SimpleFlatFileInputSource(); + inputSource.setResource(getInputResource(TEST_STRING)); + inputSource.close(); // The open still happens automatically on a read... - assertEquals("[FlatFileInputTemplate-TestData]", template.readFieldSet().toString()); + assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString()); } public void testCloseOnDestroy() throws Exception { final List list = new ArrayList(); - template = new SimpleFlatFileInputSource() { + inputSource = new SimpleFlatFileInputSource() { public void close() { list.add("close"); } }; - template.destroy(); + inputSource.destroy(); assertEquals(1, list.size()); } public void testInitializationWithNullResource() throws Exception { - template = new SimpleFlatFileInputSource(); + inputSource = new SimpleFlatFileInputSource(); try { - template.afterPropertiesSet(); + inputSource.afterPropertiesSet(); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { @@ -155,23 +173,23 @@ public class SimpleFlatFileInputSourceTests extends TestCase { } public void testOpenTwiceHasNoEffect() throws Exception { - template.open(); + inputSource.open(); testRead(); } public void testSetValidEncoding() throws Exception { - template = new SimpleFlatFileInputSource(); - template.setEncoding("UTF-8"); - template.setResource(getInputResource(TEST_STRING)); + inputSource = new SimpleFlatFileInputSource(); + inputSource.setEncoding("UTF-8"); + inputSource.setResource(getInputResource(TEST_STRING)); testRead(); } public void testSetNullEncoding() throws Exception { - template = new SimpleFlatFileInputSource(); - template.setEncoding(null); - template.setResource(getInputResource(TEST_STRING)); + inputSource = new SimpleFlatFileInputSource(); + inputSource.setEncoding(null); + inputSource.setResource(getInputResource(TEST_STRING)); try { - template.open(); + inputSource.open(); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { @@ -180,11 +198,11 @@ public class SimpleFlatFileInputSourceTests extends TestCase { } public void testSetInvalidEncoding() throws Exception { - template = new SimpleFlatFileInputSource(); - template.setEncoding("foo"); - template.setResource(getInputResource(TEST_STRING)); + inputSource = new SimpleFlatFileInputSource(); + inputSource.setEncoding("foo"); + inputSource.setResource(getInputResource(TEST_STRING)); try { - template.open(); + inputSource.open(); fail("Expected BatchEnvironmentException"); } catch (BatchEnvironmentException e) { @@ -194,12 +212,12 @@ public class SimpleFlatFileInputSourceTests extends TestCase { } public void testEncoding() throws Exception { - template.setEncoding("UTF-8"); + inputSource.setEncoding("UTF-8"); testRead(); } public void testRecordSeparator() throws Exception { - template.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); + inputSource.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); testRead(); } diff --git a/infrastructure/src/test/java/org/springframework/batch/item/provider/AbstractFieldSetItemProviderTests.java b/infrastructure/src/test/java/org/springframework/batch/item/provider/AbstractFieldSetItemProviderTests.java deleted file mode 100644 index 0f313ed08..000000000 --- a/infrastructure/src/test/java/org/springframework/batch/item/provider/AbstractFieldSetItemProviderTests.java +++ /dev/null @@ -1,59 +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.provider; - -import junit.framework.TestCase; - -import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.FieldSetInputSource; -import org.springframework.batch.io.file.support.SimpleFlatFileInputSource; -import org.springframework.core.io.ByteArrayResource; - -/** - * @author Dave Syer - * - */ -public class AbstractFieldSetItemProviderTests extends TestCase { - - public void testNotOpen() throws Exception { - TestItemProvider provider = new TestItemProvider(); - provider.setSource(getInputSource("one\ntwo\nthree")); - assertNotNull(provider.next()); - } - - public void testAfterPropertiesSet() throws Exception { - TestItemProvider provider = new TestItemProvider(); - try { - provider.afterPropertiesSet(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } - } - - private static class TestItemProvider extends AbstractFieldSetItemProvider { - protected Object transform(FieldSet fieldSet) { - return fieldSet.toString(); - } - } - - private FieldSetInputSource getInputSource(String data) throws Exception { - SimpleFlatFileInputSource template = new SimpleFlatFileInputSource(); - template.setResource(new ByteArrayResource(data.getBytes())); - template.afterPropertiesSet(); - return template; - } -} diff --git a/infrastructure/src/test/java/org/springframework/batch/item/provider/FieldSetItemProviderTests.java b/infrastructure/src/test/java/org/springframework/batch/item/provider/FieldSetItemProviderTests.java deleted file mode 100644 index 6c5cf7bdc..000000000 --- a/infrastructure/src/test/java/org/springframework/batch/item/provider/FieldSetItemProviderTests.java +++ /dev/null @@ -1,54 +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.provider; - -import junit.framework.TestCase; - -import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.support.SimpleFlatFileInputSource; -import org.springframework.core.io.ByteArrayResource; - -public class FieldSetItemProviderTests extends TestCase { - - public void testNotOpen() throws Exception { - TestItemProvider provider = new TestItemProvider("one\ntwo\nthree"); - assertNotNull(provider.next()); - } - - public void testNext() throws Exception { - TestItemProvider provider = new TestItemProvider("one\ntwo\nthree"); - assertEquals("[one]", provider.next()); - assertEquals("[two]", provider.next()); - assertEquals("[three]", provider.next()); - assertEquals(null, provider.next()); - } - - private static class TestItemProvider extends AbstractFieldSetItemProvider { - public TestItemProvider(String data) throws Exception { - super(); - SimpleFlatFileInputSource template = new SimpleFlatFileInputSource(); - template.setResource(new ByteArrayResource(data.getBytes())); - template.afterPropertiesSet(); - setSource(template); - } - - protected Object transform(FieldSet fieldSet) { - return fieldSet.toString(); - } - } - -} diff --git a/infrastructure/src/test/java/org/springframework/batch/item/provider/FlatFileItemProviderTests.java b/infrastructure/src/test/java/org/springframework/batch/item/provider/FlatFileItemProviderTests.java deleted file mode 100644 index f872491f5..000000000 --- a/infrastructure/src/test/java/org/springframework/batch/item/provider/FlatFileItemProviderTests.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.provider; - -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import junit.framework.TestCase; - -import org.springframework.batch.io.Skippable; -import org.springframework.batch.io.exception.ValidationException; -import org.springframework.batch.io.file.FieldSet; -import org.springframework.batch.io.file.FieldSetInputSource; -import org.springframework.batch.io.file.FieldSetMapper; -import org.springframework.batch.io.file.support.DefaultFlatFileInputSource; -import org.springframework.batch.item.provider.FlatFileItemProvider; -import org.springframework.batch.item.validator.Validator; -import org.springframework.batch.restart.GenericRestartData; -import org.springframework.batch.restart.RestartData; -import org.springframework.batch.restart.Restartable; -import org.springframework.batch.statistics.StatisticsProvider; -import org.springframework.batch.support.PropertiesConverter; -import org.springframework.core.io.ByteArrayResource; - -/** - * Unit tests for {@link FlatFileItemProvider} - * - * @author Robert Kasanicky - * @author Dave Syer - */ -public class FlatFileItemProviderTests extends TestCase { - - public static String FOO = "foo"; - // object under test - private FlatFileItemProvider itemProvider = new FlatFileItemProvider(); - - // Input source - private DefaultFlatFileInputSource source; - - // mock mapper - private FieldSetMapper mapper; - - private List list = new ArrayList(); - - // create mock objects and inject them into data provider - protected void setUp() throws Exception { - source = new DefaultFlatFileInputSource() { - public void skip() { - super.skip(); - list.add("skipped"); - } - }; - source.setResource(new ByteArrayResource("a,b".getBytes())); - mapper = new FieldSetMapper() { - public Object mapLine(FieldSet fs) { - return FOO; - } - }; - itemProvider.setSource(source); - itemProvider.setMapper(mapper); - assertTrue(Restartable.class - .isAssignableFrom(DefaultFlatFileInputSource.class)); - assertTrue(Skippable.class - .isAssignableFrom(DefaultFlatFileInputSource.class)); - assertTrue(FieldSetInputSource.class - .isAssignableFrom(DefaultFlatFileInputSource.class)); - assertTrue(StatisticsProvider.class - .isAssignableFrom(DefaultFlatFileInputSource.class)); - } - - /** - * Uses input template to provide the domain object. - */ - public void testNext() { - Object result = itemProvider.next(); - assertSame("domain object is provided by the input template", FOO, - result); - } - - /** - * Uses input template to provide the domain object. - */ - public void testNextWithValidator() { - itemProvider.setValidator(new Validator() { - public void validate(Object value) throws ValidationException { - list.add(value); - } - }); - itemProvider.next(); - assertSame("domain object is provided by the input template", FOO, list - .get(0)); - } - - /** - * Uses input template to provide the domain object. - */ - public void testNextWithValidatorAndInvalidData() { - itemProvider.setValidator(new Validator() { - public void validate(Object value) throws ValidationException { - throw new ValidationException("Invalid input"); - } - }); - try { - itemProvider.next(); - fail("Expected ValidationException"); - } catch (ValidationException e) { - // expected - assertEquals("Invalid input", e.getMessage()); - } - } - - /** - * Gets statistics from the input template - */ - public void testGetStatistics() { - Properties statistics = ((StatisticsProvider) source).getStatistics(); - assertEquals(statistics, itemProvider.getStatistics()); - } - - /** - * Gets statistics from the input template - */ - public void testGetStatisticsWithoutStatisticsProvider() { - itemProvider.setSource(null); - Properties props = itemProvider.getStatistics(); - assertEquals(null, props.getProperty("a")); - } - - /** - * Gets restart data from the input template - */ - public void testGetRestartData() { - RestartData data = ((Restartable) source).getRestartData(); - assertEquals(data.getProperties(), itemProvider.getRestartData() - .getProperties()); - } - - /** - * Forwarded restart data to input template - */ - public void testRestoreFrom() { - - final List list = new ArrayList(); - - RestartData data = new RestartData() { - - public Properties getProperties() { - list.add(FOO); - return ((Restartable) source).getRestartData().getProperties(); - } - }; - - itemProvider.restoreFrom(data); - - // assertEquals(1, list.size()); getProperties are called multiple times - // due to null checks - assertTrue(list.size() > 0); - } - - /** - * Forward restart data to input template - * - * @throws Exception - */ - public void testRestoreFromWithoutRestartable() throws Exception { - itemProvider.setSource(null); - try { - itemProvider.restoreFrom(new GenericRestartData(PropertiesConverter - .stringToProperties("value=bar"))); - fail("Expected IllegalStateException"); - } catch (IllegalStateException e) { - // expected - } - } - - /** - * Forward restart data to input template - * - * @throws Exception - */ - public void testGetRestartDataWithoutRestartable() throws Exception { - itemProvider.setSource(null); - try { - itemProvider.getRestartData(); - fail("Expected IllegalStateException"); - } catch (IllegalStateException e) { - // expected - } - } - - /** - * Forward restart data to input template - * - * @throws Exception - */ - public void testSkippable() throws Exception { - assertEquals(0, list.size()); - itemProvider.skip(); - assertEquals(1, list.size()); - } - -} diff --git a/infrastructure/src/test/java/org/springframework/batch/item/provider/InputSourceItemProviderTests.java b/infrastructure/src/test/java/org/springframework/batch/item/provider/InputSourceItemProviderTests.java index 1157fece8..099819f58 100644 --- a/infrastructure/src/test/java/org/springframework/batch/item/provider/InputSourceItemProviderTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/item/provider/InputSourceItemProviderTests.java @@ -31,7 +31,7 @@ import org.springframework.batch.support.PropertiesConverter; /** * Unit test for {@link InputSourceItemProvider} - * + * * @author Robert Kasanicky */ public class InputSourceItemProviderTests extends TestCase { @@ -47,6 +47,21 @@ public class InputSourceItemProviderTests extends TestCase { itemProvider.setInputSource(source); } + public void testAfterPropertiesSet()throws Exception{ + //shouldn't throw an exception since the input source is set + itemProvider.afterPropertiesSet(); + } + + public void testNullInputSource(){ + try{ + itemProvider.setInputSource(null); + itemProvider.afterPropertiesSet(); + fail(); + }catch(Exception ex){ + assertTrue(ex instanceof IllegalArgumentException); + } + } + /** * Uses input template to provide the domain object. */ @@ -78,7 +93,7 @@ public class InputSourceItemProviderTests extends TestCase { itemProvider.restoreFrom(new GenericRestartData(PropertiesConverter.stringToProperties("value=bar"))); assertEquals("bar", itemProvider.next()); } - + public void testSkip() { itemProvider.skip(); assertEquals("after skip", itemProvider.next()); @@ -87,7 +102,7 @@ public class InputSourceItemProviderTests extends TestCase { private class MockInputSource implements InputSource, StatisticsProvider, Restartable, Skippable { private Object value; - + public Properties getStatistics() { return PropertiesConverter.stringToProperties("a=b"); } diff --git a/infrastructure/src/test/java/org/springframework/batch/item/provider/ValidatingItemProviderTests.java b/infrastructure/src/test/java/org/springframework/batch/item/provider/ValidatingItemProviderTests.java new file mode 100644 index 000000000..13ebc0769 --- /dev/null +++ b/infrastructure/src/test/java/org/springframework/batch/item/provider/ValidatingItemProviderTests.java @@ -0,0 +1,114 @@ +/* + * 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.provider; + +import org.easymock.MockControl; +import org.springframework.batch.io.InputSource; +import org.springframework.batch.io.exception.ValidationException; +import org.springframework.batch.item.validator.Validator; + +import junit.framework.TestCase; + +/** + * @author Lucas Ward + * + */ +public class ValidatingItemProviderTests extends TestCase { + + InputSource inputSource; + ValidatingItemProvider itemProvider; + Validator validator; + MockControl validatorControl = MockControl.createControl(Validator.class); + + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + + inputSource = new MockInputSource(this); + validator = (Validator)validatorControl.getMock(); + itemProvider = new ValidatingItemProvider(); + itemProvider.setInputSource(inputSource); + itemProvider.setValidator(validator); + } + + /* + * Super class' afterPropertieSet should be called to + * ensure InputSource is set. + */ + public void testInputSourcePropertiesSet(){ + try{ + itemProvider.setInputSource(null); + itemProvider.afterPropertiesSet(); + fail(); + }catch(Exception ex){ + assertTrue(ex instanceof IllegalArgumentException); + } + } + + public void testValidatorPropertesSet(){ + try{ + itemProvider.setValidator(null); + itemProvider.afterPropertiesSet(); + fail(); + }catch(Exception ex){ + assertTrue(ex instanceof IllegalArgumentException); + } + } + + public void testValidation(){ + + validator.validate(this); + validatorControl.replay(); + assertEquals(itemProvider.next(), this); + validatorControl.verify(); + } + + public void testValidationException(){ + + validator.validate(this); + validatorControl.setThrowable(new ValidationException("")); + validatorControl.replay(); + try{ + itemProvider.next(); + fail(); + }catch(ValidationException ex){ + //expected + } + } + + public void testNullInput(){ + validatorControl.replay(); + itemProvider.setInputSource(new MockInputSource(null)); + assertNull(itemProvider.next()); + //assert validator wasn't called. + validatorControl.verify(); + } + + private class MockInputSource implements InputSource{ + + Object value; + + public MockInputSource(Object value){ + this.value = value; + } + + public Object read() { + return value; + } + } +} diff --git a/infrastructure/src/test/java/org/springframework/batch/repeat/support/AbstractTradeBatchTests.java b/infrastructure/src/test/java/org/springframework/batch/repeat/support/AbstractTradeBatchTests.java index 8f265abb8..9d56e0fcb 100644 --- a/infrastructure/src/test/java/org/springframework/batch/repeat/support/AbstractTradeBatchTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/repeat/support/AbstractTradeBatchTests.java @@ -19,17 +19,18 @@ package org.springframework.batch.repeat.support; import junit.framework.TestCase; import org.springframework.batch.io.file.FieldSet; +import org.springframework.batch.io.file.FieldSetMapper; import org.springframework.batch.io.file.support.SimpleFlatFileInputSource; import org.springframework.batch.item.ItemProcessor; -import org.springframework.batch.item.provider.AbstractFieldSetItemProvider; +import org.springframework.batch.item.provider.InputSourceItemProvider; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; /** * Base class for simple tests with small trade data set. - * + * * @author Dave Syer - * + * */ public abstract class AbstractTradeBatchTests extends TestCase { @@ -46,18 +47,21 @@ public abstract class AbstractTradeBatchTests extends TestCase { provider = new TradeItemProvider(resource); } - protected static class TradeItemProvider extends AbstractFieldSetItemProvider { + protected static class TradeItemProvider extends InputSourceItemProvider { protected TradeItemProvider(Resource resource) throws Exception { super(); - SimpleFlatFileInputSource template = new SimpleFlatFileInputSource(); - template.setResource(resource); - template.afterPropertiesSet(); - setSource(template); + SimpleFlatFileInputSource inputSource = new SimpleFlatFileInputSource(); + inputSource.setResource(resource); + inputSource.setFieldSetMapper(new TradeMapper()); + inputSource.afterPropertiesSet(); + setInputSource(inputSource); } + } - protected Object transform(FieldSet fieldSet) { - return new Trade(fieldSet); + protected static class TradeMapper implements FieldSetMapper{ + public Object mapLine(FieldSet fs) { + return new Trade(fs); } }