This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 0b73e4cffcdb (chores): fix SonarCloud S2276, S128, S3014 blocker
issues (#24488)
0b73e4cffcdb is described below
commit 0b73e4cffcdb32291dc98a159fe2b6f3021251e3
Author: Guillaume Nodet <[email protected]>
AuthorDate: Tue Jul 7 22:56:21 2026 +0200
(chores): fix SonarCloud S2276, S128, S3014 blocker issues (#24488)
(chores): fix SonarCloud S2276, S128, S3014 blocker issues
- S2276: Replace Thread.sleep() with wait() on a private monitor in
synchronized methods in JfrMemoryLeakDevConsole. Uses Camel StopWatch
(monotonic) for the deadline and guards against spurious wakeups.
- S128: Add missing break in switch case in XmlRoutesBuilderLoader.
- S3014: Refactor IsolatedThreadGroup in RunMojo to use composition
with Thread.UncaughtExceptionHandler instead of extending ThreadGroup.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
.../impl/console/JfrMemoryLeakDevConsole.java | 21 +++++++-
.../camel/dsl/xml/io/XmlRoutesBuilderLoader.java | 1 +
.../main/java/org/apache/camel/maven/RunMojo.java | 56 ++++++++++++++--------
3 files changed, 56 insertions(+), 22 deletions(-)
diff --git
a/core/camel-console/src/main/java/org/apache/camel/impl/console/JfrMemoryLeakDevConsole.java
b/core/camel-console/src/main/java/org/apache/camel/impl/console/JfrMemoryLeakDevConsole.java
index 3815b6cc1b02..ae395ebc6b03 100644
---
a/core/camel-console/src/main/java/org/apache/camel/impl/console/JfrMemoryLeakDevConsole.java
+++
b/core/camel-console/src/main/java/org/apache/camel/impl/console/JfrMemoryLeakDevConsole.java
@@ -40,6 +40,7 @@ import org.apache.camel.spi.Configurer;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.annotations.DevConsole;
import org.apache.camel.support.console.AbstractDevConsole;
+import org.apache.camel.util.StopWatch;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.json.JsonArray;
import org.apache.camel.util.json.JsonObject;
@@ -81,6 +82,10 @@ public class JfrMemoryLeakDevConsole extends
AbstractDevConsole {
private static final int MAX_STACK_FRAMES = 10;
private static final int MAX_CHAIN_DEPTH = 20;
+ // Private monitor for GC wait delays so that wait() does not release the
+ // 'this' monitor of synchronized methods (which guards recording state).
+ private final Object gcWaitMonitor = new Object();
+
private volatile Recording activeRecording;
private volatile JsonObject cachedResults;
private volatile JsonObject previousResults;
@@ -137,7 +142,13 @@ public class JfrMemoryLeakDevConsole extends
AbstractDevConsole {
// trigger GC before starting to establish a cleaner baseline
System.gc();
try {
- Thread.sleep(500);
+ synchronized (gcWaitMonitor) {
+ StopWatch watch = new StopWatch();
+ long remaining;
+ while ((remaining = 500 - watch.taken()) > 0) {
+ gcWaitMonitor.wait(remaining);
+ }
+ }
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
@@ -210,7 +221,13 @@ public class JfrMemoryLeakDevConsole extends
AbstractDevConsole {
// trigger GC before stopping to flush objects into the recording
System.gc();
try {
- Thread.sleep(500);
+ synchronized (gcWaitMonitor) {
+ StopWatch watch = new StopWatch();
+ long remaining;
+ while ((remaining = 500 - watch.taken()) > 0) {
+ gcWaitMonitor.wait(remaining);
+ }
+ }
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
diff --git
a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
index 181aea18d486..163e88b4501c 100644
---
a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
+++
b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
@@ -188,6 +188,7 @@ public class XmlRoutesBuilderLoader extends
RouteBuilderLoaderSupport {
new XmlModelParser(resource,
xmlInfo.getRootElementNamespace())
.parseRouteConfigurationsDefinition()
.ifPresent(this::addConfigurations);
+ break;
}
default: {
// NO-OP
diff --git
a/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RunMojo.java
b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RunMojo.java
index a9337714a207..00bcc5f41e6f 100644
---
a/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RunMojo.java
+++
b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RunMojo.java
@@ -390,7 +390,7 @@ public class RunMojo extends AbstractExecMojo {
"Cannot run Kamelet Main because camel-kamelet-main JAR is
not available on classpath");
}
- final Thread bootstrapThread = new Thread(threadGroup, () -> {
+ final Thread bootstrapThread = threadGroup.newThread(() -> {
try {
beforeBootstrapCamel();
@@ -406,7 +406,7 @@ public class RunMojo extends AbstractExecMojo {
getLog().error("Error occurred while running main from: " +
mainClass);
getLog().error(e);
getLog().error("*************************************");
-
Thread.currentThread().getThreadGroup().uncaughtException(Thread.currentThread(),
e);
+ threadGroup.uncaughtException(Thread.currentThread(), e);
}
}, mainClass + ".main()");
@@ -459,11 +459,13 @@ public class RunMojo extends AbstractExecMojo {
// noop
}
- class IsolatedThreadGroup extends ThreadGroup {
+ @SuppressWarnings("java:S3014") // ThreadGroup is needed internally for
thread containment; no modern alternative in Java 17
+ class IsolatedThreadGroup implements Thread.UncaughtExceptionHandler {
+ private final ThreadGroup threadGroup;
Throwable uncaughtException; // synchronize access to this
IsolatedThreadGroup(String name) {
- super(name);
+ this.threadGroup = new ThreadGroup(name);
}
@Override
@@ -482,13 +484,38 @@ public class RunMojo extends AbstractExecMojo {
getLog().warn("an additional exception was thrown", throwable);
}
}
+
+ Thread newThread(Runnable task, String name) {
+ Thread t = new Thread(threadGroup, task, name);
+ t.setUncaughtExceptionHandler(this);
+ return t;
+ }
+
+ Collection<Thread> getActiveThreads() {
+ Thread[] threads = new Thread[threadGroup.activeCount()];
+ threadGroup.enumerate(threads);
+ Collection<Thread> result = new ArrayList<>(threads.length);
+ for (int i = 0; i < threads.length && threads[i] != null; i++) {
+ result.add(threads[i]);
+ }
+ // note: the result should be modifiable
+ return result;
+ }
+
+ int activeCount() {
+ return threadGroup.activeCount();
+ }
+
+ void enumerate(Thread[] threads) {
+ threadGroup.enumerate(threads);
+ }
}
- private void joinNonDaemonThreads(ThreadGroup threadGroup) {
+ private void joinNonDaemonThreads(IsolatedThreadGroup threadGroup) {
boolean foundNonDaemon;
do {
foundNonDaemon = false;
- Collection<Thread> threads = getActiveThreads(threadGroup);
+ Collection<Thread> threads = threadGroup.getActiveThreads();
for (Thread thread : threads) {
if (thread.isDaemon()) {
continue;
@@ -516,13 +543,13 @@ public class RunMojo extends AbstractExecMojo {
}
}
- private void terminateThreads(ThreadGroup threadGroup) {
+ private void terminateThreads(IsolatedThreadGroup threadGroup) {
StopWatch watch = new StopWatch();
Set<Thread> uncooperativeThreads = new HashSet<>(); // these were not
responsive
// to interruption
- for (Collection<Thread> threads = getActiveThreads(threadGroup);
+ for (Collection<Thread> threads = threadGroup.getActiveThreads();
!threads.isEmpty();
- threads = getActiveThreads(threadGroup), threads
+ threads = threadGroup.getActiveThreads(), threads
.removeAll(uncooperativeThreads)) {
// Interrupt all threads we know about as of this instant (harmless
// if spuriously went dead (! isAlive())
@@ -582,17 +609,6 @@ public class RunMojo extends AbstractExecMojo {
}
}
- private Collection<Thread> getActiveThreads(ThreadGroup threadGroup) {
- Thread[] threads = new Thread[threadGroup.activeCount()];
- int numThreads = threadGroup.enumerate(threads);
- Collection<Thread> result = new ArrayList<>(numThreads);
- for (int i = 0; i < threads.length && threads[i] != null; i++) {
- result.add(threads[i]);
- }
- // note: the result should be modifiable
- return result;
- }
-
/**
* Pass any given system properties to the java system properties.
*/