Reputation: 339
I am attempting to write a simple test of renaming files in-place using a FileWritingMessageHandler, however I can't seem to figure out how to properly specify the target destination directory.
Since I am recursively scanning a directory tree I would ultimately like to simply read the parent path from the file payload and rename it using the FileNameGenerator, but that doesn't appear to work.
The 'payload.name' in the DefaultFileNameGenerator resolves properly, but 'payload.path' does not.
How do I properly determine the source file's location and use that in the handler?
Edit
Here is the channel adapter that scans for files. I had to use .setUseWatchService(true)
to achieve recursive scanning.
@Bean
@InboundChannelAdapter(channel = "sourceFileChannel", poller = @Poller(fixedRate = "5000", maxMessagesPerPoll = "-1"))
public MessageSource<File> sourceFiles() {
CompositeFileListFilter<File> filters = new CompositeFileListFilter<>();
filters.addFilter(new SimplePatternFileListFilter(sourceFilenamePattern));
filters.addFilter(persistentFilter());
FileReadingMessageSource source = new FileReadingMessageSource();
source.setAutoCreateDirectory(true);
source.setDirectory(new File(sourceDirectory));
source.setFilter(filters);
source.setUseWatchService(true);
return source;
}
UPDATE
Artem helped me understand my mistake.
I was able to achieve the desired result by using the SpelExpressionParser as Artem outlined.
The key piece being:
new SpelExpressionParser().parseExpression("payload.parent")
Where "payload.parent" resolves to the file parent path properly.
@Bean
@ServiceActivator(inputChannel = "processingFileChannel")
public MessageHandler copyFileForProcessingOutboundChannelAdapter() {
FileWritingMessageHandler adapter = new FileWritingMessageHandler(new SpelExpressionParser().parseExpression("payload.parent"));
adapter.setDeleteSourceFiles(false);
adapter.setAutoCreateDirectory(true);
adapter.setExpectReply(false);
adapter.setFileNameGenerator(processingFileNameGenerator());
return adapter;
}
@Bean
public DefaultFileNameGenerator processingFileNameGenerator() {
DefaultFileNameGenerator defaultFileNameGenerator = new DefaultFileNameGenerator();
defaultFileNameGenerator.setExpression("'p_' + payload.name");
return defaultFileNameGenerator;
}
Upvotes: 1
Views: 1480
Reputation: 121427
The 'payload.name' in the DefaultFileNameGenerator resolves properly, but 'payload.path' does not.
Well, I'm not sure what should be in your case, but for me that always returns the full, absolute path for source file, including the root directory to scan.
Since you have it there as a sourceDirectory
, how about to use it in your processingFileNameGenerator
to sever the root dir from the target path
to use? For example if my root dir is /root
and I get a file from the subdir /root/foo/my_file.txt
, I could do payload.path.replaceFirst('/root', '')
. So in the end I have just /foo/my_file.txt
.
At least that is what I'm going to do in that JIRA to populate FileHeaders.FILENAME
with the relative path from the provided directory
to scan.
UPDATE
Oh! I see. No, that isn't going to work that way. See FileWritingMessageHandler
ctors. The String
once accepts static target directory. Root for our case. The code like new LiteralExpression("payload.path")
isn't going to work a desired way, too. See LiteralExpression
JavaDocs. It is just an Expression
variant to always return the same static value. In your case it is payload.path
.
If you are really going to evaluate against an incoming Message
, you should use new SpeLexpressionParser().parseExpression("payload.path")
. But as I said before, it returns the absolute path for any file in the sub-directories.
Upvotes: 2