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 42733d37869f CAMEL-23911: camel-jbang - TUI support configuring HTTP 
proxy settings
42733d37869f is described below

commit 42733d37869f2d00dc00a8fcdf812ab6cc7612bc
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Jul 26 08:12:18 2026 +0200

    CAMEL-23911: camel-jbang - TUI support configuring HTTP proxy settings
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/DocHelper.java     | 27 ++++++++----
 .../dsl/jbang/core/commands/tui/OsvClient.java     |  1 +
 .../dsl/jbang/core/commands/tui/SettingsPopup.java | 38 ++++++++++++++---
 .../dsl/jbang/core/commands/tui/TuiSettings.java   | 48 ++++++++++++++++++++++
 .../jbang/core/commands/tui/SettingsPopupTest.java | 14 ++++---
 5 files changed, 107 insertions(+), 21 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
index 53335ecdd091..823b94ae3a99 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
@@ -18,9 +18,12 @@ package org.apache.camel.dsl.jbang.core.commands.tui;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.HttpURLConnection;
 import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
 import java.nio.charset.StandardCharsets;
+import java.time.Duration;
 
 import org.apache.camel.dsl.jbang.core.common.ExampleHelper;
 
@@ -42,17 +45,23 @@ final class DocHelper {
 
     static String downloadContent(String url) {
         try {
-            HttpURLConnection conn = (HttpURLConnection) 
URI.create(url).toURL().openConnection();
-            conn.setConnectTimeout(5000);
-            conn.setReadTimeout(10000);
-            try (InputStream is = conn.getInputStream()) {
-                return new String(is.readAllBytes(), StandardCharsets.UTF_8);
-            } finally {
-                conn.disconnect();
+            HttpClient client = HttpClient.newBuilder()
+                    .connectTimeout(Duration.ofSeconds(5))
+                    .proxy(TuiSettings.proxySelector())
+                    .build();
+            HttpRequest request = HttpRequest.newBuilder()
+                    .uri(URI.create(url))
+                    .timeout(Duration.ofSeconds(10))
+                    .GET()
+                    .build();
+            HttpResponse<String> response = client.send(request, 
HttpResponse.BodyHandlers.ofString());
+            if (response.statusCode() == 200) {
+                return response.body();
             }
         } catch (Exception e) {
-            return null;
+            // ignore
         }
+        return null;
     }
 
     static String asciidocToMarkdown(String adoc) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OsvClient.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OsvClient.java
index 112e77597412..12ce01ce1837 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OsvClient.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OsvClient.java
@@ -94,6 +94,7 @@ class OsvClient {
         try {
             HttpClient client = HttpClient.newBuilder()
                     .connectTimeout(Duration.ofSeconds(5))
+                    .proxy(TuiSettings.proxySelector())
                     .build();
             HttpRequest request = HttpRequest.newBuilder()
                     .uri(URI.create(BATCH_URL))
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
index 0ea39ed5da30..bf0bbe231cb9 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
@@ -52,12 +52,14 @@ class SettingsPopup {
     private static final int ROW_LOG_PIN = 3;
     private static final int ROW_RATE_PER = 4;
     private static final int ROW_FOLDER = 5;
-    private static final int ROW_SHELL_HISTORY = 6;
-    private static final int ROW_AI_PROVIDER = 7;
-    private static final int ROW_AI_MODEL = 8;
-    private static final int ROW_AI_URL = 9;
-    private static final int ROW_AI_PROMPT_HISTORY = 10;
-    private static final int ROW_COUNT = 11;
+    private static final int ROW_PROXY_HOST = 6;
+    private static final int ROW_PROXY_PORT = 7;
+    private static final int ROW_SHELL_HISTORY = 8;
+    private static final int ROW_AI_PROVIDER = 9;
+    private static final int ROW_AI_MODEL = 10;
+    private static final int ROW_AI_URL = 11;
+    private static final int ROW_AI_PROMPT_HISTORY = 12;
+    private static final int ROW_COUNT = 13;
 
     private static final String[] LOG_PIN_OPTIONS = { "off", "25", "50", "75" 
};
     private static final String[] RATE_PER_OPTIONS = { "seconds", "minutes" };
@@ -83,6 +85,8 @@ class SettingsPopup {
     private int ratePerIndex;
     private int aiProviderIndex;
     private TextInputState folderInput;
+    private TextInputState proxyHostInput;
+    private TextInputState proxyPortInput;
     private TextInputState shellHistoryInput;
     private TextInputState aiModelInput;
     private TextInputState aiUrlInput;
@@ -155,6 +159,8 @@ class SettingsPopup {
         ratePerIndex = "minutes".equals(currentRatePer) ? 1 : 0;
 
         folderInput = new TextInputState(settings.getDefaultFolder() != null ? 
settings.getDefaultFolder() : "");
+        proxyHostInput = new TextInputState(settings.getProxyHost() != null ? 
settings.getProxyHost() : "");
+        proxyPortInput = new TextInputState(settings.getProxyPort() != null ? 
settings.getProxyPort() : "");
         shellHistoryInput = new TextInputState(settings.getShellHistory() != 
null ? settings.getShellHistory() : "");
         String currentProvider = settings.getAiProvider() != null ? 
settings.getAiProvider() : "auto";
         int providerIdx = AI_PROVIDERS.indexOf(currentProvider);
@@ -251,6 +257,14 @@ class SettingsPopup {
             handleTextInput(ke, folderInput);
             return true;
         }
+        if (selectedRow == ROW_PROXY_HOST) {
+            handleTextInput(ke, proxyHostInput);
+            return true;
+        }
+        if (selectedRow == ROW_PROXY_PORT) {
+            handleTextInput(ke, proxyPortInput);
+            return true;
+        }
         if (selectedRow == ROW_SHELL_HISTORY) {
             handleTextInput(ke, shellHistoryInput);
             return true;
@@ -296,6 +310,8 @@ class SettingsPopup {
             monitorContext.ratePerMinute = "minutes".equals(ratePerValue);
         }
         
settings.setDefaultFolder(stripControlChars(folderInput.text().trim()));
+        settings.setProxyHost(stripControlChars(proxyHostInput.text().trim()));
+        settings.setProxyPort(stripControlChars(proxyPortInput.text().trim()));
         
settings.setShellHistory(stripControlChars(shellHistoryInput.text().trim()));
         settings.setAiProvider(AI_PROVIDERS.get(aiProviderIndex));
         settings.setAiModel(stripControlChars(aiModelInput.text().trim()));
@@ -361,6 +377,16 @@ class SettingsPopup {
         renderFolder(frame, innerX + labelW, rowY, fieldW, selectedRow == 
ROW_FOLDER);
         rowY++;
 
+        renderLabel(frame, innerX, rowY, labelW, "Proxy Host:", selectedRow == 
ROW_PROXY_HOST);
+        renderTextInput(frame, innerX + labelW, rowY, fieldW, proxyHostInput,
+                selectedRow == ROW_PROXY_HOST, "proxy.corp.com");
+        rowY++;
+
+        renderLabel(frame, innerX, rowY, labelW, "Proxy Port:", selectedRow == 
ROW_PROXY_PORT);
+        renderTextInput(frame, innerX + labelW, rowY, fieldW, proxyPortInput,
+                selectedRow == ROW_PROXY_PORT, "(8080)");
+        rowY++;
+
         renderLabel(frame, innerX, rowY, labelW, "Shell History:", selectedRow 
== ROW_SHELL_HISTORY);
         renderTextInput(frame, innerX + labelW, rowY, fieldW, 
shellHistoryInput,
                 selectedRow == ROW_SHELL_HISTORY, "(100)");
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
index ad5d07ceeca3..d586473ce3fc 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.dsl.jbang.core.commands.tui;
 
+import java.net.InetSocketAddress;
+import java.net.ProxySelector;
+
 /**
  * User-facing preferences for the Camel TUI, persisted under {@code 
camel.tui.*} keys in the CLI user configuration
  * files. The object is loaded as a whole ({@link #load()}), mutated in 
memory, and written back ({@link #save()}),
@@ -36,6 +39,8 @@ final class TuiSettings {
     static final String PROP_AI_PROVIDER = "camel.tui.ai.provider";
     static final String PROP_AI_MODEL = "camel.tui.ai.model";
     static final String PROP_AI_URL = "camel.tui.ai.url";
+    static final String PROP_PROXY_HOST = "camel.tui.proxyHost";
+    static final String PROP_PROXY_PORT = "camel.tui.proxyPort";
     static final String PROP_SHELL_HISTORY = "camel.tui.shell.history";
     static final String PROP_AI_PROMPT_HISTORY = "camel.tui.ai.promptHistory";
 
@@ -45,6 +50,8 @@ final class TuiSettings {
     private String logPin;
     private String ratePer;
     private String defaultFolder;
+    private String proxyHost;
+    private String proxyPort;
     private String aiProvider;
     private String aiModel;
     private String aiUrl;
@@ -99,6 +106,22 @@ final class TuiSettings {
         this.defaultFolder = defaultFolder;
     }
 
+    String getProxyHost() {
+        return proxyHost;
+    }
+
+    void setProxyHost(String proxyHost) {
+        this.proxyHost = proxyHost;
+    }
+
+    String getProxyPort() {
+        return proxyPort;
+    }
+
+    void setProxyPort(String proxyPort) {
+        this.proxyPort = proxyPort;
+    }
+
     String getAiProvider() {
         return aiProvider;
     }
@@ -161,6 +184,8 @@ final class TuiSettings {
             settings.logPin = trimToNull(TuiUserConfig.read(PROP_LOG_PIN));
             settings.ratePer = trimToNull(TuiUserConfig.read(PROP_RATE_PER));
             settings.defaultFolder = 
trimToNull(TuiUserConfig.read(PROP_DEFAULT_FOLDER));
+            settings.proxyHost = 
trimToNull(TuiUserConfig.read(PROP_PROXY_HOST));
+            settings.proxyPort = 
trimToNull(TuiUserConfig.read(PROP_PROXY_PORT));
             settings.aiProvider = 
trimToNull(TuiUserConfig.read(PROP_AI_PROVIDER));
             settings.aiModel = trimToNull(TuiUserConfig.read(PROP_AI_MODEL));
             settings.aiUrl = trimToNull(TuiUserConfig.read(PROP_AI_URL));
@@ -185,6 +210,8 @@ final class TuiSettings {
             TuiUserConfig.write(PROP_LOG_PIN, logPin);
             TuiUserConfig.write(PROP_RATE_PER, ratePer);
             TuiUserConfig.write(PROP_DEFAULT_FOLDER, defaultFolder);
+            TuiUserConfig.write(PROP_PROXY_HOST, proxyHost);
+            TuiUserConfig.write(PROP_PROXY_PORT, proxyPort);
             TuiUserConfig.write(PROP_AI_PROVIDER, aiProvider);
             TuiUserConfig.write(PROP_AI_MODEL, aiModel);
             TuiUserConfig.write(PROP_AI_URL, aiUrl);
@@ -195,6 +222,27 @@ final class TuiSettings {
         }
     }
 
+    /**
+     * Returns a {@link ProxySelector} based on the configured proxy settings, 
falling back to the JVM default.
+     */
+    static ProxySelector proxySelector() {
+        TuiSettings s = load();
+        String host = s.getProxyHost();
+        if (host != null && !host.isEmpty()) {
+            int port = 8080;
+            String portStr = s.getProxyPort();
+            if (portStr != null) {
+                try {
+                    port = Integer.parseInt(portStr);
+                } catch (NumberFormatException e) {
+                    // use default port
+                }
+            }
+            return ProxySelector.of(new InetSocketAddress(host, port));
+        }
+        return ProxySelector.getDefault();
+    }
+
     private static String trimToNull(String value) {
         if (value == null) {
             return null;
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
index cea26dd4af25..f353f54cf057 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
@@ -177,7 +177,9 @@ class SettingsPopupTest {
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
-        assertEquals(7, popup.selectedRow());
+        popup.handleKeyEvent(key(KeyCode.DOWN));
+        popup.handleKeyEvent(key(KeyCode.DOWN));
+        assertEquals(9, popup.selectedRow());
         assertEquals("auto", popup.selectedAiProvider());
         popup.handleKeyEvent(KeyEvent.ofChar(' '));
         assertEquals("ollama", popup.selectedAiProvider());
@@ -209,21 +211,21 @@ class SettingsPopupTest {
         popup.setTabEntries(tabs());
         popup.open();
 
-        // navigate to Shell History (row 6)
-        for (int i = 0; i < 6; i++) {
+        // navigate to Shell History (row 8)
+        for (int i = 0; i < 8; i++) {
             popup.handleKeyEvent(key(KeyCode.DOWN));
         }
-        assertEquals(6, popup.selectedRow());
+        assertEquals(8, popup.selectedRow());
         for (char c : "50".toCharArray()) {
             popup.handleKeyEvent(KeyEvent.ofChar(c));
         }
         assertEquals("50", popup.shellHistoryText());
 
-        // navigate to AI Prompt History (row 10)
+        // navigate to AI Prompt History (row 12)
         for (int i = 0; i < 4; i++) {
             popup.handleKeyEvent(key(KeyCode.DOWN));
         }
-        assertEquals(10, popup.selectedRow());
+        assertEquals(12, popup.selectedRow());
         for (char c : "200".toCharArray()) {
             popup.handleKeyEvent(KeyEvent.ofChar(c));
         }

Reply via email to