From 47ef986be7d45fc409eb56774325bfa5262e3944 Mon Sep 17 00:00:00 2001 From: jpraet Date: Mon, 4 Mar 2013 22:01:18 +0100 Subject: [PATCH] BATCH-1959 --- .../TransactionAwareBufferedWriter.java | 10 ++- .../item/file/FlatFileItemWriterTests.java | 78 ++++++++++++++++++- .../TransactionAwareBufferedWriterTests.java | 28 ++++++- 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriter.java index f5562d47c..5074fd49b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriter.java @@ -16,10 +16,12 @@ package org.springframework.batch.support.transaction; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import org.springframework.batch.item.WriteFailedException; import org.springframework.transaction.support.TransactionSynchronizationAdapter; import org.springframework.transaction.support.TransactionSynchronizationManager; @@ -137,13 +139,17 @@ public class TransactionAwareBufferedWriter extends Writer { * Convenience method for clients to determine if there is any unflushed * data. * - * @return the current size of unflushed buffered data + * @return the current size (in bytes) of unflushed buffered data */ public long getBufferSize() { if (!transactionActive()) { return 0L; } - return getCurrentBuffer().length(); + try { + return getCurrentBuffer().toString().getBytes(encoding).length; + } catch (UnsupportedEncodingException e) { + throw new WriteFailedException("Could not determine buffer size because of unsupported encoding: " + encoding, e); + } } /** 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 22d125aba..8ec1534a6 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 @@ -25,8 +25,9 @@ import static org.junit.Assert.fail; import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.Writer; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; @@ -88,6 +89,7 @@ public class FlatFileItemWriterTests { writer.setLineAggregator(new PassThroughLineAggregator()); writer.afterPropertiesSet(); writer.setSaveState(true); + writer.setEncoding("UTF-8"); executionContext = new ExecutionContext(); } @@ -110,7 +112,7 @@ public class FlatFileItemWriterTests { private String readLine() throws IOException { if (reader == null) { - reader = new BufferedReader(new FileReader(outputFile)); + reader = new BufferedReader(new InputStreamReader(new FileInputStream(outputFile), "UTF-8")); } return reader.readLine(); @@ -125,7 +127,7 @@ public class FlatFileItemWriterTests { reader = null; } } - + @Test public void testWriteWithMultipleOpen() throws Exception { writer.open(executionContext); @@ -429,6 +431,76 @@ public class FlatFileItemWriterTests { assertEquals(8, executionContext.getLong(ClassUtils.getShortName(FlatFileItemWriter.class) + ".written")); } + + @Test + // BATCH-1959 + public void testTransactionalRestartWithMultiByteCharacter() throws Exception { + + writer.setFooterCallback(new FlatFileFooterCallback() { + + @Override + public void writeFooter(Writer writer) throws IOException { + writer.write("footer"); + } + + }); + + writer.open(executionContext); + + PlatformTransactionManager transactionManager = new ResourcelessTransactionManager(); + + new TransactionTemplate(transactionManager).execute(new TransactionCallback() { + @Override + public Object doInTransaction(TransactionStatus status) { + try { + // write some lines + writer.write(Arrays.asList(new String[] { "téstLine1", "téstLine2", "téstLine3" })); + // write more lines + writer.write(Arrays.asList(new String[] { "téstLine4", "téstLine5" })); + } + catch (Exception e) { + throw new UnexpectedInputException("Could not write data", e); + } + // get restart data + writer.update(executionContext); + return null; + } + }); + // close template + writer.close(); + + // init with correct data + writer.open(executionContext); + + new TransactionTemplate(transactionManager).execute(new TransactionCallback() { + @Override + public Object doInTransaction(TransactionStatus status) { + try { + // write more lines + writer.write(Arrays.asList(new String[] { "téstLine6", "téstLine7", "téstLine8" })); + } + catch (Exception e) { + throw new UnexpectedInputException("Could not write data", e); + } + // get restart data + writer.update(executionContext); + return null; + } + }); + // close template + writer.close(); + + // verify what was written to the file + for (int i = 1; i <= 8; i++) { + assertEquals("téstLine" + i, readLine()); + } + + assertEquals("footer", readLine()); + + // 3 lines were written to the file after restart + assertEquals(3, executionContext.getLong(ClassUtils.getShortName(FlatFileItemWriter.class) + ".written")); + + } @Test public void testOpenWithNonWritableFile() throws Exception { diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriterTests.java index e1e5c3a27..dcba51971 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriterTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/transaction/TransactionAwareBufferedWriterTests.java @@ -63,6 +63,8 @@ public class TransactionAwareBufferedWriterTests { } } }); + + writer.setEncoding("UTF-8"); } private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager(); @@ -100,7 +102,7 @@ public class TransactionAwareBufferedWriterTests { assertEquals(0, writer.getBufferSize()); } - + @Ignore //TODO - need to fix capture test @Test public void testCloseOutsideTransaction() throws Exception { @@ -183,6 +185,30 @@ public class TransactionAwareBufferedWriterTests { assertEquals(0, writer.getBufferSize()); } + + @Test + @SuppressWarnings({"unchecked", "rawtypes"}) + // BATCH-1959 + public void testBufferSizeInTransactionWithMultiByteCharacter() throws Exception { + ArgumentCaptor bb = ArgumentCaptor.forClass(ByteBuffer.class); + when(fileChannel.write(bb.capture())).thenReturn(5); + + new TransactionTemplate(transactionManager).execute(new TransactionCallback() { + @Override + public Object doInTransaction(TransactionStatus status) { + try { + writer.write("fóó"); + } + catch (IOException e) { + throw new IllegalStateException("Unexpected IOException", e); + } + assertEquals(5, writer.getBufferSize()); + return null; + } + }); + + assertEquals(0, writer.getBufferSize()); + } @Test @SuppressWarnings({"unchecked", "rawtypes"})