This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 37c3e13d4c expose hop server configuration variables, fixes #6707 
(#7099)
37c3e13d4c is described below

commit 37c3e13d4cd1d638c0b9d15896118511812b3c65
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Tue May 5 20:27:02 2026 +0200

    expose hop server configuration variables, fixes #6707 (#7099)
---
 core/src/main/java/org/apache/hop/core/Const.java  | 24 ++++++++
 .../modules/ROOT/pages/variables.adoc              | 15 +++++
 .../main/java/org/apache/hop/www/HopServer.java    |  5 ++
 .../java/org/apache/hop/www/HopServerConfig.java   | 24 ++++++++
 .../org/apache/hop/www/HopServerConfigTest.java    | 71 ++++++++++++++++++++++
 5 files changed, 139 insertions(+)

diff --git a/core/src/main/java/org/apache/hop/core/Const.java 
b/core/src/main/java/org/apache/hop/core/Const.java
index 80809b9e72..b4b5dc52a5 100644
--- a/core/src/main/java/org/apache/hop/core/Const.java
+++ b/core/src/main/java/org/apache/hop/core/Const.java
@@ -401,6 +401,30 @@ public class Const {
 
   public static final String INTERNAL_VARIABLE_ACTION_ID = 
INTERNAL_VARIABLE_PREFIX + ".Action.ID";
 
+  /** The Hop server name as configured in hop-server.xml */
+  public static final String INTERNAL_VARIABLE_HOP_SERVER_NAME =
+      INTERNAL_VARIABLE_PREFIX + ".Server.Name";
+
+  /** The Hop server hostname */
+  public static final String INTERNAL_VARIABLE_HOP_SERVER_HOSTNAME =
+      INTERNAL_VARIABLE_PREFIX + ".Server.Hostname";
+
+  /** The Hop server HTTP port */
+  public static final String INTERNAL_VARIABLE_HOP_SERVER_PORT =
+      INTERNAL_VARIABLE_PREFIX + ".Server.Port";
+
+  /** The Hop server web application name */
+  public static final String INTERNAL_VARIABLE_HOP_SERVER_WEB_APP_NAME =
+      INTERNAL_VARIABLE_PREFIX + ".Server.WebAppName";
+
+  /** The Hop server username */
+  public static final String INTERNAL_VARIABLE_HOP_SERVER_USERNAME =
+      INTERNAL_VARIABLE_PREFIX + ".Server.Username";
+
+  /** Whether the Hop server is running in SSL mode */
+  public static final String INTERNAL_VARIABLE_HOP_SERVER_SSL_MODE =
+      INTERNAL_VARIABLE_PREFIX + ".Server.SslMode";
+
   /** The default maximum for the nr of lines in the GUI logs */
   public static final int MAX_NR_LOG_LINES = 5000;
 
diff --git a/docs/hop-user-manual/modules/ROOT/pages/variables.adoc 
b/docs/hop-user-manual/modules/ROOT/pages/variables.adoc
index fa2dbdff78..fd767e1096 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/variables.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/variables.adoc
@@ -364,3 +364,18 @@ Additionally, the following environment variables can help 
you to add even more
 |${Internal.Transform.BundleNr} |N |The bundle number for partitioned 
execution, helpful in load-balancing or distributing data across partitions.
 |${Internal.Action.ID} |N |The unique ID of the current action (entry) in a 
workflow. Useful for tracking specific actions within a larger workflow.
 |===
+
+=== Hop server internal variables
+
+The variables below are only set when a pipeline or workflow is executed on a 
Hop server. They are populated from the `hop-server.xml` configuration file at 
server startup and inherited by every pipeline and workflow that runs on that 
server, so you can reference the server's own coordinates from within your 
pipelines and workflows (for example to build callback URLs or to log the 
server that processed a request).
+
+[%header, width="90%", cols="2,1,5"]
+|===
+|Variable |Default |Description
+|${Internal.Server.Name} |N |The name of the Hop server as configured in 
`hop-server.xml` (the `<name>` element of the `hop-server` definition).
+|${Internal.Server.Hostname} |N |The hostname the Hop server is bound to, as 
configured in `hop-server.xml`. If a `network_interface` was configured, this 
is the resolved IP address for that interface.
+|${Internal.Server.Port} |N |The HTTP port the Hop server is listening on. 
This is the actual port the server bound to, which may differ from the value in 
`hop-server.xml` when the server was started with command-line overrides.
+|${Internal.Server.WebAppName} |N |The web application name (context path) the 
Hop server is exposed under, as configured in `hop-server.xml`. Empty when no 
web app name was set.
+|${Internal.Server.Username} |N |The username configured for the Hop server in 
`hop-server.xml`. Empty when authentication is not configured.
+|${Internal.Server.SslMode} |N |`true` when the Hop server is configured to 
use SSL/TLS, `false` otherwise.
+|===
diff --git a/engine/src/main/java/org/apache/hop/www/HopServer.java 
b/engine/src/main/java/org/apache/hop/www/HopServer.java
index f961cadeee..3dab45388d 100644
--- a/engine/src/main/java/org/apache/hop/www/HopServer.java
+++ b/engine/src/main/java/org/apache/hop/www/HopServer.java
@@ -206,6 +206,11 @@ public class HopServer implements Runnable, 
IHasHopMetadataProvider, IHopCommand
     }
 
     if (allOK) {
+      // Expose the hop-server.xml details as Internal.Server.* variables so 
they
+      // are inherited by pipelines and workflows executing on this server.
+      config.setInternalHopServerVariables(config.getVariables(), port);
+      config.setInternalHopServerVariables(variables, port);
+
       boolean shouldJoin = config.isJoining();
       if (joinOverride != null) {
         shouldJoin = joinOverride;
diff --git a/engine/src/main/java/org/apache/hop/www/HopServerConfig.java 
b/engine/src/main/java/org/apache/hop/www/HopServerConfig.java
index 6b47f5b164..cd40132503 100644
--- a/engine/src/main/java/org/apache/hop/www/HopServerConfig.java
+++ b/engine/src/main/java/org/apache/hop/www/HopServerConfig.java
@@ -212,6 +212,30 @@ public class HopServerConfig implements IXml {
             hostname + ":" + port, hostname, "" + port, "" + shutdownPort, 
null, null);
   }
 
+  /**
+   * Expose the configured Hop server details (hop-server.xml) as 
Internal.Server.* variables on the
+   * given variable space, so pipelines and workflows running on this server 
can reference them.
+   *
+   * @param variables the variable space to populate
+   * @param resolvedPort the actual HTTP port the server is bound to
+   */
+  public void setInternalHopServerVariables(IVariables variables, int 
resolvedPort) {
+    if (variables == null || hopServer == null) {
+      return;
+    }
+    variables.setVariable(
+        Const.INTERNAL_VARIABLE_HOP_SERVER_NAME, 
Const.NVL(hopServer.getName(), ""));
+    variables.setVariable(
+        Const.INTERNAL_VARIABLE_HOP_SERVER_HOSTNAME, 
Const.NVL(hopServer.getHostname(), ""));
+    variables.setVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_PORT, 
Integer.toString(resolvedPort));
+    variables.setVariable(
+        Const.INTERNAL_VARIABLE_HOP_SERVER_WEB_APP_NAME, 
Const.NVL(hopServer.getWebAppName(), ""));
+    variables.setVariable(
+        Const.INTERNAL_VARIABLE_HOP_SERVER_USERNAME, 
Const.NVL(hopServer.getUsername(), ""));
+    variables.setVariable(
+        Const.INTERNAL_VARIABLE_HOP_SERVER_SSL_MODE, 
Boolean.toString(hopServer.isSslMode()));
+  }
+
   /**
    * @return the hop server.<br>
    *     The user name and password defined in here are used to contact this 
server by the masters.
diff --git a/engine/src/test/java/org/apache/hop/www/HopServerConfigTest.java 
b/engine/src/test/java/org/apache/hop/www/HopServerConfigTest.java
index 188a4b0154..5daee773c9 100644
--- a/engine/src/test/java/org/apache/hop/www/HopServerConfigTest.java
+++ b/engine/src/test/java/org/apache/hop/www/HopServerConfigTest.java
@@ -27,7 +27,10 @@ import java.util.Map;
 import java.util.Map.Entry;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.exception.HopXmlException;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.variables.Variables;
 import org.apache.hop.core.xml.XmlHandler;
+import org.apache.hop.server.HopServerMeta;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -217,6 +220,74 @@ class HopServerConfigTest {
     assertNull(parseJettyOptions);
   }
 
+  @Test
+  void testSetInternalHopServerVariables_populatesAllVariables() {
+    HopServerMeta meta =
+        new HopServerMeta("my-server", "host.example.com", "8181", "8180", 
"admin", "secret");
+    meta.setWebAppName("hop");
+    meta.setSslMode(true);
+    slServerConfig.setHopServer(meta);
+
+    IVariables variables = new Variables();
+    slServerConfig.setInternalHopServerVariables(variables, 8181);
+
+    assertEquals("my-server", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_NAME));
+    assertEquals(
+        "host.example.com", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_HOSTNAME));
+    assertEquals("8181", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_PORT));
+    assertEquals("hop", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_WEB_APP_NAME));
+    assertEquals("admin", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_USERNAME));
+    assertEquals("true", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_SSL_MODE));
+  }
+
+  @Test
+  void testSetInternalHopServerVariables_resolvedPortOverridesConfigured() {
+    HopServerMeta meta = new HopServerMeta("local8080", "localhost", "8080", 
"8079", null, null);
+    slServerConfig.setHopServer(meta);
+
+    IVariables variables = new Variables();
+    slServerConfig.setInternalHopServerVariables(variables, 9090);
+
+    assertEquals("9090", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_PORT));
+  }
+
+  @Test
+  void testSetInternalHopServerVariables_handlesEmptyOptionalFields() {
+    HopServerMeta meta = new HopServerMeta();
+    meta.setName("minimal");
+    meta.setHostname("localhost");
+    slServerConfig.setHopServer(meta);
+
+    IVariables variables = new Variables();
+    slServerConfig.setInternalHopServerVariables(variables, 8080);
+
+    assertEquals("minimal", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_NAME));
+    assertEquals("localhost", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_HOSTNAME));
+    assertEquals("", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_WEB_APP_NAME));
+    assertEquals("", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_USERNAME));
+    assertEquals("false", 
variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_SSL_MODE));
+  }
+
+  @Test
+  void testSetInternalHopServerVariables_nullServerIsNoop() {
+    // No HopServerMeta on the config — should not throw and should not set 
any variable.
+    IVariables variables = new Variables();
+    slServerConfig.setInternalHopServerVariables(variables, 8080);
+
+    assertNull(variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_NAME));
+    
assertNull(variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_HOSTNAME));
+    assertNull(variables.getVariable(Const.INTERNAL_VARIABLE_HOP_SERVER_PORT));
+  }
+
+  @Test
+  void testSetInternalHopServerVariables_nullVariablesIsNoop() {
+    HopServerMeta meta = new HopServerMeta("server", "host", "8181", "8180", 
null, null);
+    slServerConfig.setHopServer(meta);
+
+    // Should not throw on null variables.
+    slServerConfig.setInternalHopServerVariables(null, 8181);
+  }
+
   private Node getConfigNode(String configString) throws HopXmlException {
     Document document = XmlHandler.loadXmlString(configString);
     return XmlHandler.getSubNode(document, HopServerConfig.XML_TAG);

Reply via email to