From e3e819bffe0520d8d44ce32423ec558d142d517a Mon Sep 17 00:00:00 2001 From: Sajeer Date: Thu, 13 Aug 2026 13:12:00 +0530 Subject: [PATCH 1/4] Updated the environment variable resolution log message --- .../tools/common/plugins/config/ServerConfigDocument.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java index 2ae4372f3..4450f8ed1 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java +++ b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java @@ -357,6 +357,7 @@ private String resolveExpansionProperties(Properties props, String value, String Pattern pattern = OSUtil.isWindows() ? WINDOWS_EXPANSION_VAR_PATTERN : LINUX_EXPANSION_VAR_PATTERN; Matcher matcher = pattern.matcher(value); StringBuffer sb = new StringBuffer(); + List matchedVarNames = new ArrayList<>(); while (matcher.find()) { String finalReplacement; String varName = matcher.group(1); @@ -381,10 +382,15 @@ private String resolveExpansionProperties(Properties props, String value, String finalReplacement = matcher.group(0); // Keep original } matcher.appendReplacement(sb, Matcher.quoteReplacement(finalReplacement)); - log.info(String.format("Resolving Property %s for expression %s. Resolved expression value is %s", varName , value , sb)); + matchedVarNames.add(varName); } // 4. Finalize the string matcher.appendTail(sb); + + // Log after appendTail so sb holds the complete resolved value + for (String varName : matchedVarNames) { + log.info(String.format("Resolved environment variable \"%s\" in path \"%s\" to \"%s\"", varName, value, sb)); + } return sb.toString(); } From f007a6c10ab446a9d296af79164a2d954dab9ca1 Mon Sep 17 00:00:00 2001 From: Sajeer Date: Thu, 13 Aug 2026 17:03:43 +0530 Subject: [PATCH 2/4] Tests added --- .../ExpansionVariableLogMessageTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java diff --git a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java new file mode 100644 index 000000000..70db1c590 --- /dev/null +++ b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java @@ -0,0 +1,141 @@ +/** + * (C) Copyright IBM Corporation 2026. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openliberty.tools.common.config; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import io.openliberty.tools.common.TestLogger; +import io.openliberty.tools.common.plugins.config.ServerConfigDocument; +import io.openliberty.tools.common.plugins.util.OSUtil; +import io.openliberty.tools.common.plugins.util.ServerFeatureUtil; + +// Verifies the log message format produced by resolveExpansionProperties() after the fix for issue #2076 +public class ExpansionVariableLogMessageTest { + + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + // Captures info() calls for assertion; all other methods delegate to TestLogger + private static class CapturingLogger extends TestLogger { + final List infoMessages = new ArrayList<>(); + + @Override + public void info(String msg) { infoMessages.add(msg); } + } + + // server.env is placed in serverDir because SERVER_CONFIG_DIR maps there, making it visible to processServerEnv() + private ServerConfigDocument buildDoc(CapturingLogger log, File serverDir, String serverEnvContent) throws Exception { + Files.write(new File(serverDir, "server.env").toPath(), serverEnvContent.getBytes()); + + Map dirMap = new HashMap<>(); + dirMap.put(ServerFeatureUtil.WLP_INSTALL_DIR, serverDir); + dirMap.put(ServerFeatureUtil.WLP_USER_DIR, serverDir); + dirMap.put(ServerFeatureUtil.SERVER_CONFIG_DIR, serverDir); + dirMap.put(ServerFeatureUtil.SERVER_OUTPUT_DIR, serverDir); + return new ServerConfigDocument(log, null, dirMap); + } + + @Test + public void testUnixStyleLogMessageFormat() throws Exception { + Assume.assumeFalse("Skipped on Windows: Unix ${VAR} pattern not active", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-unix"); + + String envContent = "BASE=TEST\nDERIVED=${BASE}_SUFFIX\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg = "Resolved environment variable \"BASE\" in path \"${BASE}_SUFFIX\" to \"TEST_SUFFIX\""; + assertTrue("Expected log message not found.\nActual info messages: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg))); + } + + @Test + public void testUnixStyleMultipleVarsLogsBothVarNames() throws Exception { + Assume.assumeFalse("Skipped on Windows: Unix ${VAR} pattern not active", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-unix-multi"); + + String envContent = "EXP_VAR=TEST\nEXP_VAR2=UNIX\nCOMBINED=${EXP_VAR}_${EXP_VAR2}\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST_UNIX\""; + String expectedMsg2 = "Resolved environment variable \"EXP_VAR2\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST_UNIX\""; + assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); + assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg2))); + } + + @Test + public void testNoExpansionReferenceNoLogEmitted() throws Exception { + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-no-expansion"); + + String envContent = "PLAIN_VAR=just_a_value\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + assertTrue("No info log message should be emitted for plain values, but found: " + log.infoMessages, + log.infoMessages.isEmpty()); + } + + @Test + public void testWindowsStyleBackslashesPreservedInLog() throws Exception { + Assume.assumeTrue("Skipped on non-Windows: !VAR! pattern only active on Windows", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-win"); + + // Reproduces the exact scenario from issue #2076 + String envContent = "IBM_JAVA_SEMERU_HOME=C:\\MyData\\java\\ibm-semeru-certified\nJAVA_HOME=!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg = "Resolved environment variable \"IBM_JAVA_SEMERU_HOME\" in path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; + assertTrue("Log message with backslashes not found — backslashes may have been dropped.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg))); + } + + @Test + public void testWindowsStyleMultipleVarsLogsBothVarNames() throws Exception { + Assume.assumeTrue("Skipped on non-Windows: !VAR! pattern only active on Windows", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-win-multi"); + + String envContent = "EXP_VAR=TEST\nEXP_VAR3=WINDOWS\nCOMBINED=!EXP_VAR!_!EXP_VAR3!\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST_WINDOWS\""; + String expectedMsg2 = "Resolved environment variable \"EXP_VAR3\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST_WINDOWS\""; + assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); + assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg2))); + } +} From 39339bc88740dc8906e5d0a20443e776d0aeefc6 Mon Sep 17 00:00:00 2001 From: Sajeer Date: Thu, 20 Aug 2026 14:19:50 +0530 Subject: [PATCH 3/4] Fixed the log message to report each variable's individual resolved value instead of the full expression buffer by moving the log call inside the while loop. --- .../common/plugins/config/ServerConfigDocument.java | 8 +------- .../config/ExpansionVariableLogMessageTest.java | 12 ++++++------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java index 4450f8ed1..342d8c8a1 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java +++ b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java @@ -357,7 +357,6 @@ private String resolveExpansionProperties(Properties props, String value, String Pattern pattern = OSUtil.isWindows() ? WINDOWS_EXPANSION_VAR_PATTERN : LINUX_EXPANSION_VAR_PATTERN; Matcher matcher = pattern.matcher(value); StringBuffer sb = new StringBuffer(); - List matchedVarNames = new ArrayList<>(); while (matcher.find()) { String finalReplacement; String varName = matcher.group(1); @@ -382,15 +381,10 @@ private String resolveExpansionProperties(Properties props, String value, String finalReplacement = matcher.group(0); // Keep original } matcher.appendReplacement(sb, Matcher.quoteReplacement(finalReplacement)); - matchedVarNames.add(varName); + log.info(String.format("Resolved environment variable \"%s\" in path \"%s\" to \"%s\"", varName, value, finalReplacement)); } // 4. Finalize the string matcher.appendTail(sb); - - // Log after appendTail so sb holds the complete resolved value - for (String varName : matchedVarNames) { - log.info(String.format("Resolved environment variable \"%s\" in path \"%s\" to \"%s\"", varName, value, sb)); - } return sb.toString(); } diff --git a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java index 70db1c590..cd4d0173b 100644 --- a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java +++ b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java @@ -70,7 +70,7 @@ public void testUnixStyleLogMessageFormat() throws Exception { String envContent = "BASE=TEST\nDERIVED=${BASE}_SUFFIX\n"; buildDoc(log, serverDir, envContent).processServerEnv(); - String expectedMsg = "Resolved environment variable \"BASE\" in path \"${BASE}_SUFFIX\" to \"TEST_SUFFIX\""; + String expectedMsg = "Resolved environment variable \"BASE\" in path \"${BASE}_SUFFIX\" to \"TEST\""; assertTrue("Expected log message not found.\nActual info messages: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg))); } @@ -85,8 +85,8 @@ public void testUnixStyleMultipleVarsLogsBothVarNames() throws Exception { String envContent = "EXP_VAR=TEST\nEXP_VAR2=UNIX\nCOMBINED=${EXP_VAR}_${EXP_VAR2}\n"; buildDoc(log, serverDir, envContent).processServerEnv(); - String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST_UNIX\""; - String expectedMsg2 = "Resolved environment variable \"EXP_VAR2\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST_UNIX\""; + String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST\""; + String expectedMsg2 = "Resolved environment variable \"EXP_VAR2\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"UNIX\""; assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, @@ -122,7 +122,7 @@ public void testWindowsStyleBackslashesPreservedInLog() throws Exception { } @Test - public void testWindowsStyleMultipleVarsLogsBothVarNames() throws Exception { + public void testWindowsStyleMultipleVarsOneLogPerExpression() throws Exception { Assume.assumeTrue("Skipped on non-Windows: !VAR! pattern only active on Windows", OSUtil.isWindows()); CapturingLogger log = new CapturingLogger(); @@ -131,8 +131,8 @@ public void testWindowsStyleMultipleVarsLogsBothVarNames() throws Exception { String envContent = "EXP_VAR=TEST\nEXP_VAR3=WINDOWS\nCOMBINED=!EXP_VAR!_!EXP_VAR3!\n"; buildDoc(log, serverDir, envContent).processServerEnv(); - String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST_WINDOWS\""; - String expectedMsg2 = "Resolved environment variable \"EXP_VAR3\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST_WINDOWS\""; + String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST\""; + String expectedMsg2 = "Resolved environment variable \"EXP_VAR3\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"WINDOWS\""; assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, From faa5d9e752112f6f97f1785fce81da6892249bc5 Mon Sep 17 00:00:00 2001 From: Sajeer Date: Fri, 21 Aug 2026 12:49:57 +0530 Subject: [PATCH 4/4] Added one full line log to show which one got replaced with what --- .../common/plugins/config/ServerConfigDocument.java | 6 ++++++ .../config/ExpansionVariableLogMessageTest.java | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java index 342d8c8a1..05ce7f487 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java +++ b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java @@ -357,7 +357,9 @@ private String resolveExpansionProperties(Properties props, String value, String Pattern pattern = OSUtil.isWindows() ? WINDOWS_EXPANSION_VAR_PATTERN : LINUX_EXPANSION_VAR_PATTERN; Matcher matcher = pattern.matcher(value); StringBuffer sb = new StringBuffer(); + boolean anyMatched = false; while (matcher.find()) { + anyMatched = true; String finalReplacement; String varName = matcher.group(1); // 2. Circular Reference Guard @@ -385,6 +387,10 @@ private String resolveExpansionProperties(Properties props, String value, String } // 4. Finalize the string matcher.appendTail(sb); + // Log the complete resolved value once, only when at least one variable was expanded + if (anyMatched) { + log.info(String.format("Resolved path \"%s\" to \"%s\"", value, sb)); + } return sb.toString(); } diff --git a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java index cd4d0173b..fe176c9ff 100644 --- a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java +++ b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java @@ -71,8 +71,11 @@ public void testUnixStyleLogMessageFormat() throws Exception { buildDoc(log, serverDir, envContent).processServerEnv(); String expectedMsg = "Resolved environment variable \"BASE\" in path \"${BASE}_SUFFIX\" to \"TEST\""; + String expectedSummary = "Resolved path \"${BASE}_SUFFIX\" to \"TEST_SUFFIX\""; assertTrue("Expected log message not found.\nActual info messages: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); } @Test @@ -87,10 +90,13 @@ public void testUnixStyleMultipleVarsLogsBothVarNames() throws Exception { String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST\""; String expectedMsg2 = "Resolved environment variable \"EXP_VAR2\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"UNIX\""; + String expectedSummary = "Resolved path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST_UNIX\""; assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg2))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); } @Test @@ -117,8 +123,11 @@ public void testWindowsStyleBackslashesPreservedInLog() throws Exception { buildDoc(log, serverDir, envContent).processServerEnv(); String expectedMsg = "Resolved environment variable \"IBM_JAVA_SEMERU_HOME\" in path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; + String expectedSummary = "Resolved path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; assertTrue("Log message with backslashes not found — backslashes may have been dropped.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); } @Test @@ -133,9 +142,12 @@ public void testWindowsStyleMultipleVarsOneLogPerExpression() throws Exception { String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST\""; String expectedMsg2 = "Resolved environment variable \"EXP_VAR3\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"WINDOWS\""; + String expectedSummary = "Resolved path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST_WINDOWS\""; assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg2))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); } }