diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b54311b385..45c078a2ce 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -144,9 +144,9 @@ junit-v4-13-1 = { module = "junit:junit", version = "4.13.1" } kms = { module = "software.amazon.awssdk:kms", version = "2.15.28" } libphonenumber = { module = "com.googlecode.libphonenumber:libphonenumber", version = "8.12.50" } listenablefuture = { module = "com.google.guava:listenablefuture", version = "9999.0-empty-to-avoid-conflict-with-guava" } -log4j-1-2-api = { module = "org.apache.logging.log4j:log4j-1.2-api", version = "2.25.4" } -log4j-api = { module = "org.apache.logging.log4j:log4j-api", version = "2.25.3" } -log4j-core = { module = "org.apache.logging.log4j:log4j-core", version = "2.25.4" } +log4j-1-2-api = { module = "org.apache.logging.log4j:log4j-1.2-api", version = "2.26.1" } +log4j-api = { module = "org.apache.logging.log4j:log4j-api", version = "2.26.1" } +log4j-core = { module = "org.apache.logging.log4j:log4j-core", version = "2.26.1" } management-api = { module = "org.glassfish.external:management-api", version = "3.2.1-b001" } metrics-spi = { module = "software.amazon.awssdk:metrics-spi", version = "2.15.28" } miglayout-core = { module = "com.miglayout:miglayout-core", version = "4.2" } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 5660a74f19..28595df13e 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -92,6 +92,11 @@ + + + + + @@ -117,6 +122,11 @@ + + + + + @@ -1935,6 +1945,11 @@ + + + + + @@ -1954,6 +1969,14 @@ + + + + + + + + @@ -1965,6 +1988,22 @@ + + + + + + + + + + + + + + + + @@ -1980,6 +2019,11 @@ + + + + + @@ -1999,6 +2043,14 @@ + + + + + + + + diff --git a/server/src/main/java/com/mirth/connect/server/launcher/Log4jBootstrap.java b/server/src/main/java/com/mirth/connect/server/launcher/Log4jBootstrap.java new file mode 100644 index 0000000000..215f588019 --- /dev/null +++ b/server/src/main/java/com/mirth/connect/server/launcher/Log4jBootstrap.java @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MPL-2.0 +// SPDX-FileCopyrightText: 2026 Mitch Gaffigan + +package com.mirth.connect.server.launcher; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.filefilter.WildcardFileFilter; + +/** Utility class for bootstrapping Log4j. */ +final class Log4jBootstrap { + private static final File LOG4J_LIB_DIR = new File("./server-lib/log4j"); + private static final String[] JAR_PATTERNS = { "log4j-core-*.jar", "log4j-api-*.jar", "log4j-1.2-api-*.jar" }; + + private Log4jBootstrap() {} + + /** Returns the classpath URLs for the Log4j libraries. */ + static List getClasspathUrls() throws IOException { + return getClasspathUrls(LOG4J_LIB_DIR); + } + + /** Unit testable version of getClasspathUrls. */ + static List getClasspathUrls(File log4jLibDir) throws IOException { + List log4jClasspathUrls = new ArrayList<>(); + + for (String jarPattern : JAR_PATTERNS) { + File[] matchingFiles = log4jLibDir.listFiles((FileFilter) new WildcardFileFilter(jarPattern)); + if (matchingFiles == null || matchingFiles.length != 1) { + throw new IOException("Expected exactly one " + jarPattern + " in " + log4jLibDir.getAbsolutePath()); + } + log4jClasspathUrls.add(matchingFiles[0].toURI().toURL()); + } + + return log4jClasspathUrls; + } +} \ No newline at end of file diff --git a/server/src/main/java/com/mirth/connect/server/launcher/MirthLauncher.java b/server/src/main/java/com/mirth/connect/server/launcher/MirthLauncher.java index cd3d343fd7..33458f2e08 100644 --- a/server/src/main/java/com/mirth/connect/server/launcher/MirthLauncher.java +++ b/server/src/main/java/com/mirth/connect/server/launcher/MirthLauncher.java @@ -43,9 +43,6 @@ public class MirthLauncher { private static final String LOG4J_PROPERTIES_FILE = "./conf/log4j2.properties"; private static final String PROPERTY_APP_DATA_DIR = "dir.appdata"; private static final String PROPERTY_INCLUDE_CUSTOM_LIB = "server.includecustomlib"; - private static final String[] LOG4J_JAR_FILES = { "./server-lib/log4j/log4j-core-2.25.3.jar", - "./server-lib/log4j/log4j-api-2.25.3.jar", - "./server-lib/log4j/log4j-1.2-api-2.25.3.jar" }; private static String appDataDir = null; @@ -58,9 +55,7 @@ public static void main(String[] args) { List classpathUrls = new ArrayList<>(); // Always add log4j - for (String log4jJar : LOG4J_JAR_FILES) { - classpathUrls.add(new File(log4jJar).toURI().toURL()); - } + classpathUrls.addAll(Log4jBootstrap.getClasspathUrls()); classpathUrls.addAll(addServerLauncherLibJarsToClasspath()); URLClassLoader mirthLauncherClassLoader = new URLClassLoader(classpathUrls.toArray(new URL[classpathUrls.size()]), Thread.currentThread().getContextClassLoader()); Thread.currentThread().setContextClassLoader(mirthLauncherClassLoader); diff --git a/server/src/test/java/com/mirth/connect/server/launcher/Log4jBootstrapTest.java b/server/src/test/java/com/mirth/connect/server/launcher/Log4jBootstrapTest.java new file mode 100644 index 0000000000..1a27103e93 --- /dev/null +++ b/server/src/test/java/com/mirth/connect/server/launcher/Log4jBootstrapTest.java @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MPL-2.0 +// SPDX-FileCopyrightText: 2026 Mitch Gaffigan + +package com.mirth.connect.server.launcher; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.net.URL; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +/** Unit tests for {@link Log4jBootstrap}. */ +public class Log4jBootstrapTest { + + /** Tests that {@link Log4jBootstrap#getClasspathUrls(File)} correctly resolves Log4j JARs regardless of version. */ + @Test + public void testGetClasspathUrlsDoesNotDependOnVersions() throws Exception { + File log4jLibDir = Files.createTempDirectory("log4j").toFile(); + log4jLibDir.deleteOnExit(); + + for (String name : Arrays.asList("log4j-core-99.0.0.jar", "log4j-api-99.0.0.jar", "log4j-1.2-api-99.0.0.jar")) { + File jarFile = new File(log4jLibDir, name); + assertTrue(jarFile.createNewFile()); + jarFile.deleteOnExit(); + } + + List classpathUrls = Log4jBootstrap.getClasspathUrls(log4jLibDir); + + assertEquals(Arrays.asList( + new File(log4jLibDir, "log4j-core-99.0.0.jar").toURI().toURL(), + new File(log4jLibDir, "log4j-api-99.0.0.jar").toURI().toURL(), + new File(log4jLibDir, "log4j-1.2-api-99.0.0.jar").toURI().toURL()), classpathUrls); + } +} \ No newline at end of file