/** * Add {@link PathAlterationObserverScheduler}s for the given * root directory and any nested subdirectories under the root directory to the given * {@link PathAlterationObserverScheduler}. * * @param monitor a {@link PathAlterationObserverScheduler} * @param listener a {@link org.apache.gobblin.util.filesystem.PathAlterationListener} * @param rootDirPath root directory */ public static void addPathAlterationObserver(PathAlterationObserverScheduler monitor, PathAlterationListener listener, Path rootDirPath) throws IOException { PathAlterationObserver observer = new PathAlterationObserver(rootDirPath); observer.addListener(listener); monitor.addObserver(observer); }
for (final FileStatusEntry previousEntry : previous) { while (c < currentPaths.length && comparator.compare(previousEntry.getPath(), currentPaths[c]) > 0) { current[c] = createPathEntry(parent, currentPaths[c]); doCreate(current[c]); c++; doMatch(previousEntry, currentPaths[c]); checkAndNotify(previousEntry, previousEntry.getChildren(), listPaths(currentPaths[c])); current[c] = previousEntry; c++; } else { checkAndNotify(previousEntry, previousEntry.getChildren(), EMPTY_PATH_ARRAY); doDelete(previousEntry); current[c] = createPathEntry(parent, currentPaths[c]); doCreate(current[c]);
/** * Start monitoring. * @throws IOException if an error occurs initializing the observer */ public synchronized void start() throws IOException { if (running) { throw new IllegalStateException("Monitor is already running"); } for (final PathAlterationObserver observer : observers) { observer.initialize(); } if (interval > 0) { running = true; this.executionResult = executor.scheduleWithFixedDelay(this, initialDelay, interval, TimeUnit.MILLISECONDS); } else { LOGGER.info("Not starting due to non-positive scheduling interval:" + interval); } }
/** * List the path in the format of FileStatusEntry array * @param path The path to list files for * @param entry the parent entry * @return The child files */ private FileStatusEntry[] doListPathsEntry(Path path, FileStatusEntry entry) throws IOException { final Path[] paths = listPaths(path); final FileStatusEntry[] children = paths.length > 0 ? new FileStatusEntry[paths.length] : FileStatusEntry.EMPTY_ENTRIES; for (int i = 0; i < paths.length; i++) { children[i] = createPathEntry(entry, paths[i]); } return children; }
PathAlterationObserver observer = new PathAlterationObserver(this.jobConfigDirPath); observer.initialize(); observer.checkAndNotify(); Assert.assertTrue(specs.containsKey(js1_1.getUri())); JobSpec js1_1_notified = specs.get(js1_1.getUri()); observer.checkAndNotify(); Assert.assertTrue(specs.containsKey(js1_2.getUri())); JobSpec js1_2_notified = specs.get(js1_2.getUri()); observer.checkAndNotify(); Assert.assertTrue(specs.containsKey(js2.getUri())); JobSpec js2_notified = specs.get(js2.getUri()); observer.checkAndNotify(); Assert.assertFalse(specs.containsKey(js2.getUri())); observer.checkAndNotify(); Assert.assertTrue(specs.containsKey(js3.getUri())); JobSpec js3_notified = specs.get(js3.getUri());
/** * Check whether the file and its chlidren have been created, modified or deleted. */ public void checkAndNotify() throws IOException { /* fire onStart() */ for (final PathAlterationListener listener : listeners.values()) { listener.onStart(this); } /* fire directory/file events */ final Path rootPath = rootEntry.getPath(); if (fs.exists(rootPath)) { // Current existed. checkAndNotify(rootEntry, rootEntry.getChildren(), listPaths(rootPath)); } else if (rootEntry.isExists()) { // Existed before and not existed now. checkAndNotify(rootEntry, rootEntry.getChildren(), EMPTY_PATH_ARRAY); } else { // Didn't exist and still doesn't } /* fire onStop() */ for (final PathAlterationListener listener : listeners.values()) { listener.onStop(this); } }
@Override public void run() { if (!running) { return; } for (final PathAlterationObserver observer : observers) { try { observer.checkAndNotify(); } catch (IOException ioe) { LOGGER.error("Path alteration detector error.", ioe); } } }
/** * Create a new FileStatusEntry for the specified file. * * @param parent The parent file entry * @param childPath The file to create an entry for * @return A new file entry */ private FileStatusEntry createPathEntry(final FileStatusEntry parent, final Path childPath) throws IOException { final FileStatusEntry entry = parent.newChildInstance(childPath); entry.refresh(childPath); final FileStatusEntry[] children = doListPathsEntry(childPath, entry); entry.setChildren(children); return entry; }
/** * Fire directory/file created events to the registered listeners. * * @param entry The file entry */ private void doCreate(final FileStatusEntry entry) { for (final PathAlterationListener listener : listeners.values()) { if (entry.isDirectory()) { listener.onDirectoryCreate(entry.getPath()); } else { listener.onFileCreate(entry.getPath()); } } final FileStatusEntry[] children = entry.getChildren(); for (final FileStatusEntry aChildren : children) { doCreate(aChildren); } }
/** * Stop monitoring * * @param stopInterval the amount of time in milliseconds to wait for the thread to finish. * A value of zero will wait until the thread is finished (see {@link Thread#join(long)}). * @throws IOException if an error occurs initializing the observer * @since 2.1 */ public synchronized void stop(final long stopInterval) throws IOException, InterruptedException { if (!running) { LOGGER.warn("Already stopped"); return; } running = false; for (final PathAlterationObserver observer : observers) { observer.destroy(); } executionResult.cancel(true); executor.shutdown(); if (!executor.awaitTermination(stopInterval, TimeUnit.MILLISECONDS)) { throw new RuntimeException("Did not shutdown in the timeout period"); } }
/** * Check whether the file and its chlidren have been created, modified or deleted. */ public void checkAndNotify() throws IOException { /* fire onStart() */ for (final PathAlterationListener listener : listeners.values()) { listener.onStart(this); } /* fire directory/file events */ final Path rootPath = rootEntry.getPath(); if (fs.exists(rootPath)) { // Current existed. checkAndNotify(rootEntry, rootEntry.getChildren(), listPaths(rootPath)); } else if (rootEntry.isExists()) { // Existed before and not existed now. checkAndNotify(rootEntry, rootEntry.getChildren(), EMPTY_PATH_ARRAY); } else { // Didn't exist and still doesn't } /* fire onStop() */ for (final PathAlterationListener listener : listeners.values()) { listener.onStop(this); } }
/** * List the path in the format of FileStatusEntry array * @param path The path to list files for * @param entry the parent entry * @return The child files */ private FileStatusEntry[] doListPathsEntry(Path path, FileStatusEntry entry) throws IOException { final Path[] paths = listPaths(path); final FileStatusEntry[] children = paths.length > 0 ? new FileStatusEntry[paths.length] : FileStatusEntry.EMPTY_ENTRIES; for (int i = 0; i < paths.length; i++) { children[i] = createPathEntry(entry, paths[i]); } return children; }
@Override public void run() { if (!running) { return; } for (final PathAlterationObserver observer : observers) { try { observer.checkAndNotify(); } catch (IOException ioe) { LOGGER.error("Path alteration detector error.", ioe); } } }
/** * Initialize the observer. * @throws IOException if an error occurs */ public void initialize() throws IOException { rootEntry.refresh(rootEntry.getPath()); final FileStatusEntry[] children = doListPathsEntry(rootEntry.getPath(), rootEntry); rootEntry.setChildren(children); }
/** * Fire directory/file created events to the registered listeners. * * @param entry The file entry */ private void doCreate(final FileStatusEntry entry) { for (final PathAlterationListener listener : listeners.values()) { if (entry.isDirectory()) { listener.onDirectoryCreate(entry.getPath()); } else { listener.onFileCreate(entry.getPath()); } } final FileStatusEntry[] children = entry.getChildren(); for (final FileStatusEntry aChildren : children) { doCreate(aChildren); } }
/** * Stop monitoring * * @param stopInterval the amount of time in milliseconds to wait for the thread to finish. * A value of zero will wait until the thread is finished (see {@link Thread#join(long)}). * @throws IOException if an error occurs initializing the observer * @since 2.1 */ public synchronized void stop(final long stopInterval) throws IOException, InterruptedException { if (!running) { LOGGER.warn("Already stopped"); return; } running = false; for (final PathAlterationObserver observer : observers) { observer.destroy(); } executionResult.cancel(true); executor.shutdown(); if (!executor.awaitTermination(stopInterval, TimeUnit.MILLISECONDS)) { throw new RuntimeException("Did not shutdown in the timeout period"); } }
for (final FileStatusEntry previousEntry : previous) { while (c < currentPaths.length && comparator.compare(previousEntry.getPath(), currentPaths[c]) > 0) { current[c] = createPathEntry(parent, currentPaths[c]); doCreate(current[c]); c++; doMatch(previousEntry, currentPaths[c]); checkAndNotify(previousEntry, previousEntry.getChildren(), listPaths(currentPaths[c])); current[c] = previousEntry; c++; } else { checkAndNotify(previousEntry, previousEntry.getChildren(), EMPTY_PATH_ARRAY); doDelete(previousEntry); current[c] = createPathEntry(parent, currentPaths[c]); doCreate(current[c]);
/** * Create and attach {@link PathAlterationObserverScheduler}s for the given * root directory and any nested subdirectories under the root directory to the given * {@link PathAlterationObserverScheduler}. * @param detector a {@link PathAlterationObserverScheduler} * @param listener a {@link org.apache.gobblin.util.filesystem.PathAlterationListener} * @param observerOptional Optional observer object. For testing routine, this has been initialized by user. * But for general usage, the observer object is created inside this method. * @param rootDirPath root directory * @throws IOException */ public void addPathAlterationObserver(PathAlterationListener listener, Optional<PathAlterationObserver> observerOptional, Path rootDirPath) throws IOException { PathAlterationObserver observer = observerOptional.or(new PathAlterationObserver(rootDirPath)); observer.addListener(listener); addObserver(observer); }
/** * Start monitoring. * @throws IOException if an error occurs initializing the observer */ public synchronized void start() throws IOException { if (running) { throw new IllegalStateException("Monitor is already running"); } for (final PathAlterationObserver observer : observers) { observer.initialize(); } if (interval > 0) { running = true; this.executionResult = executor.scheduleWithFixedDelay(this, initialDelay, interval, TimeUnit.MILLISECONDS); } else { LOGGER.info("Not starting due to non-positive scheduling interval:" + interval); } }
/** * Create a new FileStatusEntry for the specified file. * * @param parent The parent file entry * @param childPath The file to create an entry for * @return A new file entry */ private FileStatusEntry createPathEntry(final FileStatusEntry parent, final Path childPath) throws IOException { final FileStatusEntry entry = parent.newChildInstance(childPath); entry.refresh(childPath); final FileStatusEntry[] children = doListPathsEntry(childPath, entry); entry.setChildren(children); return entry; }