INT-3494: Resolve dir for writing as a Resource (#3109)

* INT-3494: Resolve dir for writing as a Resource

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

The expression for local directory can be resolved into a `Resource`
or resource location.
* Fix `ExpressionUtils.expressionToFile()` to support `Resource` and
also use `ResourceUtils.getFile(path)` when expression result is a string
* Modify tests to ensure that resource is resolved properly
* Upgrade affected tests to JUnit 5
* Mention an new functionality in docs

* * Improve Java doc for `ExpressionUtils.expressionToFile()`
* Finish the sentence in the `file.adoc`
This commit is contained in:
Artem Bilan
2019-11-14 16:27:59 -05:00
committed by Gary Russell
parent 069d8730e0
commit 0f5bd4a40a
7 changed files with 164 additions and 211 deletions

View File

@@ -17,6 +17,8 @@
package org.springframework.integration.expression;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -25,6 +27,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MapAccessor;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.Resource;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
@@ -39,6 +42,7 @@ import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
/**
* Utility class with static methods for helping with evaluation of SpEL expressions.
@@ -53,7 +57,7 @@ public final class ExpressionUtils {
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
private static final Log logger = LogFactory.getLog(ExpressionUtils.class);
private static final Log LOGGER = LogFactory.getLog(ExpressionUtils.class);
private ExpressionUtils() {
super();
@@ -84,7 +88,7 @@ public final class ExpressionUtils {
*/
public static StandardEvaluationContext createStandardEvaluationContext(@Nullable BeanFactory beanFactory) {
if (beanFactory == null) {
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
LOGGER.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
}
return (StandardEvaluationContext) doCreateContext(beanFactory, false);
}
@@ -98,7 +102,7 @@ public final class ExpressionUtils {
*/
public static SimpleEvaluationContext createSimpleEvaluationContext(@Nullable BeanFactory beanFactory) {
if (beanFactory == null) {
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
LOGGER.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
}
return (SimpleEvaluationContext) doCreateContext(beanFactory, true);
}
@@ -161,36 +165,56 @@ public final class ExpressionUtils {
* @param expression the expression.
* @param evaluationContext the evaluation context.
* @param message the message (if available).
* @param name the name of the result of the evaluation.
* @param propertyName the property name the expression is evaluated for.
* @return the File.
* @since 5.0
*/
public static File expressionToFile(Expression expression, EvaluationContext evaluationContext,
@Nullable Message<?> message, String name) {
@Nullable Message<?> message, String propertyName) {
File file;
Object value = message == null
? expression.getValue(evaluationContext)
: expression.getValue(evaluationContext, message);
if (value == null) {
throw new IllegalStateException(String.format("The provided %s expression (%s) must not evaluate to null.",
name, expression.getExpressionString()));
}
else if (value instanceof File) {
file = (File) value;
Object value =
message == null
? expression.getValue(evaluationContext)
: expression.getValue(evaluationContext, message);
Assert.state(value != null, () ->
String.format("The provided %s expression (%s) must not evaluate to null.",
propertyName, expression.getExpressionString()));
if (value instanceof File) {
return (File) value;
}
else if (value instanceof String) {
String path = (String) value;
Assert.hasText(path, String.format("Unable to resolve %s for the provided Expression '%s'.", name,
Assert.hasText(path, String.format("Unable to resolve %s for the provided Expression '%s'.", propertyName,
expression.getExpressionString()));
file = new File(path);
try {
return ResourceUtils.getFile(path);
}
catch (FileNotFoundException ex) {
throw new IllegalStateException(
String.format("Unable to resolve %s for the provided Expression '%s'.",
propertyName, expression.getExpressionString()),
ex);
}
}
else if (value instanceof Resource) {
try {
return ((Resource) value).getFile();
}
catch (IOException ex) {
throw new IllegalStateException(
String.format("Unable to resolve %s for the provided Expression '%s'.",
propertyName, expression.getExpressionString()),
ex);
}
}
else {
throw new IllegalStateException(String.format(
"The provided %s expression (%s) must evaluate to type java.io.File or String, not %s.", name,
"The provided %s expression (%s) must evaluate to type java.io.File, String " +
"or org.springframework.core.io.Resource, not %s.", propertyName,
expression.getExpressionString(), value.getClass().getName()));
}
return file;
}
/**

View File

@@ -18,7 +18,7 @@
<si:header-enricher>
<si:header name="#{T(org.springframework.integration.file.FileHeaders).FILENAME}" value="${test.file}"/>
</si:header-enricher>
<file:outbound-channel-adapter id="file-outbound-channel-adapter-within-chain" directory="${work.dir}"/>
<file:outbound-channel-adapter id="file-outbound-channel-adapter-within-chain" directory-expression="${work.dir}"/>
</si:chain>
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">

View File

@@ -22,69 +22,47 @@ import java.io.File;
import java.io.IOException;
import java.util.Properties;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.util.FileCopyUtils;
/**
* //INT-2275
*
* @author Artem Bilan
* @author Gary Russell
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringJUnitConfig
public class FileOutboundChannelAdapterInsideChainTests {
public static final String TEST_FILE_NAME = FileOutboundChannelAdapterInsideChainTests.class.getSimpleName();
static final String TEST_FILE_NAME = FileOutboundChannelAdapterInsideChainTests.class.getSimpleName();
public static final String WORK_DIR_NAME = System.getProperty("java.io.tmpdir") + "/" + FileOutboundChannelAdapterInsideChainTests.class.getSimpleName() + "Dir";
static final String SAMPLE_CONTENT = "test";
public static final String SAMPLE_CONTENT = "test";
@TempDir
static File WORK_DIR;
public static Properties placeholderProperties = new Properties();
static {
placeholderProperties.put("test.file", TEST_FILE_NAME);
placeholderProperties.put("work.dir", WORK_DIR_NAME);
}
@Autowired
private MessageChannel outboundChainChannel;
private static File workDir;
@BeforeClass
public static void setupClass() {
workDir = new File(WORK_DIR_NAME);
workDir.mkdir();
workDir.deleteOnExit();
@BeforeAll
static void setupClass() {
placeholderProperties.put("test.file", TEST_FILE_NAME);
placeholderProperties.put("work.dir", "'file://" + WORK_DIR.getAbsolutePath() + '\'');
}
@AfterClass
public static void cleanUp() {
if (workDir != null && workDir.exists()) {
for (File file : workDir.listFiles()) {
file.delete();
}
}
workDir.delete();
}
@Test //INT-2275
public void testFileOutboundChannelAdapterWithinChain() throws IOException {
@Test
void testFileOutboundChannelAdapterWithinChain() throws IOException {
Message<String> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
outboundChainChannel.send(message);
File testFile = new File(workDir, TEST_FILE_NAME);
File testFile = new File(WORK_DIR, TEST_FILE_NAME);
assertThat(testFile.exists()).isTrue();
byte[] testFileContent = FileCopyUtils.copyToByteArray(testFile);
assertThat(SAMPLE_CONTENT).isEqualTo(new String(testFileContent));

View File

@@ -17,15 +17,14 @@
package org.springframework.integration.file;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.io.File;
import java.io.FileOutputStream;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.MessageBuilder;
@@ -33,8 +32,7 @@ import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.util.FileCopyUtils;
/**
@@ -42,9 +40,8 @@ import org.springframework.util.FileCopyUtils;
* @author Artem Bilan
* @author Gary Russell
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class FileOutboundChannelAdapterIntegrationTests {
@SpringJUnitConfig
class FileOutboundChannelAdapterIntegrationTests {
static final String DEFAULT_ENCODING = "UTF-8";
@@ -78,103 +75,71 @@ public class FileOutboundChannelAdapterIntegrationTests {
File sourceFile;
@Before
public void setUp() throws Exception {
sourceFile = File.createTempFile("anyFile", ".txt");
sourceFile.deleteOnExit();
@BeforeEach
void setUp(@TempDir File tmpDir) throws Exception {
sourceFile = new File(tmpDir, "anyFile.txt");
FileCopyUtils.copy(SAMPLE_CONTENT.getBytes(DEFAULT_ENCODING),
new FileOutputStream(sourceFile, false));
message = MessageBuilder.withPayload(sourceFile).build();
}
@After
public void tearDown() {
sourceFile.delete();
}
@Test
public void saveToBaseDir() throws Exception {
this.inputChannelSaveToBaseDir.send(message);
void saveToBaseDir() {
this.inputChannelSaveToBaseDir.send(this.message);
assertThat(new File("target/base-directory/foo.txt").exists()).isTrue();
}
@Test
public void saveToBaseDirDeleteSourceFile() throws Exception {
void saveToBaseDirDeleteSourceFile() {
assertThat(sourceFile.exists()).isTrue();
this.inputChannelSaveToBaseDirDeleteSource.send(message);
this.inputChannelSaveToBaseDirDeleteSource.send(this.message);
assertThat(new File("target/base-directory/foo.txt").exists()).isTrue();
assertThat(sourceFile.exists()).isFalse();
}
@Test
public void saveToSubDir() throws Exception {
this.inputChannelSaveToSubDir.send(message);
void saveToSubDir() {
this.inputChannelSaveToSubDir.send(this.message);
assertThat(new File("target/base-directory/sub-directory/foo.txt").exists()).isTrue();
}
@Test
public void saveToSubDirWithWrongExpression() throws Exception {
try {
this.inputChannelSaveToSubDirWrongExpression.send(message);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo(TestUtils
.applySystemFileSeparator("Destination path [target/base-directory/sub-directory/foo.txt] does not" +
" point to a directory."));
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
void saveToSubDirWithWrongExpression() {
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirWrongExpression.send(this.message))
.withStackTraceContaining(TestUtils.applySystemFileSeparator(
"Destination path [target/base-directory/sub-directory/foo.txt] does " +
"not point to a directory."));
}
@Test
public void saveToSubDirWithEmptyStringExpression() throws Exception {
try {
this.inputChannelSaveToSubDirEmptyStringExpression.send(message);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage())
.isEqualTo("Unable to resolve Destination Directory for the provided Expression '' ''.");
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
void saveToSubDirWithEmptyStringExpression() {
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirEmptyStringExpression.send(this.message))
.withStackTraceContaining("Unable to resolve Destination Directory for " +
"the provided Expression '' ''.");
}
@Test
public void saveToSubDir2() throws Exception {
final Message<File> message2 = MessageBuilder.fromMessage(message)
.setHeader("myFileLocation", "target/base-directory/headerdir")
.build();
void saveToSubDir2() {
Message<File> message2 = MessageBuilder.fromMessage(message)
.setHeader("myFileLocation", "target/base-directory/headerdir")
.build();
this.inputChannelSaveToSubDirWithHeader.send(message2);
assertThat(new File("target/base-directory/headerdir/foo.txt").exists()).isTrue();
}
@Test
public void saveToSubDirAutoCreateOff() throws Exception {
try {
this.inputChannelSaveToSubDirAutoCreateOff.send(message);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo(TestUtils
.applySystemFileSeparator("Destination directory [target/base-directory2/sub-directory2] does not " +
"exist."));
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
void saveToSubDirAutoCreateOff() {
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirAutoCreateOff.send(this.message))
.withStackTraceContaining(TestUtils.applySystemFileSeparator("Destination directory " +
"[target/base-directory2/sub-directory2] does not exist."));
}
@Test
public void saveToSubWithFileExpression() throws Exception {
void saveToSubWithFileExpression() {
final File directory = new File("target/base-directory/sub-directory");
final Message<File> messageWithFileHeader = MessageBuilder.fromMessage(message)
.setHeader("subDirectory", directory)
@@ -184,46 +149,30 @@ public class FileOutboundChannelAdapterIntegrationTests {
}
@Test
public void saveToSubWithFileExpressionNull() throws Exception {
void saveToSubWithFileExpressionNull() {
final File directory = null;
final Message<File> messageWithFileHeader = MessageBuilder.fromMessage(message)
.setHeader("subDirectory", directory)
.build();
try {
this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo("The provided Destination Directory expression " +
"(headers['subDirectory']) must not evaluate to null.");
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader))
.withStackTraceContaining("The provided Destination Directory expression " +
"(headers['subDirectory']) must not evaluate to null.");
}
@Test
public void saveToSubWithFileExpressionUnsupportedObjectType() throws Exception {
final Integer unsupportedObject = Integer.valueOf(1234);
void saveToSubWithFileExpressionUnsupportedObjectType() {
final Integer unsupportedObject = 1234;
final Message<File> messageWithFileHeader = MessageBuilder.fromMessage(message)
.setHeader("subDirectory", unsupportedObject)
.build();
try {
this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo("The provided Destination Directory expression" +
" (headers['subDirectory']) must evaluate to type " +
"java.io.File or String, not java.lang.Integer.");
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader))
.withStackTraceContaining("The provided Destination Directory expression" +
" (headers['subDirectory']) must evaluate to type " +
"java.io.File, String or org.springframework.core.io.Resource, not java.lang.Integer.");
}
}

View File

@@ -17,6 +17,8 @@
package org.springframework.integration.file;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -39,19 +41,21 @@ import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.expression.Expression;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.QueueChannel;
@@ -79,36 +83,36 @@ public class FileWritingMessageHandlerTests {
static final String DEFAULT_ENCODING = "UTF-8";
static final String SAMPLE_CONTENT = "HelloWorld\n????";
static final String SAMPLE_CONTENT = "HelloWorld\näöüß";
private File sourceFile;
@Rule
public TemporaryFolder temp = new TemporaryFolder() {
@Override
public void create() throws IOException {
super.create();
outputDirectory = temp.newFolder("outputDirectory");
handler = new FileWritingMessageHandler(outputDirectory);
handler.setBeanFactory(mock(BeanFactory.class));
handler.afterPropertiesSet();
sourceFile = temp.newFile("sourceFile");
FileCopyUtils.copy(SAMPLE_CONTENT.getBytes(DEFAULT_ENCODING),
new FileOutputStream(sourceFile, false));
}
};
@TempDir
File tempDir;
private File outputDirectory;
private FileWritingMessageHandler handler;
@Test(expected = MessageHandlingException.class)
@BeforeEach
void setup() throws IOException {
outputDirectory = new File(tempDir, "outputDirectory");
sourceFile = new File(tempDir, "sourceFile");
FileCopyUtils.copy(SAMPLE_CONTENT.getBytes(DEFAULT_ENCODING),
new FileOutputStream(sourceFile, false));
this.handler = new FileWritingMessageHandler(this.outputDirectory);
this.handler.setBeanFactory(mock(BeanFactory.class));
this.handler.setApplicationContext(new GenericApplicationContext());
this.handler.afterPropertiesSet();
}
@Test
public void unsupportedType() {
this.handler.handleMessage(new GenericMessage<>(99));
assertThat(this.outputDirectory.listFiles()[0]).isNull();
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.handler.handleMessage(new GenericMessage<>(99)));
}
@Test
@@ -138,7 +142,7 @@ public class FileWritingMessageHandlerTests {
handler.setChmod(0777);
}
handler.setOutputChannel(new NullChannel());
handler.handleMessage(new GenericMessage<String>("test"));
handler.handleMessage(new GenericMessage<>("test"));
File[] output = outputDirectory.listFiles();
assertThat(output.length).isEqualTo(1);
assertThat(output[0]).isNotNull();
@@ -265,18 +269,14 @@ public class FileWritingMessageHandlerTests {
}
@Test
@Ignore("INT-3289: doesn't fail on all OS")
@Disabled("INT-3289: doesn't fail on all OS")
public void testCreateDirFail() {
File dir = new File("/foo");
FileWritingMessageHandler handler = new FileWritingMessageHandler(dir);
handler.setBeanFactory(mock(BeanFactory.class));
try {
handler.afterPropertiesSet();
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage()).contains("[/foo] could not be created");
}
assertThatIllegalArgumentException()
.isThrownBy(handler::afterPropertiesSet)
.withMessageContaining("[/foo] could not be created");
}
@Test
@@ -369,7 +369,7 @@ public class FileWritingMessageHandlerTests {
}
@Test
public void deleteSourceFileWithInputstreamPayloadAndFileInstanceHeader() throws Exception {
public void deleteSourceFileWithInputStreamPayloadAndFileInstanceHeader() throws Exception {
QueueChannel output = new QueueChannel();
handler.setCharset(DEFAULT_ENCODING);
handler.setDeleteSourceFiles(true);
@@ -388,7 +388,7 @@ public class FileWritingMessageHandlerTests {
}
@Test
public void deleteSourceFileWithInputstreamPayloadAndFilePathHeader() throws Exception {
public void deleteSourceFileWithInputStreamPayloadAndFilePathHeader() throws Exception {
QueueChannel output = new QueueChannel();
handler.setCharset(DEFAULT_ENCODING);
handler.setDeleteSourceFiles(true);
@@ -407,7 +407,7 @@ public class FileWritingMessageHandlerTests {
}
@Test
public void customFileNameGenerator() throws Exception {
public void customFileNameGenerator() {
final String anyFilename = "fooBar.test";
QueueChannel output = new QueueChannel();
handler.setOutputChannel(output);
@@ -422,7 +422,7 @@ public class FileWritingMessageHandlerTests {
public void existingFileIgnored() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
QueueChannel output = new QueueChannel();
File outFile = temp.newFile("/outputDirectory/" + message.getHeaders().getId().toString() + ".msg");
File outFile = new File(tempDir, "/outputDirectory/" + message.getHeaders().getId().toString() + ".msg");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(outFile));
handler.setCharset(DEFAULT_ENCODING);
handler.setOutputChannel(output);
@@ -436,7 +436,8 @@ public class FileWritingMessageHandlerTests {
public void existingWritingFileIgnored() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
QueueChannel output = new QueueChannel();
File outFile = temp.newFile("/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
File outFile =
new File(tempDir, "/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(outFile));
handler.setCharset(DEFAULT_ENCODING);
handler.setOutputChannel(output);
@@ -453,7 +454,8 @@ public class FileWritingMessageHandlerTests {
public void existingWritingFileNotIgnoredIfEmptySuffix() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
QueueChannel output = new QueueChannel();
File outFile = temp.newFile("/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
File outFile =
new File(tempDir, "/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(outFile));
handler.setCharset(DEFAULT_ENCODING);
handler.setOutputChannel(output);
@@ -470,7 +472,7 @@ public class FileWritingMessageHandlerTests {
@Test
public void noFlushAppend() throws Exception {
File tempFolder = this.temp.newFolder();
File tempFolder = new File(tempDir, UUID.randomUUID().toString());
FileWritingMessageHandler handler = new FileWritingMessageHandler(tempFolder);
handler.setFileExistsMode(FileExistsMode.APPEND_NO_FLUSH);
handler.setFileNameGenerator(message -> "foo.txt");
@@ -483,10 +485,10 @@ public class FileWritingMessageHandlerTests {
handler.afterPropertiesSet();
handler.start();
File file = new File(tempFolder, "foo.txt");
handler.handleMessage(new GenericMessage<String>("foo"));
handler.handleMessage(new GenericMessage<String>("bar"));
handler.handleMessage(new GenericMessage<String>("baz"));
handler.handleMessage(new GenericMessage<byte[]>("qux".getBytes())); // change of payload type forces flush
handler.handleMessage(new GenericMessage<>("foo"));
handler.handleMessage(new GenericMessage<>("bar"));
handler.handleMessage(new GenericMessage<>("baz"));
handler.handleMessage(new GenericMessage<>("qux".getBytes())); // change of payload type forces flush
assertThat(file.length()).isGreaterThanOrEqualTo(9L);
handler.stop(); // forces flush
assertThat(file.length()).isEqualTo(12L);
@@ -499,7 +501,7 @@ public class FileWritingMessageHandlerTests {
}
assertThat(file.length()).isEqualTo(15L);
handler.handleMessage(new GenericMessage<InputStream>(new ByteArrayInputStream("buz".getBytes())));
handler.trigger(new GenericMessage<String>(Matcher.quoteReplacement(file.getAbsolutePath())));
handler.trigger(new GenericMessage<>(Matcher.quoteReplacement(file.getAbsolutePath())));
assertThat(file.length()).isEqualTo(18L);
assertThat(TestUtils.getPropertyValue(handler, "fileStates", Map.class).size()).isEqualTo(0);
@@ -510,7 +512,7 @@ public class FileWritingMessageHandlerTests {
return true;
});
handler.handleMessage(new GenericMessage<InputStream>(new ByteArrayInputStream("box".getBytes())));
handler.trigger(new GenericMessage<String>("foo"));
handler.trigger(new GenericMessage<>("foo"));
assertThat(file.length()).isEqualTo(21L);
assertThat(called.get()).isTrue();
@@ -536,7 +538,7 @@ public class FileWritingMessageHandlerTests {
handler.setFlushWhenIdle(false);
handler.start();
for (int i = 0; i < 40; i++) {
handler.handleMessage(new GenericMessage<String>("foo"));
handler.handleMessage(new GenericMessage<>("foo"));
Thread.sleep(5);
}
assertThat(flushes.get()).isGreaterThanOrEqualTo(2);
@@ -545,7 +547,7 @@ public class FileWritingMessageHandlerTests {
@Test
public void lockForFlush() throws Exception {
File tempFolder = this.temp.newFolder();
File tempFolder = new File(tempDir, UUID.randomUUID().toString());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final BufferedOutputStream out = spy(new BufferedOutputStream(baos));
FileWritingMessageHandler handler = new FileWritingMessageHandler(tempFolder) {
@@ -617,7 +619,7 @@ public class FileWritingMessageHandlerTests {
@Test
public void replaceIfDifferentFile() throws IOException {
File file = new File(this.temp.newFolder(), "foo.txt");
File file = new File(this.tempDir, "foo.txt");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(file));
file.setLastModified(42_000_000);
QueueChannel output = new QueueChannel();
@@ -691,8 +693,7 @@ public class FileWritingMessageHandlerTests {
protected File messageToFile(Message<?> result) {
assertThat(result).isNotNull();
assertThat(result.getPayload()).isInstanceOf(File.class);
File destFile = (File) result.getPayload();
return destFile;
return (File) result.getPayload();
}
}

View File

@@ -333,7 +333,7 @@ public class FileTests {
@Bean
public IntegrationFlow fileFlow1() {
return IntegrationFlows.from("fileFlow1Input")
.handle(Files.outboundAdapter(tmpDir.getRoot())
.handle(Files.outboundAdapter("'file://" + tmpDir.getRoot().getAbsolutePath() + '\'')
.fileNameGenerator(message -> null)
.fileExistsMode(FileExistsMode.APPEND_NO_FLUSH)
.flushInterval(60000)

View File

@@ -688,7 +688,8 @@ If you want to have full SpEL support, you can use the `directory-expression` at
This attribute accepts a SpEL expression that is evaluated for each message being processed.
Thus, you have full access to a message's payload and its headers when you dynamically specify the output file directory.
The SpEL expression must resolve to either a `String` or to `java.io.File`.
The SpEL expression must resolve to either a `String`, `java.io.File` or `org.springframework.core.io.Resource`.
(The later is evaluated into a `File` anyway.)
Furthermore, the resulting `String` or `File` must point to a directory.
If you do not specify the `directory-expression` attribute, then you must set the `directory` attribute.