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 index c3cf23adf..e98a38e81 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/exception/FlatFileParsingException.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/exception/FlatFileParsingException.java @@ -27,6 +27,8 @@ package org.springframework.batch.io.exception; */ public class FlatFileParsingException extends ParsingException { + private static final long serialVersionUID = 2529197834044942724L; + private String input; private int lineNumber; diff --git a/infrastructure/src/main/java/org/springframework/batch/io/exception/ParsingException.java b/infrastructure/src/main/java/org/springframework/batch/io/exception/ParsingException.java index 9bf5c3271..cdaf1659c 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/exception/ParsingException.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/exception/ParsingException.java @@ -24,6 +24,8 @@ package org.springframework.batch.io.exception; */ public class ParsingException extends RuntimeException { + private static final long serialVersionUID = 2953386084409312312L; + public ParsingException(String message) { super(message); } diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java b/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java index 03dbd973c..fc062c876 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/file/FieldSet.java @@ -1,612 +1,625 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.io.file; - -import java.math.BigDecimal; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Properties; - -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * @author Rob Harrop - * @author Dave Syer - */ -public final class FieldSet { - - private final static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; - - /** - * The fields wrapped by this 'FieldSet' instance. - */ - private String[] tokens; - - private List names; - - public FieldSet(String[] tokens) { - this.tokens = tokens; - } - - public FieldSet(String[] tokens, String[] names) { - if (tokens.length != names.length) { - throw new IllegalArgumentException( - "Field names must be same length as values: names=" - + Arrays.asList(names) + ", values=" - + Arrays.asList(tokens)); - } - this.tokens = tokens; - this.names = Arrays.asList(names); - } - - /** - * Read the {@link String} value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public String readString(int index) { - return readAndTrim(index); - } - - /** - * Read the {@link String} value from column with given 'name'. - * - * @param name - * the field name. - */ - public String readString(String name) { - return readString(indexOf(name)); - } - - /** - * Read the 'boolean' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public boolean readBoolean(int index) { - return readBoolean(index, "true"); - } - - /** - * Read the 'boolean' value from column with given 'name'. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public boolean readBoolean(String name) { - return readBoolean(indexOf(name)); - } - - /** - * Read the 'boolean' value at index 'index'. - * - * @param index - * the field index. - * @param trueValue - * the value that signifies {@link Boolean#TRUE true}; - * case-sensitive. - * @throws IndexOutOfBoundsException - * if the index is out of bounds, or if the supplied - * trueValue is null. - */ - public boolean readBoolean(int index, String trueValue) { - Assert.notNull(trueValue, "'trueValue' cannot be null."); - - String value = readAndTrim(index); - - return trueValue.equals(value) ? true : false; - } - - /** - * Read the 'boolean' value from column with given 'name'. - * - * @param name - * the field name. - * @param trueValue - * the value that signifies {@link Boolean#TRUE true}; - * case-sensitive. - * @throws IllegalArgumentException - * if a column with given name is not defined, or if the - * supplied trueValue is null. - */ - public boolean readBoolean(String name, String trueValue) { - return readBoolean(indexOf(name), trueValue); - } - - /** - * Read the 'char' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public char readChar(int index) { - String value = readAndTrim(index); - - Assert.isTrue(value.length() == 1, "Cannot convert field value '" - + value + "' to char."); - - return value.charAt(0); - } - - /** - * Read the 'char' value from column with given 'name'. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public char readChar(String name) { - return readChar(indexOf(name)); - } - - /** - * Read the 'byte' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public byte readByte(int index) { - return Byte.parseByte(readAndTrim(index)); - } - - /** - * Read the 'byte' value from column with given 'name'. - * - * @param name - * the field name. - */ - public byte readByte(String name) { - return readByte(indexOf(name)); - } - - /** - * Read the 'short' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public short readShort(int index) { - return Short.parseShort(readAndTrim(index)); - } - - /** - * Read the 'short' value from column with given 'name'. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public short readShort(String name) { - return readShort(indexOf(name)); - } - - /** - * Read the 'int' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public int readInt(int index) { - return Integer.parseInt(readAndTrim(index)); - } - - /** - * Read the 'int' value from column with given 'name'. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public int readInt(String name) { - return readInt(indexOf(name)); - } - - /** - * Read the 'int' value at index 'index', - * using the supplied defaultValue if the field value is - * blank. - * - * @param index - * the field index.. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public int readInt(int index, int defaultValue) { - String value = readAndTrim(index); - - return StringUtils.hasLength(value) ? Integer.parseInt(value) - : defaultValue; - } - - /** - * Read the 'int' value from column with given 'name', - * using the supplied defaultValue if the field value is - * blank. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public int readInt(String name, int defaultValue) { - return readInt(indexOf(name), defaultValue); - } - - /** - * Read the 'long' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public long readLong(int index) { - return Long.parseLong(readAndTrim(index)); - } - - /** - * Read the 'long' value from column with given 'name'. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public long readLong(String name) { - return readLong(indexOf(name)); - } - - /** - * Read the 'long' value at index 'index', - * using the supplied defaultValue if the field value is - * blank. - * - * @param index - * the field index.. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public long readLong(int index, long defaultValue) { - String value = readAndTrim(index); - - return StringUtils.hasLength(value) ? Long.parseLong(value) - : defaultValue; - } - - /** - * Read the 'long' value from column with given 'name', - * using the supplied defaultValue if the field value is - * blank. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public long readLong(String name, long defaultValue) { - return readLong(indexOf(name), defaultValue); - } - - /** - * Read the 'float' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public float readFloat(int index) { - return Float.parseFloat(readAndTrim(index)); - } - - /** - * Read the 'float' value from column with given 'name. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public float readFloat(String name) { - return readFloat(indexOf(name)); - } - - /** - * Read the 'double' value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public double readDouble(int index) { - return Double.parseDouble(readAndTrim(index)); - } - - /** - * Read the 'double' value from column with given 'name. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public double readDouble(String name) { - return readDouble(indexOf(name)); - } - - /** - * Read the {@link java.math.BigDecimal} value at index 'index'. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public BigDecimal readBigDecimal(int index) { - return readBigDecimal(index, null); - } - - /** - * Read the {@link java.math.BigDecimal} value from column with given 'name. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public BigDecimal readBigDecimal(String name) { - return readBigDecimal(name, null); - } - - /** - * Read the {@link BigDecimal} value at index 'index', - * returning the supplied defaultValue if the trimmed string - * value at index 'index' is blank. - * - * @param index - * the field index. - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - */ - public BigDecimal readBigDecimal(int index, BigDecimal defaultValue) { - String candidate = readAndTrim(index); - - try { - return (StringUtils.hasText(candidate)) ? new BigDecimal(candidate) - : defaultValue; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Unparseable number: " - + candidate); - } - } - - /** - * Read the {@link BigDecimal} value from column with given 'name, - * returning the supplied defaultValue if the trimmed string - * value at index 'index' is blank. - * - * @param name - * the field name. - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - public BigDecimal readBigDecimal(String name, BigDecimal defaultValue) { - try { - return readBigDecimal(indexOf(name), defaultValue); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException(e.getMessage() + ", name: [" - + name + "]"); - } - } - - /** - * Read the java.util.Date value in default format at - * designated column index. - * - * @param index - * the field index. - * @param pattern - * the pattern describing the date and time format - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - * @see #DEFAULT_DATE_PATTERN - */ - public Date readDate(int index) { - return readDate(index, DEFAULT_DATE_PATTERN); - } - - /** - * Read the java.sql.Date value in given format from column - * with given name. - * - * @param name - * the field name. - * @param pattern - * the pattern describing the date and time format - * @throws IllegalArgumentException - * if a column with given name is not defined. - * @see #DEFAULT_DATE_PATTERN - */ - public Date readDate(String name) { - return readDate(name, DEFAULT_DATE_PATTERN); - } - - /** - * Read the java.util.Date value in default format at - * designated column index. - * - * @param index - * the field index. - * @param pattern - * the pattern describing the date and time format - * @throws IndexOutOfBoundsException - * if the index is out of bounds. - * @throws IllegalArgumentException - * if the date cannot be parsed. - * - */ - public Date readDate(int index, String pattern) { - SimpleDateFormat sdf = new SimpleDateFormat(pattern); - Date date; - String value = readAndTrim(index); - try { - date = sdf.parse(value); - } catch (ParseException e) { - throw new IllegalArgumentException(e.getMessage() + ", pattern: [" - + pattern + "]"); - } - return date; - } - - /** - * Read the java.sql.Date value in given format from column - * with given name. - * - * @param name - * the field name. - * @param pattern - * the pattern describing the date and time format - * @throws IllegalArgumentException - * if a column with given name is not defined or if the - * specified field cannot be parsed - * - */ - public Date readDate(String name, String pattern) { - try { - return readDate(indexOf(name), pattern); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException(e.getMessage() + ", name: [" - + name + "]"); - } - } - - /** - * Return the number of fields in this 'FieldSet'. - */ - public int getFieldCount() { - return tokens.length; - } - - /** - * Read and trim the {@link String} value at 'index'. - * - * @throws NullPointerException - * if the field value is null. - */ - private String readAndTrim(int index) { - String value = tokens[index]; - - if (value != null) { - return value.trim(); - } else { - return value; - } - } - - /** - * Read and trim the {@link String} value from column with given 'name. - * - * @throws IllegalArgumentException - * if a column with given name is not defined. - */ - private int indexOf(String name) { - if (names == null) { - throw new IllegalArgumentException( - "Cannot access columns by name without meta data"); - } - int index = names.indexOf(name); - if (index >= 0) { - return index; - } - throw new IllegalArgumentException("Cannot access column [" + name - + "] from " + names); - } - - public String toString() { - if (names != null) { - return getProperties().toString(); - } - // TODO return "" instead of null? - return tokens == null ? null : Arrays.asList(tokens).toString(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object object) { - if (object instanceof FieldSet) { - FieldSet fs = (FieldSet) object; - - if (this.tokens == null) { - return fs.tokens == null; - } else { - return Arrays.equals(this.tokens, fs.tokens); - } - } - - return false; - } - - public int hashCode() { - return (tokens == null) ? 0 : tokens.hashCode(); - } - - /** - * Construct name-value pairs from the field names and string values. - * - * @return some properties representing the field set. - * - * @throws IllegalStateException - * if the field name meta data is not available. - */ - public Properties getProperties() { - if (names == null) { - throw new IllegalStateException( - "Cannot create properties without meta data"); - } - Properties props = new Properties(); - for (int i = 0; i < tokens.length; i++) { - props.setProperty((String) names.get(i), readAndTrim(i)); - } - return props; - } - -} +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.batch.io.file; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * @author Rob Harrop + * @author Dave Syer + */ +public final class FieldSet { + + private final static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; + + /** + * The fields wrapped by this 'FieldSet' instance. + */ + private String[] tokens; + + private List names; + + public FieldSet(String[] tokens) { + this.tokens = tokens == null ? null : (String[])tokens.clone(); + } + + public FieldSet(String[] tokens, String[] names) { + Assert.notNull(tokens); + Assert.notNull(names); + if (tokens.length != names.length) { + throw new IllegalArgumentException( + "Field names must be same length as values: names=" + + Arrays.asList(names) + ", values=" + + Arrays.asList(tokens)); + } + this.tokens = (String[])tokens.clone(); + this.names = Arrays.asList(names); + } + + /** + * Read the {@link String} value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public String readString(int index) { + return readAndTrim(index); + } + + /** + * Read the {@link String} value from column with given 'name'. + * + * @param name + * the field name. + */ + public String readString(String name) { + return readString(indexOf(name)); + } + + /** + * Read the 'boolean' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public boolean readBoolean(int index) { + return readBoolean(index, "true"); + } + + /** + * Read the 'boolean' value from column with given 'name'. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public boolean readBoolean(String name) { + return readBoolean(indexOf(name)); + } + + /** + * Read the 'boolean' value at index 'index'. + * + * @param index + * the field index. + * @param trueValue + * the value that signifies {@link Boolean#TRUE true}; + * case-sensitive. + * @throws IndexOutOfBoundsException + * if the index is out of bounds, or if the supplied + * trueValue is null. + */ + public boolean readBoolean(int index, String trueValue) { + Assert.notNull(trueValue, "'trueValue' cannot be null."); + + String value = readAndTrim(index); + + return trueValue.equals(value) ? true : false; + } + + /** + * Read the 'boolean' value from column with given 'name'. + * + * @param name + * the field name. + * @param trueValue + * the value that signifies {@link Boolean#TRUE true}; + * case-sensitive. + * @throws IllegalArgumentException + * if a column with given name is not defined, or if the + * supplied trueValue is null. + */ + public boolean readBoolean(String name, String trueValue) { + return readBoolean(indexOf(name), trueValue); + } + + /** + * Read the 'char' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public char readChar(int index) { + String value = readAndTrim(index); + + Assert.isTrue(value.length() == 1, "Cannot convert field value '" + + value + "' to char."); + + return value.charAt(0); + } + + /** + * Read the 'char' value from column with given 'name'. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public char readChar(String name) { + return readChar(indexOf(name)); + } + + /** + * Read the 'byte' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public byte readByte(int index) { + return Byte.parseByte(readAndTrim(index)); + } + + /** + * Read the 'byte' value from column with given 'name'. + * + * @param name + * the field name. + */ + public byte readByte(String name) { + return readByte(indexOf(name)); + } + + /** + * Read the 'short' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public short readShort(int index) { + return Short.parseShort(readAndTrim(index)); + } + + /** + * Read the 'short' value from column with given 'name'. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public short readShort(String name) { + return readShort(indexOf(name)); + } + + /** + * Read the 'int' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public int readInt(int index) { + return Integer.parseInt(readAndTrim(index)); + } + + /** + * Read the 'int' value from column with given 'name'. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public int readInt(String name) { + return readInt(indexOf(name)); + } + + /** + * Read the 'int' value at index 'index', + * using the supplied defaultValue if the field value is + * blank. + * + * @param index + * the field index.. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public int readInt(int index, int defaultValue) { + String value = readAndTrim(index); + + return StringUtils.hasLength(value) ? Integer.parseInt(value) + : defaultValue; + } + + /** + * Read the 'int' value from column with given 'name', + * using the supplied defaultValue if the field value is + * blank. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public int readInt(String name, int defaultValue) { + return readInt(indexOf(name), defaultValue); + } + + /** + * Read the 'long' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public long readLong(int index) { + return Long.parseLong(readAndTrim(index)); + } + + /** + * Read the 'long' value from column with given 'name'. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public long readLong(String name) { + return readLong(indexOf(name)); + } + + /** + * Read the 'long' value at index 'index', + * using the supplied defaultValue if the field value is + * blank. + * + * @param index + * the field index.. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public long readLong(int index, long defaultValue) { + String value = readAndTrim(index); + + return StringUtils.hasLength(value) ? Long.parseLong(value) + : defaultValue; + } + + /** + * Read the 'long' value from column with given 'name', + * using the supplied defaultValue if the field value is + * blank. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public long readLong(String name, long defaultValue) { + return readLong(indexOf(name), defaultValue); + } + + /** + * Read the 'float' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public float readFloat(int index) { + return Float.parseFloat(readAndTrim(index)); + } + + /** + * Read the 'float' value from column with given 'name. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public float readFloat(String name) { + return readFloat(indexOf(name)); + } + + /** + * Read the 'double' value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public double readDouble(int index) { + return Double.parseDouble(readAndTrim(index)); + } + + /** + * Read the 'double' value from column with given 'name. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public double readDouble(String name) { + return readDouble(indexOf(name)); + } + + /** + * Read the {@link java.math.BigDecimal} value at index 'index'. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public BigDecimal readBigDecimal(int index) { + return readBigDecimal(index, null); + } + + /** + * Read the {@link java.math.BigDecimal} value from column with given 'name. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public BigDecimal readBigDecimal(String name) { + return readBigDecimal(name, null); + } + + /** + * Read the {@link BigDecimal} value at index 'index', + * returning the supplied defaultValue if the trimmed string + * value at index 'index' is blank. + * + * @param index + * the field index. + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + */ + public BigDecimal readBigDecimal(int index, BigDecimal defaultValue) { + String candidate = readAndTrim(index); + + try { + return (StringUtils.hasText(candidate)) ? new BigDecimal(candidate) + : defaultValue; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Unparseable number: " + + candidate); + } + } + + /** + * Read the {@link BigDecimal} value from column with given 'name, + * returning the supplied defaultValue if the trimmed string + * value at index 'index' is blank. + * + * @param name + * the field name. + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + public BigDecimal readBigDecimal(String name, BigDecimal defaultValue) { + try { + return readBigDecimal(indexOf(name), defaultValue); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(e.getMessage() + ", name: [" + + name + "]"); + } + } + + /** + * Read the java.util.Date value in default format at + * designated column index. + * + * @param index + * the field index. + * @param pattern + * the pattern describing the date and time format + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + * @see #DEFAULT_DATE_PATTERN + */ + public Date readDate(int index) { + return readDate(index, DEFAULT_DATE_PATTERN); + } + + /** + * Read the java.sql.Date value in given format from column + * with given name. + * + * @param name + * the field name. + * @param pattern + * the pattern describing the date and time format + * @throws IllegalArgumentException + * if a column with given name is not defined. + * @see #DEFAULT_DATE_PATTERN + */ + public Date readDate(String name) { + return readDate(name, DEFAULT_DATE_PATTERN); + } + + /** + * Read the java.util.Date value in default format at + * designated column index. + * + * @param index + * the field index. + * @param pattern + * the pattern describing the date and time format + * @throws IndexOutOfBoundsException + * if the index is out of bounds. + * @throws IllegalArgumentException + * if the date cannot be parsed. + * + */ + public Date readDate(int index, String pattern) { + SimpleDateFormat sdf = new SimpleDateFormat(pattern); + Date date; + String value = readAndTrim(index); + try { + date = sdf.parse(value); + } catch (ParseException e) { + throw new IllegalArgumentException(e.getMessage() + ", pattern: [" + + pattern + "]"); + } + return date; + } + + /** + * Read the java.sql.Date value in given format from column + * with given name. + * + * @param name + * the field name. + * @param pattern + * the pattern describing the date and time format + * @throws IllegalArgumentException + * if a column with given name is not defined or if the + * specified field cannot be parsed + * + */ + public Date readDate(String name, String pattern) { + try { + return readDate(indexOf(name), pattern); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(e.getMessage() + ", name: [" + + name + "]"); + } + } + + /** + * Return the number of fields in this 'FieldSet'. + */ + public int getFieldCount() { + return tokens.length; + } + + /** + * Read and trim the {@link String} value at 'index'. + * + * @throws NullPointerException + * if the field value is null. + */ + private String readAndTrim(int index) { + String value = tokens[index]; + + if (value != null) { + return value.trim(); + } else { + return value; + } + } + + /** + * Read and trim the {@link String} value from column with given 'name. + * + * @throws IllegalArgumentException + * if a column with given name is not defined. + */ + private int indexOf(String name) { + if (names == null) { + throw new IllegalArgumentException( + "Cannot access columns by name without meta data"); + } + int index = names.indexOf(name); + if (index >= 0) { + return index; + } + throw new IllegalArgumentException("Cannot access column [" + name + + "] from " + names); + } + + public String toString() { + if (names != null) { + return getProperties().toString(); + } + + return tokens == null ? "" : Arrays.asList(tokens).toString(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object object) { + if (object instanceof FieldSet) { + FieldSet fs = (FieldSet) object; + + if (this.tokens == null) { + return fs.tokens == null; + } else { + return Arrays.equals(this.tokens, fs.tokens); + } + } + + return false; + } + + public int hashCode() { + //this algorithm was taken from java 1.5 jdk Arrays.hashCode(Object[]) + if (tokens == null) { + return 0; + } + + int result = 1; + + for (int i = 0; i < tokens.length; i++) { + result = 31 * result + (tokens[i] == null ? 0 : tokens[i].hashCode()); + } + + return result; + } + + /** + * Construct name-value pairs from the field names and string values. + * + * @return some properties representing the field set. + * + * @throws IllegalStateException + * if the field name meta data is not available. + */ + public Properties getProperties() { + if (names == null) { + throw new IllegalStateException( + "Cannot create properties without meta data"); + } + Properties props = new Properties(); + for (int i = 0; i < tokens.length; i++) { + props.setProperty((String) names.get(i), readAndTrim(i)); + } + return props; + } + +} diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/support/FlatFileOutputSource.java b/infrastructure/src/main/java/org/springframework/batch/io/file/support/FlatFileOutputSource.java index 333d11c8a..291501e1b 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/support/FlatFileOutputSource.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/file/support/FlatFileOutputSource.java @@ -1,578 +1,578 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.io.file.support; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.charset.UnsupportedCharsetException; -import java.util.Collection; -import java.util.Iterator; -import java.util.Properties; - -import org.springframework.batch.io.OutputSource; -import org.springframework.batch.io.exception.BatchCriticalException; -import org.springframework.batch.io.exception.BatchEnvironmentException; -import org.springframework.batch.io.file.support.transform.Converter; -import org.springframework.batch.item.ResourceLifecycle; -import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager; -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.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.Resource; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.transaction.support.TransactionSynchronization; -import org.springframework.transaction.support.TransactionSynchronizationAdapter; -import org.springframework.util.Assert; - -/** - * This class is an output target that writes data to a file or stream. The - * output source also provides restart, statistics and transaction features by - * implementing corresponding interfaces where possible (with a file). The - * location of the file is defined by a {@link Resource} and must represent a - * writable file.
- * - * Uses buffered writer to improve performance.
- * - * Use {@link #write(String)} method to output a line to an output source. - * - * @author Waseem Malik - * @author Tomas Slanina - * @author Robert Kasanicky - * @author Dave Syer - */ -public class FlatFileOutputSource implements OutputSource, ResourceLifecycle, Restartable, StatisticsProvider, InitializingBean, - DisposableBean { - - /** - * @author dsyer - * - */ - public class BooleanHolder { - - public boolean value; - - } - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - public static final String WRITTEN_STATISTICS_NAME = "Written"; - - public static final String RESTART_COUNT_STATISTICS_NAME = "Restart count"; - - public static final String RESTART_DATA_NAME = "flatfileoutputtemplate.currentLine"; - - private Resource resource; - - private Properties statistics = new Properties(); - - private RestartData restartData = new GenericRestartData(new Properties()); - - private TransactionSynchronization transactionSynchronization = new FlatFileOutputTemplateTransactionSynchronization(); - - private OutputState state = new OutputState(); - - private Converter converter = new Converter() { - public Object convert(Object input) { - return "" + input; - } - }; - - public void afterPropertiesSet() throws Exception { - Assert.notNull(resource); - File file = resource.getFile(); - Assert.state(!file.exists() || file.canWrite(), "Resource is not writable: [" + resource + "]"); - } - - /** - * Public setter for the converter. If not-null this will be used to convert - * the input data before it is output. - * - * @param converter the converter to set - */ - public void setConverter(Converter converter) { - this.converter = converter; - } - - /** - * Setter for resource. Represents a file that can be written. - * - * @param resource - */ - public void setResource(Resource resource) { - this.resource = resource; - } - - /** - * Commit the transaction. - */ - private void transactionComitted() { - getOutputState().mark(); - } - - /** - * Rollback the transaction. - */ - private void transactionRolledback() { - getOutputState().checkFileSize(); - resetPositionForRestart(); - } - - // This method removes any information in the file before this reset point. - private void resetPositionForRestart() { - getOutputState().truncate(); - } - - /** - * Writes out a string followed by a "new line", where the format of the new - * line separator is determined by the underlying operating system. If the - * input is not a String and a converter is available the converter will be - * applied and then this method recursively called with the result. If the - * input is an array or collection each value will be written to a separate - * line (recursively calling this method for each value). If no converter is - * supplied the input object's toString method will be used.
- * - * @param data Object (a String or Object that can be converted) to be - * written to output stream - */ - public void write(Object data) { - convertAndWrite(data, new BooleanHolder()); - } - - /** - * Convert the date to a format that can be output and then write it out. - * @param data - * @param converted - */ - private void convertAndWrite(Object data, BooleanHolder converted) { - - if (data instanceof Collection) { - converted.value = false; - for (Iterator iterator = ((Collection) data).iterator(); iterator.hasNext();) { - Object value = (Object) iterator.next(); - // (recursive) - write(value); - } - return; - } - if (data.getClass().isArray()) { - converted.value = false; - Object[] array = (Object[]) data; - for (int i = 0; i < array.length; i++) { - Object value = array[i]; - // (recursive) - write(value); - } - return; - } - if (data instanceof String) { - // This is where the output stream is actually written to - getOutputState().write(data + LINE_SEPARATOR); - } - else if (!converted.value) { - // (recursive) - converted.value = true; - convertAndWrite(converter.convert(data), converted); - return; - } - else { - // Should not happen... - throw new IllegalStateException( - "Infinite loop detected - converter did not convert to String or collection/array of objects convertible to String."); - } - } - - /** - * @see ResourceLifecycle#close() - */ - public void close() { - getOutputState().close(); - } - - /** - * Calls close to ensure that bean factories can close and always release - * resources. - * - * @see org.springframework.beans.factory.DisposableBean#destroy() - */ - public void destroy() throws Exception { - close(); - } - - /** - * Sets encoding for output template. - */ - public void setEncoding(String newEncoding) { - getOutputState().setEncoding(newEncoding); - } - - /** - * Sets buffer size for output template - */ - public void setBufferSize(int newSize) { - getOutputState().setBufferSize(newSize); - } - - /** - * @param shouldDeleteIfExists the shouldDeleteIfExists to set - */ - public void setShouldDeleteIfExists(boolean shouldDeleteIfExists) { - getOutputState().setShouldDeleteIfExists(shouldDeleteIfExists); - } - - /** - * Initialize the Output Template. - * @see ResourceLifecycle#open() - */ - public void open() { - registerSynchronization(); - } - - /** - * @see StatisticsProvider - */ - public Properties getStatistics() { - final OutputState os = getOutputState(); - - statistics.setProperty(WRITTEN_STATISTICS_NAME, String.valueOf(os.linesWritten)); - statistics.setProperty(RESTART_COUNT_STATISTICS_NAME, String.valueOf(os.restartCount)); - return statistics; - } - - /** - * @see Restartable#getRestartData() - */ - public RestartData getRestartData() { - final OutputState os = getOutputState(); - - restartData.getProperties().setProperty(RESTART_DATA_NAME, String.valueOf(os.position())); - return restartData; - } - - /** - * @see Restartable#restoreFrom(RestartData) - */ - public void restoreFrom(RestartData data) { - if (data == null) - return; - - getOutputState().restoreFrom(data.getProperties()); - - } - - // Registers a new transaction synchronization for the current thread. - private void registerSynchronization() { - BatchTransactionSynchronizationManager.registerSynchronization(this.transactionSynchronization); - } - - // Returns object representing state. - private OutputState getOutputState() { - return (OutputState) state; - } - - // added package visibility method so that tests can invoke transaction - // events - TransactionSynchronization getTransactionSynchronization() { - return this.transactionSynchronization; - } - - /** - * Encapsulates the runtime state of the output source. All state changing - * operations on the output source go through this class. - */ - private class OutputState { - // default encoding for writing to output files - set to UTF-8. - private static final String DEFAULT_CHARSET = "UTF-8"; - - private static final int DEFAULT_BUFFER_SIZE = 2048; - - // The bufferedWriter over the file channel that is actually written - BufferedWriter outputBufferedWriter; - - FileChannel fileChannel; - - // this represents the charset encoding (if any is needed) for the - // output file - String encoding = DEFAULT_CHARSET; - - // Optional write buffer size - int bufferSize = DEFAULT_BUFFER_SIZE; - - boolean restarted = false; - - boolean initialized = false; - - long lastMarkedByteOffsetPosition = 0; - - long linesWritten = 0; - - long restartCount = 0; - - boolean shouldDeleteIfExists = true; - - /** - * Return the byte offset position of the cursor in the output file as a - * long integer. - */ - public long position() { - long pos = 0; - - if (fileChannel == null) { - return 0; - } - - try { - outputBufferedWriter.flush(); - pos = fileChannel.position(); - } - catch (IOException e) { - throw new BatchCriticalException("An Error occured while trying to get filechannel position", e); - } - - return pos; - - } - - /** - * @param properties - */ - public void restoreFrom(Properties properties) { - lastMarkedByteOffsetPosition = Long.parseLong(properties.getProperty(RESTART_DATA_NAME)); - restarted = true; - } - - /** - * @param shouldDeleteIfExists2 - */ - public void setShouldDeleteIfExists(boolean shouldDeleteIfExists) { - this.shouldDeleteIfExists = shouldDeleteIfExists; - } - - /** - * @param newSize - */ - public void setBufferSize(int newSize) { - bufferSize = newSize; - } - - /** - * @param newEncoding - */ - public void setEncoding(String newEncoding) { - encoding = newEncoding; - } - - /** - * Close the open resource and reset counters. - */ - public void close() { - initialized = false; - restarted = false; - try { - if (outputBufferedWriter == null) { - return; - } - outputBufferedWriter.close(); - fileChannel.close(); - } - catch (IOException ioe) { - throw new BatchEnvironmentException("Unable to close the the Output Source", ioe); - } - } - - /** - * @param data - * @param offset - * @param length - */ - public void write(String line) { - if (!initialized) { - initializeBufferedWriter(); - } - - try { - outputBufferedWriter.write(line); - outputBufferedWriter.flush(); - linesWritten++; - } - catch (IOException e) { - throw new BatchCriticalException("An Error occured while trying to write to FileWriterOutputSource", e); - } - } - - /** - * Truncate the output at the last known good point. - */ - public void truncate() { - try { - fileChannel.truncate(lastMarkedByteOffsetPosition); - fileChannel.position(lastMarkedByteOffsetPosition); - } - catch (Exception e) { - throw new BatchCriticalException("An Error occured while reseting position in a file for restart", e); - } - } - - /** - * Mark the current position. - */ - public void mark() { - lastMarkedByteOffsetPosition = this.position(); - } - - /** - * Creates the buffered writer for the output file channel based on - * configuration information. - */ - private void initializeBufferedWriter() { - File file; - - try { - file = resource.getFile(); - - // If the output source was restarted, keep existing file. - // If the output source was not restarted, check following: - // - if the file should be deleted, delete it if it was exiting - // and create blank file, - // - if the file should not be deleted, if it already exists, - // throw an exception, - // - if the file was not existing, create new. - if (!restarted) { - if (file.exists()) { - if (shouldDeleteIfExists) { - file.delete(); - } - else { - throw new BatchEnvironmentException("Resource already exists: " + resource); - } - } - file.createNewFile(); - } - - } - catch (IOException ioe) { - throw new DataAccessResourceFailureException("Unable to write to file resource: [" + resource + "]", - ioe); - } - - try { - fileChannel = (new FileOutputStream(file.getAbsolutePath(), true)).getChannel(); - } - catch (FileNotFoundException fnfe) { - throw new BatchEnvironmentException("Bad filename property parameter " + file, fnfe); - } - - outputBufferedWriter = getBufferedWriter(fileChannel, encoding, bufferSize); - - // in case of restarting reset position to last commited point - if (restarted) { - this.resetPosition(); - } - - initialized = true; - linesWritten = 0; - } - - /** - * Returns the buffered writer opened to the beginning of the file - * specified by the absolute path name contained in absoluteFileName. - */ - private BufferedWriter getBufferedWriter(FileChannel fileChannel, String encoding, int bufferSize) { - try { - - BufferedWriter outputBufferedWriter = null; - - // If a buffer was requested, allocate. - if (bufferSize > 0) { - outputBufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, encoding), bufferSize); - } - else { - outputBufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, encoding)); - } - - return outputBufferedWriter; - } - catch (UnsupportedCharsetException ucse) { - throw new BatchEnvironmentException("Bad encoding configuration for output file " + fileChannel, ucse); - } - } - - /** - * Resets the file writer's current position to the point stored in the - * last marked byte offset position variable. It first checks to make - * sure the current size of the file is not less than the byte position - * to be moved to (if it is, throws an environment exception), then it - * truncates the file to that reset position, and set the cursor to - * start writing at that point. - */ - private void resetPosition() { - checkFileSize(); - resetPositionForRestart(); - } - - /** - * Checks (on setState) to make sure that the current output file's size - * is not smaller than the last saved commit point. If it is, then the - * file has been damaged in some way and whole task must be started over - * again from the beginning. - */ - public void checkFileSize() { - long size = -1; - - try { - outputBufferedWriter.flush(); - size = fileChannel.size(); - } - catch (Exception e) { - throw new BatchCriticalException("An Error occured while checking file size", e); - } - - if (size < lastMarkedByteOffsetPosition) { - throw new BatchCriticalException("Current file size is smaller than size at last commit"); - } - } - - } - - /** - * Encapsulates transaction events. - */ - private class FlatFileOutputTemplateTransactionSynchronization extends TransactionSynchronizationAdapter { - /** - * TransactionSynchronization method indicating that a transaction has - * completed. - * - * @param status indicates whether it was a rollback or commit - */ - public void afterCompletion(int status) { - if (status == TransactionSynchronization.STATUS_COMMITTED) { - transactionComitted(); - } - else if (status == TransactionSynchronization.STATUS_ROLLED_BACK) { - transactionRolledback(); - } - } - } - -} +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.batch.io.file.support; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Properties; + +import org.springframework.batch.io.OutputSource; +import org.springframework.batch.io.exception.BatchCriticalException; +import org.springframework.batch.io.exception.BatchEnvironmentException; +import org.springframework.batch.io.file.support.transform.Converter; +import org.springframework.batch.item.ResourceLifecycle; +import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager; +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.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationAdapter; +import org.springframework.util.Assert; + +/** + * This class is an output target that writes data to a file or stream. The + * output source also provides restart, statistics and transaction features by + * implementing corresponding interfaces where possible (with a file). The + * location of the file is defined by a {@link Resource} and must represent a + * writable file.
+ * + * Uses buffered writer to improve performance.
+ * + * Use {@link #write(String)} method to output a line to an output source. + * + * @author Waseem Malik + * @author Tomas Slanina + * @author Robert Kasanicky + * @author Dave Syer + */ +public class FlatFileOutputSource implements OutputSource, ResourceLifecycle, Restartable, StatisticsProvider, InitializingBean, + DisposableBean { + + /** + * @author dsyer + * + */ + public static class BooleanHolder { + + public boolean value; + + } + + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + public static final String WRITTEN_STATISTICS_NAME = "Written"; + + public static final String RESTART_COUNT_STATISTICS_NAME = "Restart count"; + + public static final String RESTART_DATA_NAME = "flatfileoutputtemplate.currentLine"; + + private Resource resource; + + private Properties statistics = new Properties(); + + private RestartData restartData = new GenericRestartData(new Properties()); + + private TransactionSynchronization transactionSynchronization = new FlatFileOutputTemplateTransactionSynchronization(); + + private OutputState state = new OutputState(); + + private Converter converter = new Converter() { + public Object convert(Object input) { + return "" + input; + } + }; + + public void afterPropertiesSet() throws Exception { + Assert.notNull(resource); + File file = resource.getFile(); + Assert.state(!file.exists() || file.canWrite(), "Resource is not writable: [" + resource + "]"); + } + + /** + * Public setter for the converter. If not-null this will be used to convert + * the input data before it is output. + * + * @param converter the converter to set + */ + public void setConverter(Converter converter) { + this.converter = converter; + } + + /** + * Setter for resource. Represents a file that can be written. + * + * @param resource + */ + public void setResource(Resource resource) { + this.resource = resource; + } + + /** + * Commit the transaction. + */ + private void transactionComitted() { + getOutputState().mark(); + } + + /** + * Rollback the transaction. + */ + private void transactionRolledback() { + getOutputState().checkFileSize(); + resetPositionForRestart(); + } + + // This method removes any information in the file before this reset point. + private void resetPositionForRestart() { + getOutputState().truncate(); + } + + /** + * Writes out a string followed by a "new line", where the format of the new + * line separator is determined by the underlying operating system. If the + * input is not a String and a converter is available the converter will be + * applied and then this method recursively called with the result. If the + * input is an array or collection each value will be written to a separate + * line (recursively calling this method for each value). If no converter is + * supplied the input object's toString method will be used.
+ * + * @param data Object (a String or Object that can be converted) to be + * written to output stream + */ + public void write(Object data) { + convertAndWrite(data, new BooleanHolder()); + } + + /** + * Convert the date to a format that can be output and then write it out. + * @param data + * @param converted + */ + private void convertAndWrite(Object data, BooleanHolder converted) { + + if (data instanceof Collection) { + converted.value = false; + for (Iterator iterator = ((Collection) data).iterator(); iterator.hasNext();) { + Object value = (Object) iterator.next(); + // (recursive) + write(value); + } + return; + } + if (data.getClass().isArray()) { + converted.value = false; + Object[] array = (Object[]) data; + for (int i = 0; i < array.length; i++) { + Object value = array[i]; + // (recursive) + write(value); + } + return; + } + if (data instanceof String) { + // This is where the output stream is actually written to + getOutputState().write(data + LINE_SEPARATOR); + } + else if (!converted.value) { + // (recursive) + converted.value = true; + convertAndWrite(converter.convert(data), converted); + return; + } + else { + // Should not happen... + throw new IllegalStateException( + "Infinite loop detected - converter did not convert to String or collection/array of objects convertible to String."); + } + } + + /** + * @see ResourceLifecycle#close() + */ + public void close() { + getOutputState().close(); + } + + /** + * Calls close to ensure that bean factories can close and always release + * resources. + * + * @see org.springframework.beans.factory.DisposableBean#destroy() + */ + public void destroy() throws Exception { + close(); + } + + /** + * Sets encoding for output template. + */ + public void setEncoding(String newEncoding) { + getOutputState().setEncoding(newEncoding); + } + + /** + * Sets buffer size for output template + */ + public void setBufferSize(int newSize) { + getOutputState().setBufferSize(newSize); + } + + /** + * @param shouldDeleteIfExists the shouldDeleteIfExists to set + */ + public void setShouldDeleteIfExists(boolean shouldDeleteIfExists) { + getOutputState().setShouldDeleteIfExists(shouldDeleteIfExists); + } + + /** + * Initialize the Output Template. + * @see ResourceLifecycle#open() + */ + public void open() { + registerSynchronization(); + } + + /** + * @see StatisticsProvider + */ + public Properties getStatistics() { + final OutputState os = getOutputState(); + + statistics.setProperty(WRITTEN_STATISTICS_NAME, String.valueOf(os.linesWritten)); + statistics.setProperty(RESTART_COUNT_STATISTICS_NAME, String.valueOf(os.restartCount)); + return statistics; + } + + /** + * @see Restartable#getRestartData() + */ + public RestartData getRestartData() { + final OutputState os = getOutputState(); + + restartData.getProperties().setProperty(RESTART_DATA_NAME, String.valueOf(os.position())); + return restartData; + } + + /** + * @see Restartable#restoreFrom(RestartData) + */ + public void restoreFrom(RestartData data) { + if (data == null) + return; + + getOutputState().restoreFrom(data.getProperties()); + + } + + // Registers a new transaction synchronization for the current thread. + private void registerSynchronization() { + BatchTransactionSynchronizationManager.registerSynchronization(this.transactionSynchronization); + } + + // Returns object representing state. + private OutputState getOutputState() { + return (OutputState) state; + } + + // added package visibility method so that tests can invoke transaction + // events + TransactionSynchronization getTransactionSynchronization() { + return this.transactionSynchronization; + } + + /** + * Encapsulates the runtime state of the output source. All state changing + * operations on the output source go through this class. + */ + private class OutputState { + // default encoding for writing to output files - set to UTF-8. + private static final String DEFAULT_CHARSET = "UTF-8"; + + private static final int DEFAULT_BUFFER_SIZE = 2048; + + // The bufferedWriter over the file channel that is actually written + BufferedWriter outputBufferedWriter; + + FileChannel fileChannel; + + // this represents the charset encoding (if any is needed) for the + // output file + String encoding = DEFAULT_CHARSET; + + // Optional write buffer size + int bufferSize = DEFAULT_BUFFER_SIZE; + + boolean restarted = false; + + boolean initialized = false; + + long lastMarkedByteOffsetPosition = 0; + + long linesWritten = 0; + + long restartCount = 0; + + boolean shouldDeleteIfExists = true; + + /** + * Return the byte offset position of the cursor in the output file as a + * long integer. + */ + public long position() { + long pos = 0; + + if (fileChannel == null) { + return 0; + } + + try { + outputBufferedWriter.flush(); + pos = fileChannel.position(); + } + catch (IOException e) { + throw new BatchCriticalException("An Error occured while trying to get filechannel position", e); + } + + return pos; + + } + + /** + * @param properties + */ + public void restoreFrom(Properties properties) { + lastMarkedByteOffsetPosition = Long.parseLong(properties.getProperty(RESTART_DATA_NAME)); + restarted = true; + } + + /** + * @param shouldDeleteIfExists2 + */ + public void setShouldDeleteIfExists(boolean shouldDeleteIfExists) { + this.shouldDeleteIfExists = shouldDeleteIfExists; + } + + /** + * @param newSize + */ + public void setBufferSize(int newSize) { + bufferSize = newSize; + } + + /** + * @param newEncoding + */ + public void setEncoding(String newEncoding) { + encoding = newEncoding; + } + + /** + * Close the open resource and reset counters. + */ + public void close() { + initialized = false; + restarted = false; + try { + if (outputBufferedWriter == null) { + return; + } + outputBufferedWriter.close(); + fileChannel.close(); + } + catch (IOException ioe) { + throw new BatchEnvironmentException("Unable to close the the Output Source", ioe); + } + } + + /** + * @param data + * @param offset + * @param length + */ + public void write(String line) { + if (!initialized) { + initializeBufferedWriter(); + } + + try { + outputBufferedWriter.write(line); + outputBufferedWriter.flush(); + linesWritten++; + } + catch (IOException e) { + throw new BatchCriticalException("An Error occured while trying to write to FileWriterOutputSource", e); + } + } + + /** + * Truncate the output at the last known good point. + */ + public void truncate() { + try { + fileChannel.truncate(lastMarkedByteOffsetPosition); + fileChannel.position(lastMarkedByteOffsetPosition); + } + catch (Exception e) { + throw new BatchCriticalException("An Error occured while reseting position in a file for restart", e); + } + } + + /** + * Mark the current position. + */ + public void mark() { + lastMarkedByteOffsetPosition = this.position(); + } + + /** + * Creates the buffered writer for the output file channel based on + * configuration information. + */ + private void initializeBufferedWriter() { + File file; + + try { + file = resource.getFile(); + + // If the output source was restarted, keep existing file. + // If the output source was not restarted, check following: + // - if the file should be deleted, delete it if it was exiting + // and create blank file, + // - if the file should not be deleted, if it already exists, + // throw an exception, + // - if the file was not existing, create new. + if (!restarted) { + if (file.exists()) { + if (shouldDeleteIfExists) { + file.delete(); + } + else { + throw new BatchEnvironmentException("Resource already exists: " + resource); + } + } + file.createNewFile(); + } + + } + catch (IOException ioe) { + throw new DataAccessResourceFailureException("Unable to write to file resource: [" + resource + "]", + ioe); + } + + try { + fileChannel = (new FileOutputStream(file.getAbsolutePath(), true)).getChannel(); + } + catch (FileNotFoundException fnfe) { + throw new BatchEnvironmentException("Bad filename property parameter " + file, fnfe); + } + + outputBufferedWriter = getBufferedWriter(fileChannel, encoding, bufferSize); + + // in case of restarting reset position to last commited point + if (restarted) { + this.resetPosition(); + } + + initialized = true; + linesWritten = 0; + } + + /** + * Returns the buffered writer opened to the beginning of the file + * specified by the absolute path name contained in absoluteFileName. + */ + private BufferedWriter getBufferedWriter(FileChannel fileChannel, String encoding, int bufferSize) { + try { + + BufferedWriter outputBufferedWriter = null; + + // If a buffer was requested, allocate. + if (bufferSize > 0) { + outputBufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, encoding), bufferSize); + } + else { + outputBufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, encoding)); + } + + return outputBufferedWriter; + } + catch (UnsupportedCharsetException ucse) { + throw new BatchEnvironmentException("Bad encoding configuration for output file " + fileChannel, ucse); + } + } + + /** + * Resets the file writer's current position to the point stored in the + * last marked byte offset position variable. It first checks to make + * sure the current size of the file is not less than the byte position + * to be moved to (if it is, throws an environment exception), then it + * truncates the file to that reset position, and set the cursor to + * start writing at that point. + */ + private void resetPosition() { + checkFileSize(); + resetPositionForRestart(); + } + + /** + * Checks (on setState) to make sure that the current output file's size + * is not smaller than the last saved commit point. If it is, then the + * file has been damaged in some way and whole task must be started over + * again from the beginning. + */ + public void checkFileSize() { + long size = -1; + + try { + outputBufferedWriter.flush(); + size = fileChannel.size(); + } + catch (Exception e) { + throw new BatchCriticalException("An Error occured while checking file size", e); + } + + if (size < lastMarkedByteOffsetPosition) { + throw new BatchCriticalException("Current file size is smaller than size at last commit"); + } + } + + } + + /** + * Encapsulates transaction events. + */ + private class FlatFileOutputTemplateTransactionSynchronization extends TransactionSynchronizationAdapter { + /** + * TransactionSynchronization method indicating that a transaction has + * completed. + * + * @param status indicates whether it was a rollback or commit + */ + public void afterCompletion(int status) { + if (status == TransactionSynchronization.STATUS_COMMITTED) { + transactionComitted(); + } + else if (status == TransactionSynchronization.STATUS_ROLLED_BACK) { + transactionRolledback(); + } + } + } + +} diff --git a/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/DelimitedLineTokenizer.java b/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/DelimitedLineTokenizer.java index 306d6496b..a1e816c32 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/DelimitedLineTokenizer.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/file/support/transform/DelimitedLineTokenizer.java @@ -1,186 +1,183 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.io.file.support.transform; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.batch.io.exception.BatchConfigurationException; -import org.springframework.util.StringUtils; - -/** - * - * @author Rob Harrop - * @author Dave Syer - * - */ -public class DelimitedLineTokenizer extends AbstractLineTokenizer { - /** - * Convenient constant for the common case of a tab delimiter. - */ - public static final char DELIMITER_TAB = '\t'; - - /** - * Convenient constant for the common case of a comma delimiter. - */ - public static final char DELIMITER_COMMA = ','; - - /** - * Convenient constant for the common case of a " character used to escape - * delimiters or line endings. - */ - public static final char DEFAULT_QUOTE_CHARACTER = '"'; - - // the delimiter character used when reading input. - private char delimiter; - - private char quoteCharacter = DEFAULT_QUOTE_CHARACTER; - - /** - * Create a new instance of the {@link DelimitedLineTokenizer} class for the - * common case where the delimiter is a {@link #DELIMITER_COMMA comma}. - * - * @see #DelimitedLineTokenizer(char) - * @see #DELIMITER_COMMA - */ - public DelimitedLineTokenizer() { - this(DELIMITER_COMMA); - } - - /** - * Create a new instance of the {@link DelimitedLineTokenizer} class. - * - * @param delimiter the desired delimiter - */ - public DelimitedLineTokenizer(char delimiter) { - if (delimiter == DEFAULT_QUOTE_CHARACTER) { - throw new BatchConfigurationException("'" + DEFAULT_QUOTE_CHARACTER - + "' is not allowed as delimiter for tokenizers."); - } - - this.delimiter = delimiter; - } - - /** - * Setter for the delimiter character. - * @param delimiter - */ - public void setDelimiter(char delimiter) { - this.delimiter = delimiter; - } - - /** - * Public setter for the quoteCharacter. The quote character can be used to - * extend a field across line endings or to enclose a String which contains - * the delimiter. Inside a quoted token the quote character can be used to - * escape itself, thus "a""b""c" is tokenized to a"b"c. - * - * @param quoteCharacter the quoteCharacter to set - * - * @see #DEFAULT_QUOTE_CHARACTER - */ - public void setQuoteCharacter(char quoteCharacter) { - this.quoteCharacter = quoteCharacter; - } - - /** - * Yields the tokens resulting from the splitting of the supplied - * line. - * - * @param line the line to be tokenised (can be null) - * - * @return the resulting tokens - */ - public List doTokenize(String line) { - - List tokens = new ArrayList(); - - char[] chars = line.toCharArray(); - boolean inQuoted = false; - char lastChar = 0; - int lastCut = 0; - int length = chars.length; - - // TODO if line was null there would be exception while getting chars - // value - if (line != null) { - - for (int i = 0; i < length; i++) { - - char currentChar = chars[i]; - boolean isEnd = (i == (length - 1)); - - if ((isDelimiterCharacter(currentChar) && !inQuoted) || isEnd) { - int endPosition = (isEnd ? (length - lastCut) : (i - lastCut)); - - if (isEnd && isDelimiterCharacter(currentChar)) { - endPosition--; - } - - String value = null; - - if (isQuoteCharacter(lastChar) || isQuoteCharacter(currentChar)) { - value = new String(chars, lastCut + 1, endPosition - 2); - value = StringUtils.replace(value, "" + quoteCharacter + quoteCharacter, "" + quoteCharacter); - } - else { - value = new String(chars, lastCut, endPosition); - } - - tokens.add(value); - - if (isEnd && (isDelimiterCharacter(currentChar))) { - tokens.add(""); - } - - lastCut = i + 1; - } - else if (isQuoteCharacter(currentChar)) { - inQuoted = !inQuoted; - } - - lastChar = currentChar; - } - } - - return tokens; - } - - /** - * Is the supplied character the delimiter character? - * - * @param c the character to be checked - * @return true if the supplied character is the delimiter - * character - * @see DelimitedLineTokenizer#DelimitedLineTokenizer(char) - */ - private boolean isDelimiterCharacter(char c) { - return c == this.delimiter; - } - - /** - * Is the supplied character a quote character? - * - * @param c the character to be checked - * @return true if the supplied character is an quote - * character - * @see #setQuoteCharacter(char) - */ - protected boolean isQuoteCharacter(char c) { - return c == quoteCharacter; - } -} +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.batch.io.file.support.transform; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.batch.io.exception.BatchConfigurationException; +import org.springframework.util.StringUtils; + +/** + * + * @author Rob Harrop + * @author Dave Syer + * + */ +public class DelimitedLineTokenizer extends AbstractLineTokenizer { + /** + * Convenient constant for the common case of a tab delimiter. + */ + public static final char DELIMITER_TAB = '\t'; + + /** + * Convenient constant for the common case of a comma delimiter. + */ + public static final char DELIMITER_COMMA = ','; + + /** + * Convenient constant for the common case of a " character used to escape + * delimiters or line endings. + */ + public static final char DEFAULT_QUOTE_CHARACTER = '"'; + + // the delimiter character used when reading input. + private char delimiter; + + private char quoteCharacter = DEFAULT_QUOTE_CHARACTER; + + /** + * Create a new instance of the {@link DelimitedLineTokenizer} class for the + * common case where the delimiter is a {@link #DELIMITER_COMMA comma}. + * + * @see #DelimitedLineTokenizer(char) + * @see #DELIMITER_COMMA + */ + public DelimitedLineTokenizer() { + this(DELIMITER_COMMA); + } + + /** + * Create a new instance of the {@link DelimitedLineTokenizer} class. + * + * @param delimiter the desired delimiter + */ + public DelimitedLineTokenizer(char delimiter) { + if (delimiter == DEFAULT_QUOTE_CHARACTER) { + throw new BatchConfigurationException("'" + DEFAULT_QUOTE_CHARACTER + + "' is not allowed as delimiter for tokenizers."); + } + + this.delimiter = delimiter; + } + + /** + * Setter for the delimiter character. + * @param delimiter + */ + public void setDelimiter(char delimiter) { + this.delimiter = delimiter; + } + + /** + * Public setter for the quoteCharacter. The quote character can be used to + * extend a field across line endings or to enclose a String which contains + * the delimiter. Inside a quoted token the quote character can be used to + * escape itself, thus "a""b""c" is tokenized to a"b"c. + * + * @param quoteCharacter the quoteCharacter to set + * + * @see #DEFAULT_QUOTE_CHARACTER + */ + public void setQuoteCharacter(char quoteCharacter) { + this.quoteCharacter = quoteCharacter; + } + + /** + * Yields the tokens resulting from the splitting of the supplied + * line. + * + * @param line the line to be tokenized + * + * @return the resulting tokens + */ + protected List doTokenize(String line) { + + List tokens = new ArrayList(); + + //line is never null in current implementation + //line is checked in parent: AbstractLineTokenizer.tokenize() + char[] chars = line.toCharArray(); + boolean inQuoted = false; + char lastChar = 0; + int lastCut = 0; + int length = chars.length; + + for (int i = 0; i < length; i++) { + + char currentChar = chars[i]; + boolean isEnd = (i == (length - 1)); + + if ((isDelimiterCharacter(currentChar) && !inQuoted) || isEnd) { + int endPosition = (isEnd ? (length - lastCut) : (i - lastCut)); + + if (isEnd && isDelimiterCharacter(currentChar)) { + endPosition--; + } + + String value = null; + + if (isQuoteCharacter(lastChar) || isQuoteCharacter(currentChar)) { + value = new String(chars, lastCut + 1, endPosition - 2); + value = StringUtils.replace(value, "" + quoteCharacter + quoteCharacter, "" + quoteCharacter); + } + else { + value = new String(chars, lastCut, endPosition); + } + + tokens.add(value); + + if (isEnd && (isDelimiterCharacter(currentChar))) { + tokens.add(""); + } + + lastCut = i + 1; + } + else if (isQuoteCharacter(currentChar)) { + inQuoted = !inQuoted; + } + + lastChar = currentChar; + } + + return tokens; + } + + /** + * Is the supplied character the delimiter character? + * + * @param c the character to be checked + * @return true if the supplied character is the delimiter + * character + * @see DelimitedLineTokenizer#DelimitedLineTokenizer(char) + */ + private boolean isDelimiterCharacter(char c) { + return c == this.delimiter; + } + + /** + * Is the supplied character a quote character? + * + * @param c the character to be checked + * @return true if the supplied character is an quote + * character + * @see #setQuoteCharacter(char) + */ + protected boolean isQuoteCharacter(char c) { + return c == quoteCharacter; + } +} diff --git a/infrastructure/src/main/java/org/springframework/batch/io/support/AbstractDrivingQueryInputSource.java b/infrastructure/src/main/java/org/springframework/batch/io/support/AbstractDrivingQueryInputSource.java index 338001693..7c64ebb37 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/support/AbstractDrivingQueryInputSource.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/support/AbstractDrivingQueryInputSource.java @@ -159,7 +159,7 @@ public abstract class AbstractDrivingQueryInputSource implements InputSource, Re keys = restoreKeys(data); - if(keys != null & keys.size() > 0){ + if(keys != null && keys.size() > 0){ keysIterator = keys.listIterator(); initialized = true; } diff --git a/infrastructure/src/test/java/org/springframework/batch/io/file/support/mapping/TestObject.java b/infrastructure/src/test/java/org/springframework/batch/io/file/support/mapping/TestObject.java index a6bf6f637..83c54f8a5 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/file/support/mapping/TestObject.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/file/support/mapping/TestObject.java @@ -1,135 +1,135 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.io.file.support.mapping; - -import java.math.BigDecimal; -import java.util.Date; - -public class TestObject { - String varString; - - boolean varBoolean; - - char varChar; - - byte varByte; - - short varShort; - - int varInt; - - long varLong; - - float varFloat; - - double varDouble; - - BigDecimal varBigDecimal; - - Date varDate; - - public Date getVarDate() { - return varDate; - } - - public void setVarDate(Date varDate) { - this.varDate = varDate; - } - - public TestObject() { - } - - public BigDecimal getVarBigDecimal() { - return varBigDecimal; - } - - public void setVarBigDecimal(BigDecimal varBigDecimal) { - this.varBigDecimal = varBigDecimal; - } - - public boolean isVarBoolean() { - return varBoolean; - } - - public void setVarBoolean(boolean varBoolean) { - this.varBoolean = varBoolean; - } - - public byte getVarByte() { - return varByte; - } - - public void setVarByte(byte varByte) { - this.varByte = varByte; - } - - public char getVarChar() { - return varChar; - } - - public void setVarChar(char varChar) { - this.varChar = varChar; - } - - public double getVarDouble() { - return varDouble; - } - - public void setVarDouble(double varDouble) { - this.varDouble = varDouble; - } - - public float getVarFloat() { - return varFloat; - } - - public void setVarFloat(float varFloat) { - this.varFloat = varFloat; - } - - public long getVarLong() { - return varLong; - } - - public void setVarLong(long varLong) { - this.varLong = varLong; - } - - public short getVarShort() { - return varShort; - } - - public void setVarShort(short varShort) { - this.varShort = varShort; - } - - public String getVarString() { - return varString; - } - - public void setVarString(String varString) { - this.varString = varString; - } - - public int getVarInt() { - return varInt; - } - - public void setVarInt(int varInt) { - this.varInt = varInt; - } -} +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.batch.io.file.support.mapping; + +import java.math.BigDecimal; +import java.util.Date; + +public class TestObject { + String varString; + + boolean varBoolean; + + char varChar; + + byte varByte; + + short varShort; + + int varInt; + + long varLong; + + float varFloat; + + double varDouble; + + BigDecimal varBigDecimal; + + Date varDate; + + public Date getVarDate() { + return (Date)varDate.clone(); + } + + public void setVarDate(Date varDate) { + this.varDate = varDate == null ? null : (Date)varDate.clone(); + } + + public TestObject() { + } + + public BigDecimal getVarBigDecimal() { + return varBigDecimal; + } + + public void setVarBigDecimal(BigDecimal varBigDecimal) { + this.varBigDecimal = varBigDecimal; + } + + public boolean isVarBoolean() { + return varBoolean; + } + + public void setVarBoolean(boolean varBoolean) { + this.varBoolean = varBoolean; + } + + public byte getVarByte() { + return varByte; + } + + public void setVarByte(byte varByte) { + this.varByte = varByte; + } + + public char getVarChar() { + return varChar; + } + + public void setVarChar(char varChar) { + this.varChar = varChar; + } + + public double getVarDouble() { + return varDouble; + } + + public void setVarDouble(double varDouble) { + this.varDouble = varDouble; + } + + public float getVarFloat() { + return varFloat; + } + + public void setVarFloat(float varFloat) { + this.varFloat = varFloat; + } + + public long getVarLong() { + return varLong; + } + + public void setVarLong(long varLong) { + this.varLong = varLong; + } + + public short getVarShort() { + return varShort; + } + + public void setVarShort(short varShort) { + this.varShort = varShort; + } + + public String getVarString() { + return varString; + } + + public void setVarString(String varString) { + this.varString = varString; + } + + public int getVarInt() { + return varInt; + } + + public void setVarInt(int varInt) { + this.varInt = varInt; + } +} diff --git a/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java b/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java index a8b60aea5..06e5cc5fc 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java @@ -24,12 +24,12 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; import javax.xml.transform.Result; +import junit.framework.TestCase; + import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.oxm.Marshaller; import org.springframework.oxm.XmlMappingException; -import junit.framework.TestCase; - /** * * @@ -67,7 +67,7 @@ public class MarshallingObjectToXmlSerializerTests extends TestCase { } } - private class MockMarshaller implements Marshaller{ + private static class MockMarshaller implements Marshaller{ private Object marshalledObject; private boolean throwException = false; @@ -93,7 +93,7 @@ public class MarshallingObjectToXmlSerializerTests extends TestCase { } } - private class StubXmlEventWriter implements XMLEventWriter{ + private static class StubXmlEventWriter implements XMLEventWriter{ public void add(XMLEvent arg0) throws XMLStreamException { } diff --git a/infrastructure/src/test/java/org/springframework/batch/io/sample/domain/Order.java b/infrastructure/src/test/java/org/springframework/batch/io/sample/domain/Order.java index 1d010cacd..755a8c20c 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/sample/domain/Order.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/sample/domain/Order.java @@ -1,83 +1,83 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.io.sample.domain; - -import java.util.Date; -import java.util.List; - -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; - -/** - * An XML order. - * - * This is a complex type. - */ -public class Order { - private Customer customer; - - private Date date; - - private List lineItems; - - private Shipper shipper; - - public Customer getCustomer() { - return customer; - } - - public void setCustomer(Customer customer) { - this.customer = customer; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public List getLineItems() { - return lineItems; - } - - public void setLineItems(List lineItems) { - this.lineItems = lineItems; - } - - public Shipper getShipper() { - return shipper; - } - - public void setShipper(Shipper shipper) { - this.shipper = shipper; - } - - public boolean equals(Object obj) { - return EqualsBuilder.reflectionEquals(obj, this); - } - - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } - - public String toString() { - return ToStringBuilder.reflectionToString(this); - } -} +/* + * 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.sample.domain; + +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; + +/** + * An XML order. + * + * This is a complex type. + */ +public class Order { + private Customer customer; + + private Date date; + + private List lineItems; + + private Shipper shipper; + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public Date getDate() { + return (Date)date.clone(); + } + + public void setDate(Date date) { + this.date = date == null ? null : (Date)date.clone(); + } + + public List getLineItems() { + return lineItems; + } + + public void setLineItems(List lineItems) { + this.lineItems = lineItems; + } + + public Shipper getShipper() { + return shipper; + } + + public void setShipper(Shipper shipper) { + this.shipper = shipper; + } + + public boolean equals(Object obj) { + return EqualsBuilder.reflectionEquals(obj, this); + } + + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } + + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/infrastructure/src/test/java/org/springframework/batch/io/sql/CompositeKeySqlDrivingQueryInputSourceIntegrationTests.java b/infrastructure/src/test/java/org/springframework/batch/io/sql/CompositeKeySqlDrivingQueryInputSourceIntegrationTests.java index 5a1c88566..99f56afce 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/sql/CompositeKeySqlDrivingQueryInputSourceIntegrationTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/sql/CompositeKeySqlDrivingQueryInputSourceIntegrationTests.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Properties; import org.springframework.batch.io.InputSource; -import org.springframework.batch.io.sql.CompositeKeySqlDrivingQueryInputSource; import org.springframework.batch.restart.GenericRestartData; import org.springframework.batch.restart.RestartData; import org.springframework.jdbc.core.RowMapper; @@ -48,7 +47,7 @@ public class CompositeKeySqlDrivingQueryInputSourceIntegrationTests extends return fooInputSource; } - private class FooRestartDataConverter implements CompositeKeyRestartDataConverter{ + private static class FooRestartDataConverter implements CompositeKeyRestartDataConverter{ private static final String ID_RESTART_KEY = "FooRestartDataConverter.id"; private static final String VALUE_RESTART_KEY = "FooRestartDataConverter.value"; @@ -70,7 +69,7 @@ public class CompositeKeySqlDrivingQueryInputSourceIntegrationTests extends } } - private class FooCompositeKeyMapper implements RowMapper{ + private static class FooCompositeKeyMapper implements RowMapper{ public Object mapRow(ResultSet rs, int rowNum) throws SQLException { List key = new ArrayList(); key.add(new Long(rs.getLong(1))); diff --git a/infrastructure/src/test/java/org/springframework/batch/io/sql/SingleKeySqlDrivingQueryInputSourceIntegrationTests.java b/infrastructure/src/test/java/org/springframework/batch/io/sql/SingleKeySqlDrivingQueryInputSourceIntegrationTests.java index f009e7bfb..647d9177a 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/sql/SingleKeySqlDrivingQueryInputSourceIntegrationTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/sql/SingleKeySqlDrivingQueryInputSourceIntegrationTests.java @@ -13,7 +13,8 @@ public class SingleKeySqlDrivingQueryInputSourceIntegrationTests extends Abstrac */ protected InputSource createInputSource() throws Exception { - SingleKeySqlDrivingQueryInputSource inputSource = new SingleKeySqlDrivingQueryInputSource(getJdbcTemplate(), "SELECT ID from T_FOOS order by ID"); + SingleKeySqlDrivingQueryInputSource inputSource = new SingleKeySqlDrivingQueryInputSource(getJdbcTemplate(), + "SELECT ID from T_FOOS order by ID"); inputSource.setRestartQuery("SELECT ID from T_FOOS where ID > ? order by ID"); return new FooInputSource(inputSource, getJdbcTemplate()); diff --git a/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventReaderWrapperTests.java b/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventReaderWrapperTests.java index fcd0bf9db..812642e90 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventReaderWrapperTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventReaderWrapperTests.java @@ -19,12 +19,12 @@ import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; +import junit.framework.TestCase; + import org.easymock.MockControl; import com.bea.xml.stream.events.StartDocumentEvent; -import junit.framework.TestCase; - /** * @author Lucas Ward * @@ -126,7 +126,7 @@ public class AbstractEventReaderWrapperTests extends TestCase { mockEventReaderControl.verify(); } - private class StubEventReader extends AbstractEventReaderWrapper{ + private static class StubEventReader extends AbstractEventReaderWrapper{ public StubEventReader(XMLEventReader wrappedEventReader) { super(wrappedEventReader); } diff --git a/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventWriterWrapperTests.java b/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventWriterWrapperTests.java index 565337807..d7d7165e5 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventWriterWrapperTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/stax/AbstractEventWriterWrapperTests.java @@ -126,7 +126,7 @@ public class AbstractEventWriterWrapperTests extends TestCase { mockEventWriterControl.verify(); } - private class StubEventWriter extends AbstractEventWriterWrapper{ + private static class StubEventWriter extends AbstractEventWriterWrapper{ public StubEventWriter(XMLEventWriter wrappedEventWriter) { super(wrappedEventWriter); } diff --git a/infrastructure/src/test/java/org/springframework/batch/io/stax/StaxEventReaderInputSourceTests.java b/infrastructure/src/test/java/org/springframework/batch/io/stax/StaxEventReaderInputSourceTests.java index f0899fa5f..840b764dd 100644 --- a/infrastructure/src/test/java/org/springframework/batch/io/stax/StaxEventReaderInputSourceTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/io/stax/StaxEventReaderInputSourceTests.java @@ -347,7 +347,7 @@ public class StaxEventReaderInputSourceTests extends TestCase { } - private class MockStaxEventReaderInputSource extends StaxEventReaderInputSource { + private static class MockStaxEventReaderInputSource extends StaxEventReaderInputSource { private boolean openCalled = false; 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 099819f58..c5b084198 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 @@ -22,7 +22,6 @@ import junit.framework.TestCase; import org.springframework.batch.io.InputSource; import org.springframework.batch.io.Skippable; -import org.springframework.batch.item.provider.InputSourceItemProvider; import org.springframework.batch.restart.GenericRestartData; import org.springframework.batch.restart.RestartData; import org.springframework.batch.restart.Restartable; @@ -99,7 +98,7 @@ public class InputSourceItemProviderTests extends TestCase { assertEquals("after skip", itemProvider.next()); } - private class MockInputSource implements InputSource, StatisticsProvider, Restartable, Skippable { + private static class MockInputSource implements InputSource, StatisticsProvider, Restartable, Skippable { private Object value; 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 index 13ebc0769..a57dbeada 100644 --- a/infrastructure/src/test/java/org/springframework/batch/item/provider/ValidatingItemProviderTests.java +++ b/infrastructure/src/test/java/org/springframework/batch/item/provider/ValidatingItemProviderTests.java @@ -15,13 +15,13 @@ */ package org.springframework.batch.item.provider; +import junit.framework.TestCase; + 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 * @@ -99,7 +99,7 @@ public class ValidatingItemProviderTests extends TestCase { validatorControl.verify(); } - private class MockInputSource implements InputSource{ + private static class MockInputSource implements InputSource{ Object value;