After searching for an obvious feature I found that it is missing in Camel out-of-the-box - I needed to track changes to a file with. I thought it would look like this: file://mydirectory?fileName=myFile.txt. File changes - I get an Exchange. This does not work. It is possible to track changes only to directories - appearance of new files. After the file was packed into Exchange it is deleted.
However, it appears there is a solution. For this we will need the latest version of Camel (see why) and a bit of courage:
package com.anydoby.camel;
import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.camel.spi.IdempotentRepository;
public class FileLastModifiedRepository implements IdempotentRepository<String> {
private final Map<String, FileLastModified> cache = new ConcurrentHashMap<String, FileLastModified>();
public boolean add(final String key) {
final File file = new File(key);
final long newLastModified = file.lastModified();
final FileLastModified lastModified = new FileLastModified(newLastModified, file);
final FileLastModified put = this.cache.put(key, lastModified);
return put == null || put.previousLastModified < newLastModified;
}
public boolean confirm(final String key) {
return true;
}
public boolean contains(final String key) {
final boolean containsKey = this.cache.containsKey(key);
if (containsKey) {
final FileLastModified lastModified = this.cache.get(key);
final long newLastModified = lastModified.fileReference.lastModified();
return newLastModified == lastModified.previousLastModified;
} else {
return false;
}
}
public boolean remove(final String key) {
return this.cache.remove(key) != null;
}
private static class FileLastModified {
public final long previousLastModified;
public final File fileReference;
FileLastModified(final Long previousLastModified, final File fileReference) {
this.previousLastModified = previousLastModified;
this.fileReference = fileReference;
}
}
}
The approach is as follows. In the file component options you can say idempotent=true - it means that duplicate messages are not delivered to the client. The code above is implementing a message id repository which uses File.lastModified as the criterion for "duplicacy". The net effect is what we wanted to achieve - the processed file will not be deleted, when it changes we get a notification.
Here is the route which we need to add:
from(
"file:target?noop=true&fileName=test.txt&initialDelay=0&delay=500&idempotentRepository=#fileLastModifiedRepository").process(processor());
Of course the repository has to be added as a Spring bean under the id fileLastModifiedRepository.
Here you can have a look at the unit test which demonstrates the usage.
