INT-3726-4.2.x: Support path for generateFileName

JIRA: https://jira.spring.io/browse/INT-3726

Backport for `4.2.x`
This commit is contained in:
Artem Bilan
2016-01-05 17:49:26 -05:00
parent 265d3d2562
commit 588ccdbb00
3 changed files with 41 additions and 14 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@@ -26,6 +26,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -259,6 +260,9 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
validateDestinationDirectory(directory, this.autoCreateDirectory);
}
Assert.state(!(this.temporaryFileSuffixSet && FileExistsMode.APPEND.equals(this.fileExistsMode)),
"'temporaryFileSuffix' can not be set when appending to an existing file");
if (!this.fileNameGeneratorSet && this.fileNameGenerator instanceof BeanFactoryAware) {
((BeanFactoryAware) this.fileNameGenerator).setBeanFactory(this.getBeanFactory());
}
@@ -277,9 +281,6 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
"Destination path [" + destinationDirectory + "] does not point to a directory.");
Assert.isTrue(destinationDirectory.canWrite(),
"Destination directory [" + destinationDirectory + "] is not writable.");
Assert.state(!(this.temporaryFileSuffixSet
&& FileExistsMode.APPEND.equals(this.fileExistsMode)),
"'temporaryFileSuffix' can not be set when appending to an existing file");
}
@Override
@@ -307,6 +308,11 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
if (!ignore) {
try {
if (!resultFile.exists() &&
generatedFileName.replaceAll("/", Matcher.quoteReplacement(File.separator))
.contains(File.separator)) {
resultFile.getParentFile().mkdirs();
}
if (payload instanceof File) {
resultFile = handleFileMessage((File) payload, tempFile, resultFile);
}

View File

@@ -33,18 +33,19 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.file.support.FileExistsMode;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.support.GenericMessage;
@@ -57,6 +58,7 @@ import org.springframework.util.FileCopyUtils;
* @author Gary Russell
* @author Tony Falabella
* @author Gunnar Hillert
* @author Artem Bilan
*/
public class FileWritingMessageHandlerTests {
@@ -115,6 +117,21 @@ public class FileWritingMessageHandlerTests {
assertFileContentIsMatching(result);
}
@Test
public void testFileNameHeader() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT)
.setHeader(FileHeaders.FILENAME, "dir1" + File.separator + "dir2/test")
.build();
QueueChannel output = new QueueChannel();
handler.setCharset(DEFAULT_ENCODING);
handler.setOutputChannel(output);
handler.handleMessage(message);
Message<?> result = output.receive(0);
assertFileContentIsMatching(result);
File destFile = (File) result.getPayload();
assertThat(destFile.getAbsolutePath(), containsString(TestUtils.applySystemFileSeparator("/dir1/dir2/test")));
}
@Test
public void stringPayloadCopiedToNewFileWithNewLines() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
@@ -196,7 +213,8 @@ public class FileWritingMessageHandlerTests {
assertFileContentIs(result, SAMPLE_CONTENT + System.getProperty("line.separator"));
}
@Test @Ignore // INT-3289 ignored because it won't fail on all OS
@Test
@Ignore("INT-3289: doesn't fail on all OS")
public void testCreateDirFail() {
File dir = new File("/foo");
FileWritingMessageHandler handler = new FileWritingMessageHandler(dir);
@@ -404,18 +422,18 @@ public class FileWritingMessageHandlerTests {
assertFileContentIs(outFile, "foo");
}
void assertFileContentIsMatching(Message<?> result) throws IOException, UnsupportedEncodingException {
void assertFileContentIsMatching(Message<?> result) throws IOException {
assertFileContentIs(result, SAMPLE_CONTENT);
}
void assertFileContentIs(Message<?> result, String expected) throws IOException, UnsupportedEncodingException {
void assertFileContentIs(Message<?> result, String expected) throws IOException {
assertThat(result, is(notNullValue()));
assertThat(result.getPayload(), is(instanceOf(File.class)));
File destFile = (File) result.getPayload();
assertFileContentIs(destFile, expected);
}
void assertFileContentIs(File destFile, String expected) throws IOException, UnsupportedEncodingException {
void assertFileContentIs(File destFile, String expected) throws IOException {
assertNotSame(destFile, sourceFile);
assertThat(destFile.exists(), is(true));
byte[] destFileContent = FileCopyUtils.copyToByteArray(destFile);

View File

@@ -459,17 +459,22 @@ Once setup, the `DefaultFileNameGenerator` will employ the following resolution
When using the XML namespace support, both, the _File Outbound Channel Adapter_ and the _File Outbound Gateway_ support the following two mutually exclusive configuration attributes:
* `filename-generator` (a reference to a `FileNameGenerator`) implementation)
* `filename-generator` (a reference to a `FileNameGenerator` implementation)
* `filename-generator-expression` (an expression evaluating to a `String`)
While writing files, a temporary file suffix will be used (default: `.writing`).
It is appended to the filename while the file is being written.
To customize the suffix, you can set the _temporary-file-suffix_ attribute on both the _File Outbound Channel Adapter_ and the _File Outbound Gateway_.
NOTE: When using the _APPEND_ file _mode_, the _temporary-file-suffix_ attribute is ignored, since the data is appended to the file directly.
Starting with _version 4.2.5_ the generated file name (as a result of `filename-generator`/`filename-generator-expression`
evaluation) can represent a _sub-path_ together with the target file name.
It is used as a second constructor argument for `File(File parent, String child)` as before, but in the past we didn't
created (`mkdirs()`) directories for _sub-path_ assuming only the _file name_.
This approach is useful for cases when we need to restore the file system tree according the source directory.
For example we unzipping the archive and want to save all file in the target directory at the same order.
[[file-writing-output-directory]]
==== Specifying the Output Directory
@@ -478,8 +483,6 @@ Both, the _File Outbound Channel Adapter_ and the _File Outbound Gateway_ provid
* _directory_
* _directory-expression_
NOTE: The _directory-expression_ attribute is available since Spring Integration 2.2.
*Using the directory attribute*