Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
* @author Christian Tzolov
* @author Ngoc Nhan
* @author Thomas Knall
* @author Jiwoo Lee
*
* @since 7.0
*/
Expand Down Expand Up @@ -674,24 +675,43 @@ private void appendStreamToFile(File fileToWriteTo, InputStream sourceFileInputS
bos.write(System.lineSeparator().getBytes());
}
}
finally {
cleanUpFileState(fileToWriteTo, state, bos);
catch (IOException | RuntimeException ex) {
cleanUpFileStateSuppressing(ex, fileToWriteTo, state, bos);
throw ex;
}
cleanUpFileState(fileToWriteTo, state, bos);
}

private void cleanUpFileState(File fileToWriteTo, @Nullable FileState state, @Nullable Closeable closeable) {
try {
if (state == null || this.flushTask == null) {
private void cleanUpFileState(File fileToWriteTo, @Nullable FileState state, @Nullable Closeable closeable)
throws IOException {

if (state == null || this.flushTask == null) {
try {
if (closeable != null) {
closeable.close();
}
clearState(fileToWriteTo, state);
}
else {
state.lastWrite = System.currentTimeMillis();
finally {
clearState(fileToWriteTo, state);
}
}
else {
state.lastWrite = System.currentTimeMillis();
}
}

/**
* Clean up after a write that has already failed, adding any failure from the clean up
* to the exception which is on its way out, the way try-with-resources does.
*/
private void cleanUpFileStateSuppressing(Throwable primary, File fileToWriteTo, @Nullable FileState state,
@Nullable Closeable closeable) {

try {
cleanUpFileState(fileToWriteTo, state, closeable);
}
catch (IOException ex) {
primary.addSuppressed(ex);
}
}

Expand Down Expand Up @@ -733,9 +753,11 @@ private void writeBytesToFile(File fileToWriteTo, boolean append, byte[] bytes)
bos.write(System.lineSeparator().getBytes());
}
}
finally {
cleanUpFileState(fileToWriteTo, state, bos);
catch (IOException | RuntimeException ex) {
cleanUpFileStateSuppressing(ex, fileToWriteTo, state, bos);
throw ex;
}
cleanUpFileState(fileToWriteTo, state, bos);
}

private File handleStringMessage(String content, @Nullable File originalFile, File tempFile, File resultFile,
Expand Down Expand Up @@ -776,9 +798,11 @@ private void writeStringToFile(File fileToWriteTo, boolean append, String conten
writer.newLine();
}
}
finally {
cleanUpFileState(fileToWriteTo, state, writer);
catch (IOException | RuntimeException ex) {
cleanUpFileStateSuppressing(ex, fileToWriteTo, state, writer);
throw ex;
}
cleanUpFileState(fileToWriteTo, state, writer);
}

private File determineFileToWrite(File resultFile, File tempFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
package org.springframework.integration.file.outbound;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.attribute.PosixFilePermission;
Expand Down Expand Up @@ -90,6 +94,7 @@
* @author Alen Turkovic
* @author Glenn Renfro
* @author Thomas Knall
* @author Jiwoo Lee
*/
public class FileWritingMessageHandlerTests implements TestApplicationContextAware {

Expand Down Expand Up @@ -776,4 +781,47 @@ protected File messageToFile(Message<?> result) {
return (File) result.getPayload();
}

@Test
void closeFailureIsReportedAndTheFileIsNotPromoted(@TempDir File localRoot) throws Exception {
File out = new File(localRoot, "out");
// A writer whose close() fails the way a full disk does: the buffered content
// never reaches the file and the IOException surfaces from close().
FileWritingMessageHandler handler = new FileWritingMessageHandler(out) {

@Override
protected BufferedWriter createWriter(File fileToWriteTo, boolean append)
throws FileNotFoundException {

Writer target;
try {
target = new FileWriter(fileToWriteTo, append);
}
catch (IOException ex) {
throw new FileNotFoundException(ex.getMessage());
}
return new BufferedWriter(target) {

@Override
public void close() throws IOException {
target.close();
throw new IOException("No space left on device");
}

};
}

};
handler.setFileNameGenerator(message -> "payload.txt");
handler.setOutputChannel(new NullChannel());
handler.setBeanFactory(TEST_INTEGRATION_CONTEXT);
handler.setApplicationContext(new GenericApplicationContext());
handler.afterPropertiesSet();

assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> handler.handleMessage(new GenericMessage<>("important payload")))
.withStackTraceContaining("java.io.IOException: No space left on device");

assertThat(new File(out, "payload.txt")).doesNotExist();
}

}