use of java.nio.file.WatchKey in project hutool by looly.
the class WatchServer method watch.
/**
* 执行事件获取并处理
*
* @param action 监听回调函数,实现此函数接口用于处理WatchEvent事件
* @param watchFilter 监听过滤接口,通过实现此接口过滤掉不需要监听的情况,null表示不过滤
* @since 5.4.0
*/
public void watch(WatchAction action, Filter<WatchEvent<?>> watchFilter) {
WatchKey wk;
try {
wk = watchService.take();
} catch (InterruptedException | ClosedWatchServiceException e) {
// 用户中断
close();
return;
}
final Path currentPath = watchKeyPathMap.get(wk);
for (WatchEvent<?> event : wk.pollEvents()) {
// 如果监听文件,检查当前事件是否与所监听文件关联
if (null != watchFilter && false == watchFilter.accept(event)) {
continue;
}
action.doAction(event, currentPath);
}
wk.reset();
}
use of java.nio.file.WatchKey in project hutool by looly.
the class WatchServer method registerPath.
/**
* 将指定路径加入到监听中
*
* @param path 路径
* @param maxDepth 递归下层目录的最大深度
*/
public void registerPath(Path path, int maxDepth) {
final WatchEvent.Kind<?>[] kinds = ArrayUtil.defaultIfEmpty(this.events, WatchKind.ALL);
try {
final WatchKey key;
if (ArrayUtil.isEmpty(this.modifiers)) {
key = path.register(this.watchService, kinds);
} else {
key = path.register(this.watchService, kinds, this.modifiers);
}
watchKeyPathMap.put(key, path);
// 递归注册下一层层级的目录
if (maxDepth > 1) {
// 遍历所有子目录并加入监听
Files.walkFileTree(path, EnumSet.noneOf(FileVisitOption.class), maxDepth, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
// 继续添加目录
registerPath(dir, 0);
return super.postVisitDirectory(dir, exc);
}
});
}
} catch (IOException e) {
if (false == (e instanceof AccessDeniedException)) {
throw new WatchException(e);
}
// 对于禁止访问的目录,跳过监听
}
}
use of java.nio.file.WatchKey in project gradle by gradle.
the class WatchServiceRegistrar method watchDir.
protected void watchDir(Path dir) throws IOException {
LOG.debug("Registering watch for {}", dir);
if (Thread.currentThread().isInterrupted()) {
LOG.debug("Skipping adding watch since current thread is interrupted.");
}
// on Windows, check if any parent is already watched
for (Path path = dir; path != null; path = FILE_TREE_WATCHING_SUPPORTED ? path.getParent() : null) {
WatchKey previousWatchKey = watchKeys.get(path);
if (previousWatchKey != null && previousWatchKey.isValid()) {
LOG.debug("Directory {} is already watched and the watch is valid, not adding another one.", path);
return;
}
}
int retryCount = 0;
IOException lastException = null;
while (retryCount++ < 2) {
try {
WatchKey watchKey = dir.register(watchService, WATCH_KINDS, WATCH_MODIFIERS);
watchKeys.put(dir, watchKey);
return;
} catch (IOException e) {
LOG.debug("Exception in registering for watching of " + dir, e);
lastException = e;
if (e instanceof NoSuchFileException) {
LOG.debug("Return silently since directory doesn't exist.");
return;
}
if (e instanceof FileSystemException && e.getMessage() != null && e.getMessage().contains("Bad file descriptor")) {
// retry after getting "Bad file descriptor" exception
LOG.debug("Retrying after 'Bad file descriptor'");
continue;
}
// So, we just ignore the exception if the dir doesn't exist anymore
if (!Files.exists(dir)) {
// return silently when directory doesn't exist
LOG.debug("Return silently since directory doesn't exist.");
return;
} else {
// no retry
throw e;
}
}
}
LOG.debug("Retry count exceeded, throwing last exception");
throw lastException;
}
use of java.nio.file.WatchKey in project cas by apereo.
the class ServiceRegistryConfigWatcher method run.
@Override
public void run() {
if (this.running.compareAndSet(false, true)) {
while (this.running.get()) {
// wait for key to be signaled
WatchKey key = null;
try {
key = this.watcher.take();
handleEvent(key);
} catch (final InterruptedException e) {
return;
} finally {
/*
Reset the key -- this step is critical to receive
further watch events. If the key is no longer valid, the directory
is inaccessible so exit the loop.
*/
final boolean valid = key != null && key.reset();
if (!valid) {
LOGGER.warn("Directory key is no longer valid. Quitting watcher service");
}
}
}
}
}
use of java.nio.file.WatchKey in project bazel by bazelbuild.
the class WatchServiceDiffAwareness method collectChanges.
/** Returns the changed files caught by the watch service. */
private Set<Path> collectChanges() throws BrokenDiffAwarenessException, IOException {
Set<Path> createdFilesAndDirectories = new HashSet<>();
Set<Path> deletedOrModifiedFilesAndDirectories = new HashSet<>();
Set<Path> deletedTrackedDirectories = new HashSet<>();
WatchKey watchKey;
while ((watchKey = watchService.poll()) != null) {
Path dir = watchKeyToDirBiMap.get(watchKey);
Preconditions.checkArgument(dir != null);
// construct the diff of this directory since the last #collectChanges call.
for (WatchEvent<?> event : watchKey.pollEvents()) {
Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
// gently.
throw new BrokenDiffAwarenessException("Overflow when watching local filesystem for " + "changes");
}
if (event.context() == null) {
// detail here.
throw new BrokenDiffAwarenessException("Insufficient information from local file system " + "watcher");
}
// For the events we've registered, the context given is a relative path.
Path relativePath = (Path) event.context();
Path path = dir.resolve(relativePath);
Preconditions.checkState(path.isAbsolute(), path);
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
createdFilesAndDirectories.add(path);
deletedOrModifiedFilesAndDirectories.remove(path);
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
createdFilesAndDirectories.remove(path);
deletedOrModifiedFilesAndDirectories.add(path);
WatchKey deletedDirectoryKey = watchKeyToDirBiMap.inverse().get(path);
if (deletedDirectoryKey != null) {
// If the deleted directory has children, then there will also be events for the
// WatchKey of the directory itself. WatchService#poll doesn't specify the order in
// which WatchKeys are returned, so the key for the directory itself may be processed
// *after* the current key (the parent of the deleted directory), and so we don't want
// to remove the deleted directory from our bimap just yet.
//
// For example, suppose we have the file '/root/a/foo.txt' and are watching the
// directories '/root' and '/root/a'. If the directory '/root/a' gets deleted then the
// following is a valid sequence of events by key.
//
// WatchKey '/root/'
// WatchEvent EVENT_MODIFY 'a'
// WatchEvent EVENT_DELETE 'a'
// WatchKey '/root/a'
// WatchEvent EVENT_DELETE 'foo.txt'
deletedTrackedDirectories.add(path);
// Since inotify uses inodes under the covers we cancel our registration on this key to
// avoid getting WatchEvents from a new directory that happens to have the same inode.
deletedDirectoryKey.cancel();
}
} else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
// created.
if (!createdFilesAndDirectories.contains(path)) {
deletedOrModifiedFilesAndDirectories.add(path);
}
}
}
if (!watchKey.reset()) {
// Watcher got deleted, directory no longer valid.
watchKeyToDirBiMap.remove(watchKey);
}
}
for (Path path : deletedTrackedDirectories) {
WatchKey staleKey = watchKeyToDirBiMap.inverse().get(path);
watchKeyToDirBiMap.remove(staleKey);
}
if (watchKeyToDirBiMap.isEmpty()) {
// No more directories to watch, something happened the root directory being watched.
throw new IOException("Root directory " + watchRootPath + " became inaccessible.");
}
Set<Path> changedPaths = new HashSet<>();
for (Path path : createdFilesAndDirectories) {
if (Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) {
// This is a new directory, so changes to it since its creation have not been watched.
// We manually traverse the directory tree to register all the new subdirectories and find
// all the new subdirectories and files.
changedPaths.addAll(registerSubDirectoriesAndReturnContents(path));
} else {
changedPaths.add(path);
}
}
changedPaths.addAll(deletedOrModifiedFilesAndDirectories);
return changedPaths;
}
Aggregations