BATCH-140: Modified file input sources to no longer implemented FieldSet and now accept an injected mapper.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.<br/>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @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) {
|
||||
|
||||
@@ -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. <br/>
|
||||
*
|
||||
*
|
||||
* 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.<br/>
|
||||
*
|
||||
*
|
||||
* @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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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 <code>read</code> method
|
||||
*/
|
||||
public void testReadFieldSet() throws IOException {
|
||||
assertEquals("[FlatFileInputTemplate-TestData]", template.readFieldSet().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular usage of <code>read</code> method
|
||||
*/
|
||||
public void testRead() throws IOException {
|
||||
assertEquals("[FlatFileInputTemplate-TestData]", template.read().toString());
|
||||
assertEquals("[FlatFileInputTemplate-TestData]", inputSource.read().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular usage of <code>read</code> 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 <code>read</code> 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user