From cb3f23e4c5c8d102e1a3b22910fbb8bdb77249d6 Mon Sep 17 00:00:00 2001 From: lucasward Date: Thu, 3 Jul 2008 18:36:52 +0000 Subject: [PATCH] BATCH-713: FlatFileItemWriter now requires open to be called before write. There are also some additional clarifying test cases to the tokenizer tests. --- .../batch/item/WriterNotOpenException.java | 43 +++++++++++++++++++ .../batch/item/file/FlatFileItemWriter.java | 35 ++++++++++++--- .../item/file/FlatFileItemWriterTests.java | 25 +++++++++++ .../DelimitedLineTokenizerTests.java | 2 - .../transform/FixedLengthTokenizerTests.java | 9 ++++ 5 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 spring-batch-infrastructure/src/main/java/org/springframework/batch/item/WriterNotOpenException.java diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/WriterNotOpenException.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/WriterNotOpenException.java new file mode 100644 index 000000000..cf13c54c8 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/WriterNotOpenException.java @@ -0,0 +1,43 @@ +/* + * Copyright 2006-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item; + +/** + * Exception indicating that an {@link ItemReader} needed to be opened before read. + * + * @author Ben Hale + */ +public class WriterNotOpenException extends ItemReaderException { + + /** + * Create a new {@link WriterNotOpenException} based on a message. + * + * @param message the message for this exception + */ + public WriterNotOpenException(String message) { + super(message); + } + + /** + * Create a new {@link WriterNotOpenException} based on a message and another exception. + * + * @param msg the message for this exception + * @param nested the other exception + */ + public WriterNotOpenException(String msg, Throwable nested) { + super(msg, nested); + } +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemWriter.java index 98deeb6eb..e20ca57fe 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemWriter.java @@ -36,6 +36,7 @@ import org.springframework.batch.item.ItemStreamException; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.MarkFailedException; import org.springframework.batch.item.ResetFailedException; +import org.springframework.batch.item.WriterNotOpenException; import org.springframework.batch.item.file.mapping.FieldSet; import org.springframework.batch.item.file.mapping.FieldSetCreator; import org.springframework.batch.item.file.transform.DelimitedLineAggregator; @@ -97,7 +98,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I private List headerLines = new ArrayList(); private String lineSeparator = DEFAULT_LINE_SEPARATOR; - + public FlatFileItemWriter() { setName(ClassUtils.getShortName(FlatFileItemWriter.class)); } @@ -206,11 +207,17 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I * * @param data Object (a String or Object that can be converted) to be * written to output stream - * @throws Exception if the transformer or file output fail + * @throws Exception if the transformer or file output fail, WriterNotOpenException + * if the writer has not been initialized. */ public void write(Object data) throws Exception { - FieldSet fieldSet = fieldSetCreator.mapItem(data); - lineBuffer.add(lineAggregator.aggregate(fieldSet) + lineSeparator); + if(getOutputState().isInitialized()){ + FieldSet fieldSet = fieldSetCreator.mapItem(data); + lineBuffer.add(lineAggregator.aggregate(fieldSet) + lineSeparator); + } + else{ + throw new WriterNotOpenException("Writer must be open before it can be written to"); + } } /** @@ -224,11 +231,19 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I } /** - * Initialize the reader. + * Initialize the reader. This method may be called multiple times before close is + * called. * * @see ItemStream#open(ExecutionContext) */ public void open(ExecutionContext executionContext) throws ItemStreamException { + + if(!getOutputState().isInitialized()){ + doOpen(executionContext); + } + } + + private void doOpen(ExecutionContext executionContext){ OutputState outputState = getOutputState(); if (executionContext.containsKey(getKey(RESTART_DATA_NAME))) { outputState.restoreFrom(executionContext); @@ -328,8 +343,6 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I boolean restarted = false; - boolean initialized = false; - long lastMarkedByteOffsetPosition = 0; long linesWritten = 0; @@ -337,6 +350,8 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I long restartCount = 0; boolean shouldDeleteIfExists = true; + + boolean initialized = false; /** * Return the byte offset position of the cursor in the output file as a @@ -445,6 +460,8 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I * @throws IOException */ private void initializeBufferedWriter() throws IOException { + + File file = resource.getFile(); FileUtils.setUpOutputFile(file, restarted, shouldDeleteIfExists); @@ -461,6 +478,10 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I initialized = true; linesWritten = 0; } + + public boolean isInitialized() { + return initialized; + } /** * Returns the buffered writer opened to the beginning of the file diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemWriterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemWriterTests.java index 3140af973..7ca1fd323 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemWriterTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemWriterTests.java @@ -103,6 +103,24 @@ public class FlatFileItemWriterTests extends TestCase { return reader.readLine(); } + + public void testWriteWithMultipleOpen() throws Exception{ + + writer.open(executionContext); + writer.write("test1"); + writer.flush(); + writer.open(executionContext); + writer.write("test2"); + writer.flush(); + assertEquals("test1", readLine()); + assertEquals("test2", readLine()); + } + + public void testOpenTwice(){ + //opening the writer twice should cause no issues + writer.open(executionContext); + writer.open(executionContext); + } /** * Regular usage of write(String) method @@ -131,6 +149,7 @@ public class FlatFileItemWriterTests extends TestCase { } }); Object data = new Object(); + writer.open(executionContext); writer.write(data); writer.flush(); String lineFromFile = readLine(); @@ -150,6 +169,7 @@ public class FlatFileItemWriterTests extends TestCase { } }); Object data = new Object(); + writer.open(executionContext); writer.write(data); writer.flush(); String lineFromFile = readLine(); @@ -168,6 +188,7 @@ public class FlatFileItemWriterTests extends TestCase { return new DefaultFieldSet(new String[] { "FOO:" + data }); } }); + writer.open(executionContext); writer.write(TEST_STRING); writer.flush(); String lineFromFile = readLine(); @@ -181,6 +202,7 @@ public class FlatFileItemWriterTests extends TestCase { */ public void testWriteRecord() throws Exception { String args = "1"; + writer.open(executionContext); writer.write(args); writer.flush(); String lineFromFile = readLine(); @@ -189,6 +211,7 @@ public class FlatFileItemWriterTests extends TestCase { public void testWriteRecordWithrecordSeparator() throws Exception { writer.setLineSeparator("|"); + writer.open(executionContext); writer.write("1"); writer.write("2"); writer.flush(); @@ -197,6 +220,7 @@ public class FlatFileItemWriterTests extends TestCase { } public void testRollback() throws Exception { + writer.open(executionContext); writer.write("testLine1"); // rollback rollback(); @@ -207,6 +231,7 @@ public class FlatFileItemWriterTests extends TestCase { } public void testCommit() throws Exception { + writer.open(executionContext); writer.write("testLine1"); // rollback commit(); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/DelimitedLineTokenizerTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/DelimitedLineTokenizerTests.java index 45ae5649a..c5ded246f 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/DelimitedLineTokenizerTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/DelimitedLineTokenizerTests.java @@ -178,6 +178,4 @@ public class DelimitedLineTokenizerTests extends TestCase { assertEquals(4, line.getFieldCount()); assertEquals("", line.readString(2)); } - - } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FixedLengthTokenizerTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FixedLengthTokenizerTests.java index 7dd379cc8..4d4a29f32 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FixedLengthTokenizerTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/FixedLengthTokenizerTests.java @@ -35,6 +35,15 @@ public class FixedLengthTokenizerTests extends TestCase { FieldSet tokens = tokenizer.tokenize(""); assertEquals(0, tokens.getFieldCount()); } + + public void testTokenizeSmallerStringThanRanges() { + tokenizer.setColumns(new Range[] {new Range(1,5),new Range(6,10),new Range(11,15)}); + FieldSet tokens = tokenizer.tokenize("12345"); + assertEquals(3, tokens.getFieldCount()); + assertEquals("12345", tokens.readString(0)); + assertEquals("", tokens.readString(1)); + assertEquals("", tokens.readString(2)); + } public void testTokenizeNullString() { tokenizer.setColumns(new Range[] {new Range(1,5),new Range(6,10),new Range(11,15)});