/** * Method to call on service activation */ public void activate() { Path pathToWatch = getSourcePath(); if (pathToWatch != null) { watchQueueReader = WatchQueueReader.getInstance(); watchQueueReader.customizeWatchQueueReader(this, pathToWatch, watchSubDirectories()); } }
public boolean apply(ReadyMarker readyMarker) { return isTracked(type, readyMarker.getType()) && isTracked(identifier, readyMarker.getIdentifier()); }
/** * Method to call on service deactivation */ public void deactivate() { WatchQueueReader watchQueueReader = this.watchQueueReader; if (watchQueueReader != null) { watchQueueReader.stopWatchService(this); } this.watchQueueReader = null; }
synchronized (futures) { logger.trace("Modification event for {} ", resolvedPath); ScheduledFuture<?> previousFuture = removeScheduledJob(key, resolvedPath); if (previousFuture != null) { previousFuture.cancel(true); ScheduledFuture<?> res = removeScheduledJob(key, resolvedPath); if (res != null) { logger.trace("Job removed itself for {}", resolvedPath); logger.trace("Job couldn't find itself for {}", resolvedPath); if (checkAndTrackContent(service, resolvedPath)) { service.processWatchEvent(event, event.kind(), resolvedPath); } else { logger.trace("File content '{}' has not changed, skipping modification event", resolvedPath); rememberScheduledJob(key, resolvedPath, future);
@Override public String toString() { return getType() + "=" + getIdentifier(); }
/** * Customize the queue reader to process the watch events for the given directory, provided by the watch service * * @param watchService the watch service, requesting the watch events for the watched directory * @param toWatch the directory being watched by the watch service * @param watchSubDirectories a boolean flag that specifies if the child directories of the registered directory * will being watched by the watch service */ protected void customizeWatchQueueReader(AbstractWatchService watchService, Path toWatch, boolean watchSubDirectories) { try { if (watchSubDirectories) { // walk through all folders and follow symlinks registerWithSubDirectories(watchService, toWatch); } else { registerDirectoryInternal(watchService, watchService.getWatchEventKinds(toWatch), toWatch); } } catch (NoSuchFileException e) { logger.debug("Not watching folder '{}' as it does not exist.", toWatch); } catch (IOException e) { logger.warn("Cannot customize folder watcher for folder '{}'", toWatch, e); } }
/** * Returns a {@link ReadyMarkerFilter} restricted to the given type. * * @param type * @return */ public ReadyMarkerFilter withType(@Nullable String type) { return new ReadyMarkerFilter(type, identifier); }
private Path resolvePath(WatchKey key, WatchEvent<?> event) { WatchEvent<Path> ev = cast(event); // Context for directory entry event is the file name of entry. Path contextPath = ev.context(); Path baseWatchedDir = null; Path registeredPath = null; synchronized (this) { baseWatchedDir = keyToService.get(key).getSourcePath(); registeredPath = registeredKeys.get(key); } if (registeredPath != null) { // If the path has been registered in the watch service it relative path can be resolved // The context path is resolved by its already registered parent path return registeredPath.resolve(contextPath); } logger.warn( "Detected invalid WatchEvent '{}' and key '{}' for entry '{}' in not registered file or directory of '{}'", event, key, contextPath, baseWatchedDir); return null; }
private void rememberScheduledJob(WatchKey key, Path resolvedPath, ScheduledFuture<?> future) { Map<Path, @Nullable ScheduledFuture<?>> keyFutures = getKeyFutures(key); keyFutures.put(resolvedPath, future); }
private void notifyTracker(ReadyTracker readyTracker, Consumer<ReadyMarker> action) { ReadyMarkerFilter f = trackers.get(readyTracker); markers.stream().filter(marker -> f.apply(marker)).forEach(action); }
@Override public void unregisterTracker(ReadyTracker readyTracker) { rwlTrackers.writeLock().lock(); try { if (trackers.containsKey(readyTracker)) { notifyTracker(readyTracker, marker -> readyTracker.onReadyMarkerRemoved(marker)); } trackers.remove(readyTracker); } finally { rwlTrackers.writeLock().unlock(); } }
@Override public void markReady(ReadyMarker readyMarker) { rwlTrackers.readLock().lock(); try { boolean isNew = markers.add(readyMarker); if (isNew) { notifyTrackers(readyMarker, tracker -> tracker.onReadyMarkerAdded(readyMarker)); logger.trace("Added ready marker {}", readyMarker); } } finally { rwlTrackers.readLock().unlock(); } }
@Override public FileVisitResult preVisitDirectory(Path subDir, BasicFileAttributes attrs) throws IOException { Kind<?>[] kinds = watchService.getWatchEventKinds(subDir); if (kinds != null) { registerDirectoryInternal(watchService, kinds, subDir); } return FileVisitResult.CONTINUE; }
@Override public @Nullable StateDescription getStateDescription(@Nullable Locale locale) { if (stateDescriptionService != null) { return stateDescriptionService.getStateDescription(this.name, locale); } return null; }
/** * Calculate a checksum of the given file and report back whether it has changed since the last time. * * @param service the service determining the scope * @param resolvedPath the file path * @return {@code true} if the file content has changed since the last call to this method */ private boolean checkAndTrackContent(AbstractWatchService service, Path resolvedPath) { byte[] newHash = hash(resolvedPath); if (newHash == null) { return true; } Map<Path, byte[]> keyHashes = hashes.get(service); if (keyHashes == null) { keyHashes = new HashMap<>(); hashes.put(service, keyHashes); } byte[] oldHash = keyHashes.put(resolvedPath, newHash); return oldHash == null || !Arrays.equals(oldHash, newHash); }
/** * Returns a {@link ReadyMarkerFilter} restricted to the given identifier. * * @param type * @return */ public ReadyMarkerFilter withIdentifier(@Nullable String identifier) { return new ReadyMarkerFilter(type, identifier); }
private ScheduledFuture<?> removeScheduledJob(WatchKey key, Path resolvedPath) { Map<Path, @Nullable ScheduledFuture<?>> keyFutures = getKeyFutures(key); return keyFutures.remove(resolvedPath); }
private void notifyTrackers(ReadyMarker readyMarker, Consumer<ReadyTracker> action) { trackers.entrySet().stream().filter(entry -> { return entry.getValue().apply(readyMarker); }).map(entry -> { return entry.getKey(); }).forEach(action); }
@Override public void unmarkReady(ReadyMarker readyMarker) { rwlTrackers.readLock().lock(); try { boolean isRemoved = markers.remove(readyMarker); if (isRemoved) { notifyTrackers(readyMarker, tracker -> tracker.onReadyMarkerRemoved(readyMarker)); logger.trace("Removed ready marker {}", readyMarker); } } finally { rwlTrackers.readLock().unlock(); } }
@Override public void registerTracker(ReadyTracker readyTracker, ReadyMarkerFilter filter) { rwlTrackers.writeLock().lock(); try { if (!trackers.containsKey(readyTracker)) { trackers.put(readyTracker, filter); notifyTracker(readyTracker, marker -> readyTracker.onReadyMarkerAdded(marker)); } } catch (RuntimeException e) { logger.error("Registering tracker '" + readyTracker + "' failed!", e); } finally { rwlTrackers.writeLock().unlock(); } }