rcurrie
rcurrie

Reputation: 339

Rename file in-place using Spring Integration FileWritingMessageHandler

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

Answers (1)

Artem Bilan
Artem Bilan

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

Related Questions