This is an automated email from the ASF dual-hosted git repository.
davsclaus 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 47406dddffe6 CAMEL-24372: Auto-inject camel-cli-connector for Spring
Boot projects
47406dddffe6 is described below
commit 47406dddffe6c87a34aa11ef9ea821c26e8acda4
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Aug 10 19:20:33 2026 +0200
CAMEL-24372: Auto-inject camel-cli-connector for Spring Boot projects
When launching a Spring Boot project via F10, inject the
camel-cli-connector-starter dependency into a temp pom copy if not
already present, so the TUI can communicate with the running app.
Also enable restart for Spring Boot and Quarkus projects.
CAMEL-24372: Restart Spring Boot/Quarkus via Maven parent re-launch
For Spring Boot and Quarkus restarts, find the Maven parent process
and re-launch it instead of the raw Java child process. This ensures
source changes are recompiled before the app restarts.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../dsl/jbang/core/commands/tui/CamelMonitor.java | 76 ++++++++++++++++++++--
.../dsl/jbang/core/commands/tui/LaunchManager.java | 64 ++++++++++++++++++
2 files changed, 134 insertions(+), 6 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index fe75b998ffd4..a4b751233121 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
@@ -1904,16 +1904,80 @@ public class CamelMonitor extends CamelCommand {
}
String platform = info.platform;
- boolean isSpringBoot = "Spring Boot".equals(platform);
- boolean isQuarkus = "Quarkus".equals(platform);
+ boolean isMavenManaged = "Spring Boot".equals(platform) ||
"Quarkus".equals(platform);
+ if (isMavenManaged) {
+ restartMavenProcess(ph, info);
+ } else {
+ restartCamelMainProcess(ph, info);
+ }
+ }
- // TODO: restart for Spring Boot and Quarkus is not yet reliable
- if (isSpringBoot || isQuarkus) {
- setNotification("Restart not supported for " + platform, true);
+ private void restartMavenProcess(ProcessHandle ph, IntegrationInfo info) {
+ // Find the Maven parent process (mvn spring-boot:run / quarkus:dev)
+ ProcessHandle mavenPh = ph.parent().orElse(null);
+ if (mavenPh == null) {
+ setNotification("Cannot restart: Maven parent process not found",
true);
return;
}
- restartCamelMainProcess(ph, info);
+ // Capture Maven parent command line before stopping
+ Optional<String> cmdOpt = mavenPh.info().command();
+ Optional<String[]> argsOpt = mavenPh.info().arguments();
+ Optional<String> cmdLineOpt = mavenPh.info().commandLine();
+
+ String name = info.name;
+ String directory = info.directory;
+
+ ctx.lastSelectedName = name;
+ dataService.forceFullScan();
+
+ // Kill the Maven parent (which also kills the child Java process)
+ mavenPh.destroy();
+ setNotification("Restarting: " + name, false);
+
+ if (runner != null) {
+ ctx.backgroundExecutor.execute(() -> {
+ try {
+ CompletableFuture<ProcessHandle> exitFuture =
mavenPh.onExit().toCompletableFuture();
+ try {
+ exitFuture.get(15, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ mavenPh.destroyForcibly();
+ Thread.sleep(500);
+ }
+
+ List<String> cmd = new ArrayList<>();
+ if (cmdOpt.isPresent() && argsOpt.isPresent() &&
argsOpt.get().length > 0) {
+ cmd.add(cmdOpt.get());
+ Collections.addAll(cmd, argsOpt.get());
+ } else {
+ cmdLineOpt.ifPresent(s ->
cmd.addAll(parseCommandLine(s)));
+ }
+
+ if (cmd.isEmpty()) {
+ runner.runOnRenderThread(
+ () -> setNotification("Cannot restart: Maven
command line not available", true));
+ return;
+ }
+
+ ProcessBuilder pb = new ProcessBuilder(cmd);
+ if (directory != null) {
+ pb.directory(new File(directory));
+ }
+ pb.redirectErrorStream(true);
+ Path outputFile =
LaunchManager.createSecureTempFile("camel-restart-", ".log");
+ outputFile.toFile().deleteOnExit();
+ pb.redirectOutput(outputFile.toFile());
+ Process process = pb.start();
+ actionsPopup.getLaunchManager().addPendingLaunch(name,
process, outputFile);
+
+ runner.runOnRenderThread(() -> setNotification("Restarted:
" + name + " (recompiling)", false));
+ } catch (Exception e) {
+ runner.runOnRenderThread(
+ () -> setNotification("Restart failed: " +
e.getMessage(), true));
+ }
+ });
+ }
}
private void restartCamelMainProcess(ProcessHandle ph, IntegrationInfo
info) {
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
index 890e8043ad50..6ac7d6e5e2c5 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
@@ -203,6 +203,10 @@ class LaunchManager {
}
// Translate Camel JBang args to Maven-compatible args
cmd.addAll(translateArgsForMaven(extraArgs, projectType));
+ // Inject camel-cli-connector if not already in the project
+ if ("spring-boot".equals(projectType)) {
+ injectCliConnectorIfMissing(dir, cmd);
+ }
Path outputFile = createSecureTempFile("camel-maven-", ".log");
outputFile.toFile().deleteOnExit();
ProcessBuilder pb = new ProcessBuilder(cmd);
@@ -217,6 +221,66 @@ class LaunchManager {
}
}
+ private void injectCliConnectorIfMissing(String dir, List<String> cmd) {
+ try {
+ Path pomFile = Path.of(dir, "pom.xml");
+ if (!Files.isRegularFile(pomFile)) {
+ return;
+ }
+ String pomContent = Files.readString(pomFile);
+ if (pomContent.contains("camel-cli-connector")) {
+ return;
+ }
+ // Add cli-connector-starter dependency (version managed by BOM)
+ String dep = "\n <dependency>\n"
+ + "
<groupId>org.apache.camel.springboot</groupId>\n"
+ + "
<artifactId>camel-cli-connector-starter</artifactId>\n"
+ + " </dependency>";
+ // Find the project-level </dependencies> (not inside
dependencyManagement or plugins)
+ int insertIdx = findProjectDependenciesEnd(pomContent);
+ if (insertIdx < 0) {
+ return;
+ }
+ String modified = pomContent.substring(0, insertIdx) + dep + "\n
" + pomContent.substring(insertIdx);
+ // Write temp pom in the project dir so Maven can find sources
+ Path tempPom = Path.of(dir, ".camel-tui-pom.xml");
+ tempPom.toFile().deleteOnExit();
+ Files.writeString(tempPom, modified);
+ cmd.add("-f");
+ cmd.add(tempPom.getFileName().toString());
+ } catch (Exception e) {
+ // best effort — don't fail the launch
+ }
+ }
+
+ private static int findProjectDependenciesEnd(String pom) {
+ // Find <dependencies> that is a direct child of <project>,
+ // not nested inside <dependencyManagement>, <plugin>, or <profile>
+ int dmStart = pom.indexOf("<dependencyManagement>");
+ int dmEnd = dmStart >= 0 ? pom.indexOf("</dependencyManagement>",
dmStart) : -1;
+ int buildStart = pom.indexOf("<build>");
+
+ int searchFrom = 0;
+ while (true) {
+ int depStart = pom.indexOf("<dependencies>", searchFrom);
+ if (depStart < 0) {
+ return -1;
+ }
+ // Skip if inside <dependencyManagement>
+ if (dmStart >= 0 && depStart > dmStart && (dmEnd < 0 || depStart <
dmEnd)) {
+ searchFrom = dmEnd > 0 ? dmEnd : depStart + 14;
+ continue;
+ }
+ // Skip if inside <build> (plugins can have dependencies)
+ if (buildStart >= 0 && depStart > buildStart) {
+ searchFrom = depStart + 14;
+ continue;
+ }
+ int depEnd = pom.indexOf("</dependencies>", depStart);
+ return depEnd >= 0 ? depEnd : -1;
+ }
+ }
+
void launchCamelRun(String sourceDir, String displayName, List<String>
extraArgs) {
try {
List<String> cmd = new
ArrayList<>(LauncherHelper.getCamelCommand());