core/src/main/java/io/methvin/watcher/DirectoryWatcher.java
public void watch() {
    for (; ; ) {
      if (!listener.isWatching()) {
        return;
      }
      // wait for key to be signalled
      WatchKey key;
      try {
        key = watchService.take();
      } catch (InterruptedException x) {
        return;
      }
      for (WatchEvent<?> event : key.pollEvents()) {
        try {
          WatchEvent.Kind<?> kind = event.kind();
          // Context for directory entry event is the file name of entry
          WatchEvent<Path> ev = PathUtils.cast(event);
          int count = ev.count();
          Path eventPath = ev.context();
          if (!keyRoots.containsKey(key)) {
            throw new IllegalStateException(
                "WatchService returned key [" + key + "] but it was not found in keyRoots!");
          }
          Path childPath = eventPath == null ? null : keyRoots.get(key).resolve(eventPath);
          logger.debug("{} [{}]", kind, childPath);
          /*
           * If a directory is created, and we're watching recursively, then register it and its sub-directories.
           */
          if (kind == OVERFLOW) {
            listener.onEvent(new DirectoryChangeEvent(EventType.OVERFLOW, childPath, count));
          } else if (eventPath == null) {
            throw new IllegalStateException("WatchService returned a null path for " + kind.name());
          } else if (kind == ENTRY_CREATE) {
            if (Files.isDirectory(childPath, NOFOLLOW_LINKS)) {
              if (!Boolean.TRUE.equals(fileTreeSupported)) {
                registerAll(childPath);
              }
              /*
               * Our custom Mac service sends subdirectory changes but the Windows/Linux do not.
               * Walk the file tree to make sure we send create events for any files that were created.
               */
              if (!isMac) {
                PathUtils.recursiveVisitFiles(
                    childPath,
                    dir -> notifyCreateEvent(dir, count),
                    file -> notifyCreateEvent(file, count));
              }
            }
            notifyCreateEvent(childPath, count);
          } else if (kind == ENTRY_MODIFY) {
            if (fileHasher != null || Files.isDirectory(childPath)) {
              /*
               * Note that existingHash may be null due to the file being created before we start listening
               * It's important we don't discard the event in this case
               */
              HashCode existingHash = pathHashes.get(childPath);

              /*
               * newHash can be null when using File#delete() on windows - it generates MODIFY and DELETE in succession.
               * In this case the MODIFY event can be safely ignored
               */
              HashCode newHash = PathUtils.hash(fileHasher, childPath);

              if (newHash != null && !newHash.equals(existingHash)) {
                pathHashes.put(childPath, newHash);
                listener.onEvent(new DirectoryChangeEvent(EventType.MODIFY, childPath, count));
              } else if (newHash == null) {
                logger.debug(
                    "Failed to hash modified file [{}]. It may have been deleted.", childPath);
              }
            } else {
              listener.onEvent(new DirectoryChangeEvent(EventType.MODIFY, childPath, count));
            }
          } else if (kind == ENTRY_DELETE) {
            // we cannot tell if the deletion was on file or folder because path points nowhere
            // (file/folder was deleted)
            pathHashes.entrySet().removeIf(e -> e.getKey().startsWith(childPath));
            listener.onEvent(new DirectoryChangeEvent(EventType.DELETE, childPath, count));
          }
        } catch (Exception e) {
          logger.debug("DirectoryWatcher got an exception while watching!", e);
          listener.onException(e);
        }
      }
      boolean valid = key.reset();
      if (!valid) {
        logger.debug("WatchKey for [{}] no longer valid; removing.", key.watchable());
        // remove the key from the keyRoots
        keyRoots.remove(key);
        // if there are no more keys left to watch, we can break out
        if (keyRoots.isEmpty()) {
          logger.debug("No more directories left to watch; terminating watcher.");
          break;
        }
      }
    }
  }
public void watch() {
    for (; ; ) {
      if (!listener.isWatching()) {
        return;
      }
      // wait for key to be signalled
      WatchKey key;
      try {
        key = watchService.take();
      } catch (InterruptedException x) {
        return;
      }
      for (WatchEvent<?> event : key.pollEvents()) {
        try {
          WatchEvent.Kind<?> kind = event.kind();
          // Context for directory entry event is the file name of entry
          WatchEvent<Path> ev = PathUtils.cast(event);
          int count = ev.count();
          Path eventPath = ev.context();
          if (!keyRoots.containsKey(key)) {
            throw new IllegalStateException(
                "WatchService returned key [" + key + "] but it was not found in keyRoots!");
          }
          Path childPath = eventPath == null ? null : keyRoots.get(key).resolve(eventPath);
          logger.debug("{} [{}]", kind, childPath);
          /*
           * If a directory is created, and we're watching recursively, then register it and its sub-directories.
           */
          if (kind == OVERFLOW) {
            listener.onEvent(new DirectoryChangeEvent(EventType.OVERFLOW, childPath, count));
          } else if (eventPath == null) {
            throw new IllegalStateException("WatchService returned a null path for " + kind.name());
          } else if (kind == ENTRY_CREATE) {
            if (Files.isDirectory(childPath, NOFOLLOW_LINKS)) {
              if (!Boolean.TRUE.equals(fileTreeSupported)) {
                registerAll(childPath);
              }
              /*
               * Our custom Mac service sends subdirectory changes but the Windows/Linux do not.
               * Walk the file tree to make sure we send create events for any files that were created.
               */
              if (!isMac) {
                PathUtils.recursiveVisitFiles(
                    childPath,
                    dir -> notifyCreateEvent(dir, count),
                    file -> notifyCreateEvent(file, count));
              }
            }
            notifyCreateEvent(childPath, count);
          } else if (kind == ENTRY_MODIFY) {
            if (fileHasher != null || Files.isDirectory(childPath)) {
              /*
               * Note that existingHash may be null due to the file being created before we start listening
               * It's important we don't discard the event in this case
               */
              HashCode existingHash = pathHashes.get(childPath);

              /*
               * newHash can be null when using File#delete() on windows - it generates MODIFY and DELETE in succession.
               * In this case the MODIFY event can be safely ignored
               */
              HashCode newHash = PathUtils.hash(fileHasher, childPath);

              if (newHash != null && !newHash.equals(existingHash)) {
                pathHashes.put(childPath, newHash);
                listener.onEvent(new DirectoryChangeEvent(EventType.MODIFY, childPath, count));
              } else if (newHash == null) {
                logger.debug(
                    "Failed to hash modified file [{}]. It may have been deleted.", childPath);
              }
            } else {
              listener.onEvent(new DirectoryChangeEvent(EventType.MODIFY, childPath, count));
            }
          } else if (kind == ENTRY_DELETE) {
            // we cannot tell if the deletion was on file or folder because path points nowhere
            // (file/folder was deleted)
            pathHashes.entrySet().removeIf(e -> e.getKey().startsWith(childPath));
            listener.onEvent(new DirectoryChangeEvent(EventType.DELETE, childPath, count));
          }
        } catch (Exception e) {
          logger.debug("DirectoryWatcher got an exception while watching!", e);
          listener.onException(e);
        }
      }
      boolean valid = key.reset();
      if (!valid) {
        logger.debug("WatchKey for [{}] no longer valid; removing.", key.watchable());
        // remove the key from the keyRoots
        keyRoots.remove(key);
        // if there are no more keys left to watch, we can break out
        if (keyRoots.isEmpty()) {
          logger.debug("No more directories left to watch; terminating watcher.");
          break;
        }
      }
    }
  }
public void watch ( ) { for ( ; ; ) { if ( ! listener . isWatching ( ) ) { return ; } // wait for key to be signalled WatchKey key ; try { key = watchService . take ( ) ; } catch ( InterruptedException x ) { return ; } for ( WatchEvent < ? > event : key . pollEvents ( ) ) { try { WatchEvent . Kind < ? > kind = event . kind ( ) ; // Context for directory entry event is the file name of entry WatchEvent < Path > ev = PathUtils . cast ( event ) ; int count = ev . count ( ) ; Path eventPath = ev . context ( ) ; if ( ! keyRoots . containsKey ( key ) ) { throw new IllegalStateException ( "WatchService returned key [" + key + "] but it was not found in keyRoots!" ) ; } Path childPath = eventPath == null ? null : keyRoots . get ( key ) . resolve ( eventPath ) ; logger . debug ( "{} [{}]" , kind , childPath ) ; /*
           * If a directory is created, and we're watching recursively, then register it and its sub-directories.
           */ if ( kind == OVERFLOW ) { listener . onEvent ( new DirectoryChangeEvent ( EventType . OVERFLOW , childPath , count ) ) ; } else if ( eventPath == null ) { throw new IllegalStateException ( "WatchService returned a null path for " + kind . name ( ) ) ; } else if ( kind == ENTRY_CREATE ) { if ( Files . isDirectory ( childPath , NOFOLLOW_LINKS ) ) { if ( ! Boolean . TRUE . equals ( fileTreeSupported ) ) { registerAll ( childPath ) ; } /*
               * Our custom Mac service sends subdirectory changes but the Windows/Linux do not.
               * Walk the file tree to make sure we send create events for any files that were created.
               */ if ( ! isMac ) { PathUtils . recursiveVisitFiles ( childPath , dir -> notifyCreateEvent ( dir , count ) , file -> notifyCreateEvent ( file , count ) ) ; } } notifyCreateEvent ( childPath , count ) ; } else if ( kind == ENTRY_MODIFY ) { if ( fileHasher != null || Files . isDirectory ( childPath ) ) { /*
               * Note that existingHash may be null due to the file being created before we start listening
               * It's important we don't discard the event in this case
               */ HashCode existingHash = pathHashes . get ( childPath ) ; /*
               * newHash can be null when using File#delete() on windows - it generates MODIFY and DELETE in succession.
               * In this case the MODIFY event can be safely ignored
               */ HashCode newHash = PathUtils . hash ( fileHasher , childPath ) ; if ( newHash != null && ! newHash . equals ( existingHash ) ) { pathHashes . put ( childPath , newHash ) ; listener . onEvent ( new DirectoryChangeEvent ( EventType . MODIFY , childPath , count ) ) ; } else if ( newHash == null ) { logger . debug ( "Failed to hash modified file [{}]. It may have been deleted." , childPath ) ; } } else { listener . onEvent ( new DirectoryChangeEvent ( EventType . MODIFY , childPath , count ) ) ; } } else if ( kind == ENTRY_DELETE ) { // we cannot tell if the deletion was on file or folder because path points nowhere // (file/folder was deleted) pathHashes . entrySet ( ) . removeIf ( e -> e . getKey ( ) . startsWith ( childPath ) ) ; listener . onEvent ( new DirectoryChangeEvent ( EventType . DELETE , childPath , count ) ) ; } } catch ( Exception e ) { logger . debug ( "DirectoryWatcher got an exception while watching!" , e ) ; listener . onException ( e ) ; } } boolean valid = key . reset ( ) ; if ( ! valid ) { logger . debug ( "WatchKey for [{}] no longer valid; removing." , key . watchable ( ) ) ; // remove the key from the keyRoots keyRoots . remove ( key ) ; // if there are no more keys left to watch, we can break out if ( keyRoots . isEmpty ( ) ) { logger . debug ( "No more directories left to watch; terminating watcher." ) ; break ; } } } }
Watch the directories. Block until either the listener stops watching or the DirectoryWatcher
is closed.
Watch the directories . Block until either the listener stops watching or the DirectoryWatcher is closed .