/** Check that a cancelled key will never be queued */ static void testCancel(Path dir) throws IOException { System.out.println("-- Cancel --"); try (WatchService watcher = FileSystems.getDefault().newWatchService()) { System.out.format("register %s for events\n", dir); WatchKey myKey = dir.register(watcher, new WatchEvent.Kind<?>[] {ENTRY_CREATE}); checkKey(myKey, dir); System.out.println("cancel key"); myKey.cancel(); // create a file in the directory Path file = dir.resolve("mars"); System.out.format("create: %s\n", file); Files.createFile(file); // poll for keys - there will be none System.out.println("poll..."); try { WatchKey key = watcher.poll(3000, TimeUnit.MILLISECONDS); if (key != null) throw new RuntimeException("key should not be queued"); } catch (InterruptedException x) { throw new RuntimeException(x); } // done Files.delete(file); System.out.println("OKAY"); } }
public synchronized void unwatchPath(File file, final FileChangeCallback callback) { PathData data = files.get(file); if (data != null) { data.callbacks.remove(callback); if (data.callbacks.isEmpty()) { files.remove(file); for (WatchKey key : data.keys) { key.cancel(); pathDataByKey.remove(key); } } } }
private void rescan() throws IOException { try { synchronized (processing) { while (processing.get() > 0) { processing.wait(); } } for (WatchKey key : keys.keySet()) { key.cancel(); } keys.clear(); Files.walkFileTree(root, new FilteringFileVisitor()); synchronized (processing) { while (processing.get() > 0) { processing.wait(); } } } catch (InterruptedException e) { throw (IOException) new InterruptedIOException().initCause(e); } }
public void downloadFile(String relPath) { VOSync.debug("Downloading file from storage: " + relPath); Path filePath = FileSystems.getDefault().getPath(startDir.toString(), relPath.substring(1)); try { WatchKey key = filePath.getParent().register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.remove(key); key.cancel(); FileOutputStream outp = new FileOutputStream(filePath.toFile()); DropboxFileInfo info = api.getFile(relPath, null, outp, null); outp.close(); key = filePath.getParent().register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.put(key, filePath.getParent()); MetaHandler.setFile(relPath, filePath.toFile(), info.getMetadata().rev); } catch (IOException ex) { logger.error("Error downloading file " + relPath + ": " + ex.getMessage()); } catch (DropboxException ex) { ex.printStackTrace(); logger.error("Error downloading file " + relPath + ": " + ex.getMessage()); } }
/** * @param path Path to monitor. * @param fileEncoding Encoding for reading the file * @param listener Handler for detected events. * @throws IOException Errors other than {@link NoSuchFileException}. */ public void watch(Path path, Charset fileEncoding, FileModificationListener listener) throws IOException { // Read file from beginning. fileEndPosition = 0; watching = true; WatchService ws; if (!Files.exists(path)) { listener.noSuchFile(path); } try { ws = path.getFileSystem().newWatchService(); logger.debug("Using Java WatchService."); } catch (UnsupportedOperationException e) { logger.debug("Falling back to polling."); // File system does not support watching. polling(path, fileEncoding, listener); // Polling is infinite. return; } // Watching is likely supported. Kind<?>[] kinds = { StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY }; while (watching) { // Acquire a watch as close to the monitored file as possible. Path closestExisting = getClosestWatchable(path); Path watchToDesiredWatch = closestExisting.relativize(path.getParent()); boolean watchingDesired = closestExisting.equals(path.getParent()); WatchKey key = null; try { logger.debug("Start watching " + closestExisting); key = closestExisting.register(ws, kinds); } catch (Exception e) { logger.error("Failed to register watch on " + closestExisting, e); } if (key == null) { throw new NotWatchableException(); } if (Files.exists(path)) { // Process new files (either newly created or available due to // parent folder moves). examineFile(path, fileEncoding, listener); } awaitKeys: while (watching) { WatchKey res = null; try { // Await the presence of new events on the watched folder. res = ws.take(); for (WatchEvent<?> candidate : res.pollEvents()) { // Skip over unknown events. if (candidate.kind() == StandardWatchEventKinds.OVERFLOW) { logger.debug("Java lost events, checking for additions to monitored file."); // Java lost events. Make sure to process existing // file to avoid missing additions. if (Files.exists(path)) { examineFile(path, fileEncoding, listener); } continue; } @SuppressWarnings("unchecked") WatchEvent<Path> event = (WatchEvent<Path>) candidate; if (watchingDesired) { // Already watching desired folder, see if monitored // files is affected. if (event.context().getName(0).equals(path.getFileName())) { // Something happened to the monitored file. if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE || event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { logger.debug(path + " was created or modified."); // Read the file's content and notify // listener. examineFile(path, fileEncoding, listener); } else if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) { logger.debug(path + " was deleted."); listener.noSuchFile(path); } } } else { // Not yet watching desired folder. if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { if (event.context().getName(0).equals(watchToDesiredWatch.getName(0))) { logger.debug("More specific path to monitor available."); // Path towards monitored file created, // dispose current watch and try to get a // closer watch. res.cancel(); res = null; break awaitKeys; } } } } } catch (InterruptedException e) { logger.error("Interrupted waiting for watch event.", e); break; } finally { if (res != null && res.reset() == false) { logger.debug("Aborting watch on " + closestExisting + " as it is no longer watchable."); break; } } } } }