Русский English Tags View Sergey Zolotaryov's profile on LinkedIn Sign-in
How to track file modifications in Camel
Permanent link 28-07-2010 anydoby java camel

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.

Add a comment

taharqa
03-10-2011

Hi ,

Thank you for your article, and for your IdempotentRepository implementation !

/!\ I'm completly new with camel !

Do your implementation, can be used to monitoring recursivly all the file from one folder ?

In your sample you're monitoting a single file.

Thank you in advance

E.

anydoby
03-10-2011

Hi. Well, repository only keeps track of modified files, so whether you track a file or folder does not matter.

And it is also a demo implementation, a more robust solution is needed for production :)

Previous article Reusable properties exposed as beans in Spring Next article New and noteworthy