gnodet-bot commented on code in PR #26653:
URL: https://github.com/apache/camel/pull/26653#discussion_r4059929509


##########
core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java:
##########
@@ -225,13 +231,62 @@ private void registerRecursive(final WatchService 
watcher, final Path root, fina
         Files.walkFileTree(root, new SimpleFileVisitor<>() {
             @Override
             public FileVisitResult preVisitDirectory(Path dir, 
BasicFileAttributes attrs) throws IOException {
+                if (isCompileWorkDir(dir)) {
+                    return FileVisitResult.SKIP_SUBTREE;
+                }
                 WatchKey key = registerPathToWatcher(modifier, dir, watcher);
                 folderKeys.put(key, dir);
                 return FileVisitResult.CONTINUE;
             }
         });
     }
 
+    /**
+     * Registers a directory created while watching recursively, and its 
subdirectories, and collects the files already
+     * in them as changes: a tree such as src/main/java/com/acme is usually 
created with its first file in it, before
+     * the watcher can see the directory.
+     */
+    private void registerNewDirectory(Path dir, List<File> changed) {
+        try {
+            Files.walkFileTree(dir, new SimpleFileVisitor<>() {
+                @Override
+                public FileVisitResult preVisitDirectory(Path d, 
BasicFileAttributes attrs) throws IOException {
+                    if (isCompileWorkDir(d) || folderKeys.containsValue(d)) {
+                        return FileVisitResult.SKIP_SUBTREE;
+                    }
+                    WatchKey k = registerPathToWatcher(watchModifier, d, 
watcher);
+                    folderKeys.put(k, d);
+                    LOG.debug("Watching new directory: {}", d);
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult visitFile(Path f, BasicFileAttributes 
attrs) {
+                    changed.add(f.toFile());
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        } catch (IOException e) {
+            LOG.warn("Cannot watch new directory: {} due to: {}. This 
exception is ignored.", dir, e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Whether the directory is the compile work directory (or inside it): the 
class files the runtime writes there when
+     * it compiles a Java source are not changes to watch, and would otherwise 
trigger a reload of their own, which
+     * compiles again, which writes again (CAMEL-24862).
+     */
+    protected boolean isCompileWorkDir(Path dir) {
+        CompileStrategy cs = getCamelContext() != null
+                ? 
getCamelContext().getCamelContextExtension().getContextPlugin(CompileStrategy.class)
 : null;
+        String workDir = cs != null ? cs.getWorkDir() : null;
+        if (workDir == null) {
+            return false;
+        }
+        Path work = Paths.get(workDir).toAbsolutePath().normalize();

Review Comment:
   ⚠️ **Hot-path repeated work:** `isCompileWorkDir()` is called on every file 
event (and on every directory `ENTRY_CREATE` event). Inside the method, 
`getCamelContext().getCamelContextExtension().getContextPlugin(CompileStrategy.class)`
 is resolved on each call, and 
`Paths.get(workDir).toAbsolutePath().normalize()` constructs a new `Path` 
object every time.
   
   Since the compile work directory is immutable at runtime (set once before 
the watcher starts), this should be resolved once in `doStart()` and stored as 
a nullable field, e.g. `private Path compileWorkDirPath`. The check in 
`isCompileWorkDir()` then becomes a single `startsWith` with no allocation per 
event.



##########
core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java:
##########
@@ -225,13 +231,62 @@ private void registerRecursive(final WatchService 
watcher, final Path root, fina
         Files.walkFileTree(root, new SimpleFileVisitor<>() {
             @Override
             public FileVisitResult preVisitDirectory(Path dir, 
BasicFileAttributes attrs) throws IOException {
+                if (isCompileWorkDir(dir)) {
+                    return FileVisitResult.SKIP_SUBTREE;
+                }
                 WatchKey key = registerPathToWatcher(modifier, dir, watcher);
                 folderKeys.put(key, dir);
                 return FileVisitResult.CONTINUE;
             }
         });
     }
 
+    /**
+     * Registers a directory created while watching recursively, and its 
subdirectories, and collects the files already
+     * in them as changes: a tree such as src/main/java/com/acme is usually 
created with its first file in it, before
+     * the watcher can see the directory.
+     */
+    private void registerNewDirectory(Path dir, List<File> changed) {
+        try {
+            Files.walkFileTree(dir, new SimpleFileVisitor<>() {
+                @Override
+                public FileVisitResult preVisitDirectory(Path d, 
BasicFileAttributes attrs) throws IOException {
+                    if (isCompileWorkDir(d) || folderKeys.containsValue(d)) {
+                        return FileVisitResult.SKIP_SUBTREE;
+                    }
+                    WatchKey k = registerPathToWatcher(watchModifier, d, 
watcher);
+                    folderKeys.put(k, d);
+                    LOG.debug("Watching new directory: {}", d);
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult visitFile(Path f, BasicFileAttributes 
attrs) {
+                    changed.add(f.toFile());
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        } catch (IOException e) {
+            LOG.warn("Cannot watch new directory: {} due to: {}. This 
exception is ignored.", dir, e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Whether the directory is the compile work directory (or inside it): the 
class files the runtime writes there when
+     * it compiles a Java source are not changes to watch, and would otherwise 
trigger a reload of their own, which
+     * compiles again, which writes again (CAMEL-24862).
+     */
+    protected boolean isCompileWorkDir(Path dir) {
+        CompileStrategy cs = getCamelContext() != null
+                ? 
getCamelContext().getCamelContextExtension().getContextPlugin(CompileStrategy.class)
 : null;
+        String workDir = cs != null ? cs.getWorkDir() : null;
+        if (workDir == null) {
+            return false;
+        }
+        Path work = Paths.get(workDir).toAbsolutePath().normalize();

Review Comment:
   🔧 **Style:** `Paths.get()` is the legacy NIO API (deprecated in spirit since 
Java 11). Use `Path.of()` instead — no extra import needed.
   
   ```suggestion
           Path work = Path.of(workDir).toAbsolutePath().normalize();
   ```



##########
core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java:
##########
@@ -225,13 +231,62 @@ private void registerRecursive(final WatchService 
watcher, final Path root, fina
         Files.walkFileTree(root, new SimpleFileVisitor<>() {
             @Override
             public FileVisitResult preVisitDirectory(Path dir, 
BasicFileAttributes attrs) throws IOException {
+                if (isCompileWorkDir(dir)) {
+                    return FileVisitResult.SKIP_SUBTREE;
+                }
                 WatchKey key = registerPathToWatcher(modifier, dir, watcher);
                 folderKeys.put(key, dir);
                 return FileVisitResult.CONTINUE;
             }
         });
     }
 
+    /**
+     * Registers a directory created while watching recursively, and its 
subdirectories, and collects the files already
+     * in them as changes: a tree such as src/main/java/com/acme is usually 
created with its first file in it, before
+     * the watcher can see the directory.
+     */
+    private void registerNewDirectory(Path dir, List<File> changed) {
+        try {
+            Files.walkFileTree(dir, new SimpleFileVisitor<>() {
+                @Override
+                public FileVisitResult preVisitDirectory(Path d, 
BasicFileAttributes attrs) throws IOException {
+                    if (isCompileWorkDir(d) || folderKeys.containsValue(d)) {

Review Comment:
   🔍 **O(n) lookup:** `folderKeys.containsValue(d)` is a linear scan across all 
registered directories. For deep watched trees this runs once per node during 
`registerNewDirectory`'s recursive walk. An inverse `Set<Path>` (or a second 
`Map<Path, WatchKey>`) would reduce this to O(1). Low severity since directory 
creation events are rare, but worth addressing if the watcher is used on large 
source trees.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to