Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WatchService - incorrectly resolved absolute path

I've been playing around with the java.nio.file.WatchService and noticed that the Paths returned from WatchEvent.context() does not return correct .toAbsolutePath(). Here is an example application:

public class FsWatcher {
  public static void main(String[] args) throws IOException, InterruptedException {
    if (args.length != 1) {
      System.err.println("Invalid number of arguments: " + args.length);
      return;
    }
    //Run the application with absolute path like /home/<username>
    final Path watchedDirectory = Paths.get(args[0]).toAbsolutePath();
    final FileSystem fileSystem = FileSystems.getDefault();
    final WatchService watchService = fileSystem.newWatchService();
    watchedDirectory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);

    while (true) {
      WatchKey watchKey = watchService.take();
      for (WatchEvent<?> watchEvent : watchKey.pollEvents()) {
        if (watchEvent.kind().equals(StandardWatchEventKinds.OVERFLOW)) {
          continue;
        }

        final Path createdFile = (Path) watchEvent.context();
        final Path expectedAbsolutePath = watchedDirectory.resolve(createdFile);
        System.out.println("Context path: " + createdFile);
        System.out.println("Context absolute path: " + createdFile.toAbsolutePath());
        System.out.println("Expected absolute path: " + expectedAbsolutePath);
        System.out.println("usr.dir: " + System.getProperty("user.dir"));
      }
      watchKey.reset();
    }
  }
}

Example output:

Context path: document.txt
Context absolute path: /home/svetlin/workspaces/default/FsWatcher/document.txt
Expected absolute path: /home/svetlin/document.txt
usr.dir: /home/svetlin/workspaces/default/FsWatcher

It seems that the absolute path is resolved against the user.dir system property instead of the Path used for the WatchService registration. That's a problem because when I try to use (for instance Files.copy()) the path returned from the WatchEvent I receive a java.nio.file.NoSuchFileException, which is expected as there is no such file at this path. Am I missing something or this is a bug in the JRE ?

like image 895
Svetlin Zarev Avatar asked Sep 21 '15 09:09

Svetlin Zarev


1 Answers

This is not a bug, but certainly confusing.

If WatchEvent.context() returns a Path then it is relative:

In the case of ENTRY_CREATE, ENTRY_DELETE, and ENTRY_MODIFY events the context is a Path that is the relative path between the directory registered with the watch service, and the entry that is created, deleted, or modified.

Now if you turn such a path into an absolute path by calling toAbsolutePath() this happens not relative to the watched directory but to the default directory.

This method resolves the path in an implementation dependent manner, typically by resolving the path against a file system default directory. Depending on the implementation, this method may throw an I/O error if the file system is not accessible.

Therefore to turn the path into an absolute path you need to use

watchedDirectory.resolve(createdFile);
like image 114
wero Avatar answered Sep 27 '22 15:09

wero