private void notifyListeners(File file) { // listeners is a synchronized list - no need to sync here for (FileWatcherListener listener : listeners) { try { listener.fileChanged(file); } catch (Exception e) { logger.info( "Discarding exception " + e.getLocalizedMessage() + " thrown by FileWatcherListener"); } } }
public void run() { // now that thread is running, check that directory exists // doing this test here allows it to be created subsequent to the file watcher construction if (!dir.exists()) { throw new RuntimeException("FileWatcher directory path does not exist[" + dir + "]"); } for (FileWatcherListener listener : listeners) { listener.startedWatching(dir); } // record time we started polling long startPollTime = System.currentTimeMillis(); for (; ; ) { logger.debug("starting directory poll {}", dir); // has an external thread requested that this one be stopped? if (stopHasBeenRequested()) { logger.info("stopping file watcher thread"); break; } // scan directory for files or directories we are interested in File[] files = dir.listFiles( new FileFilter() { public boolean accept(File file) { boolean isDir = file.isDirectory(); if (watchDirs != isDir) return false; return file.getName().matches(nameRegexp); } }); // find directory entries that have been changed since previous poll // note: given that even the retrieval of the last modified time can consume time // (let alone any actions in the notifications), it is not safe to just compare the // current last modified time of each file against a single time for the end of the // previous poll - instead we maintain a record of the previous modification time // for any file which has been modified during the lifetime of this poller // then compare the current last modified time against that for (File file : files) { logger.debug("found " + file.getName()); // find previous known last modified time for file Long prevModifiedTime = prevModifiedTimeByFile.get(file); if (prevModifiedTime == null) { // we do not know about this file - this means that it had not previously // been modified since we started polling so use start of polling as its // previous modification time prevModifiedTimeByFile.put(file, prevModifiedTime = startPollTime); logger.debug("no previous modification time for file {}", file); } else if ((System.currentTimeMillis() - prevModifiedTime) > MAX_TIME_SINCE_LAST_MODIFIED) { // the last time this file was modified since we started up this poller // was over (default) a day ago - we can't possibly get confused over a // modification time that long ago so get rid of file from cache prevModifiedTimeByFile.remove(file); logger.debug("cache entry expired, ignoring file {}", file); continue; } logger.debug("prevModifiedTime={} for file {}", prevModifiedTime, file); long lastModifiedTime = file.lastModified(); logger.debug("lastModifiedTime={} for file {}", lastModifiedTime, file); if (lastModifiedTime > prevModifiedTime) { notifyFileChange(file); prevModifiedTimeByFile.put(file, lastModifiedTime); } } try { Thread.sleep(pollingIntervalMillis); } catch (InterruptedException exp) { } } }