Skip to content

Commit 71a5c24

Browse files
committed
Clean up log4j migration code, add more tests
Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
1 parent 66d7b8f commit 71a5c24

4 files changed

Lines changed: 160 additions & 67 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) Mirth Corporation. All rights reserved.
3+
*
4+
* http://www.mirthcorp.com
5+
*
6+
* The software in this package is published under the terms of the MPL license a copy of which has
7+
* been included with this distribution in the LICENSE.txt file.
8+
*/
9+
10+
package com.mirth.connect.server.launcher;
11+
12+
import java.io.File;
13+
import java.io.IOException;
14+
import java.nio.charset.StandardCharsets;
15+
import java.util.List;
16+
17+
import org.apache.commons.io.FileUtils;
18+
19+
public class Log4jMigrations {
20+
private static final String INVALID_LOG4J_PROPERTY = "dir.logs";
21+
22+
private Log4jMigrations() {}
23+
24+
public static void migrateConfiguration(File propertiesFile) {
25+
if (!propertiesFile.exists() || !propertiesFile.isFile()) {
26+
return;
27+
}
28+
29+
try {
30+
List<String> lines = FileUtils.readLines(propertiesFile, StandardCharsets.UTF_8);
31+
if (stripDirLogs(lines)) {
32+
FileUtils.writeLines(propertiesFile, StandardCharsets.UTF_8.name(), lines, System.lineSeparator(), false);
33+
}
34+
} catch (IOException e) {
35+
System.err.println("Failed to migrate Log4j configuration: " + propertiesFile.getAbsolutePath());
36+
e.printStackTrace();
37+
}
38+
}
39+
40+
private static boolean stripDirLogs(List<String> lines) {
41+
return lines.removeIf(line -> isPropertyLine(line, INVALID_LOG4J_PROPERTY));
42+
}
43+
44+
private static boolean isPropertyLine(String line, String propertyName) {
45+
String trimmedLine = line.trim();
46+
int equalsIndex = trimmedLine.indexOf('=');
47+
return equalsIndex >= 0 && trimmedLine.substring(0, equalsIndex).trim().equals(propertyName);
48+
}
49+
}

server/src/com/mirth/connect/server/launcher/MirthLauncher.java

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
/*
2-
* Copyright (c) Mirth Corporation. All rights reserved.
3-
*
4-
* http://www.mirthcorp.com
5-
*
6-
* The software in this package is published under the terms of the MPL license a copy of which has
7-
* been included with this distribution in the LICENSE.txt file.
8-
*/
1+
// SPDX-License-Identifier: MPL-2.0
2+
// SPDX-FileCopyrightText: 2026 Mitch Gaffigan <mitch@gaffigan.net>
93

104
package com.mirth.connect.server.launcher;
115

@@ -15,7 +9,6 @@
159
import java.io.IOException;
1610
import java.net.URL;
1711
import java.net.URLClassLoader;
18-
import java.nio.charset.StandardCharsets;
1912
import java.util.ArrayList;
2013
import java.util.Collection;
2114
import java.util.List;
@@ -47,7 +40,6 @@ public class MirthLauncher {
4740
private static final String[] LOG4J_JAR_FILES = { "./server-lib/log4j/log4j-core-2.25.3.jar",
4841
"./server-lib/log4j/log4j-api-2.25.3.jar",
4942
"./server-lib/log4j/log4j-1.2-api-2.25.3.jar" };
50-
private static final String INVALID_LOG4J_PROPERTY = "dir.logs";
5143

5244
private static String appDataDir = null;
5345

@@ -56,7 +48,7 @@ public class MirthLauncher {
5648
public static void main(String[] args) {
5749
JarFile mirthClientCoreJarFile = null;
5850
try {
59-
sanitizeLog4jConfiguration(new File(LOG4J_PROPERTIES_FILE));
51+
Log4jMigrations.migrateConfiguration(new File(LOG4J_PROPERTIES_FILE));
6052

6153
List<URL> classpathUrls = new ArrayList<>();
6254
// Always add log4j
@@ -133,28 +125,6 @@ public static void main(String[] args) {
133125
}
134126
}
135127

136-
private static void sanitizeLog4jConfiguration(File propertiesFile) {
137-
if (!propertiesFile.exists() || !propertiesFile.isFile()) {
138-
return;
139-
}
140-
141-
try {
142-
List<String> lines = FileUtils.readLines(propertiesFile, StandardCharsets.UTF_8);
143-
if (lines.removeIf(MirthLauncher::isInvalidLog4jPropertyLine)) {
144-
FileUtils.writeLines(propertiesFile, StandardCharsets.UTF_8.name(), lines, System.lineSeparator(), false);
145-
}
146-
} catch (IOException e) {
147-
System.err.println("Failed to sanitize Log4j configuration: " + propertiesFile.getAbsolutePath());
148-
e.printStackTrace();
149-
}
150-
}
151-
152-
private static boolean isInvalidLog4jPropertyLine(String line) {
153-
String trimmedLine = line.trim();
154-
int equalsIndex = trimmedLine.indexOf('=');
155-
return equalsIndex >= 0 && trimmedLine.substring(0, equalsIndex).trim().equals(INVALID_LOG4J_PROPERTY);
156-
}
157-
158128
// if we have an uninstall file, uninstall the listed extensions
159129
private static void uninstallPendingExtensions() throws Exception {
160130
File extensionsDir = new File(EXTENSIONS_DIR);
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
// SPDX-FileCopyrightText: 2026 Mitch Gaffigan <mitch@gaffigan.net>
3+
4+
package com.mirth.connect.server.launcher;
5+
6+
import static org.junit.Assert.assertEquals;
7+
import static org.junit.Assert.assertFalse;
8+
import static org.junit.Assert.assertTrue;
9+
10+
import java.io.ByteArrayOutputStream;
11+
import java.io.File;
12+
import java.io.PrintStream;
13+
import java.nio.charset.StandardCharsets;
14+
import java.nio.file.Files;
15+
import java.nio.file.Path;
16+
import java.nio.file.attribute.FileTime;
17+
import java.nio.file.attribute.PosixFilePermission;
18+
import java.util.EnumSet;
19+
import java.util.Set;
20+
21+
import org.junit.Assume;
22+
import org.junit.Test;
23+
24+
public class Log4jMigrationsTest {
25+
26+
@Test
27+
public void testMigrateLog4jRemovesDirLogs() throws Exception {
28+
File file = File.createTempFile("log4j2", ".properties");
29+
file.deleteOnExit();
30+
Files.writeString(file.toPath(), String.join(System.lineSeparator(),
31+
"rootLogger = ERROR,stdout,fout",
32+
"dir.logs = logs",
33+
"property.log.dir = logs",
34+
"appender.rolling.fileName = ${log.dir}/mirth.log"), StandardCharsets.UTF_8);
35+
36+
Log4jMigrations.migrateConfiguration(file);
37+
38+
String fileContents = Files.readString(file.toPath(), StandardCharsets.UTF_8);
39+
assertFalse(fileContents.contains("dir.logs"));
40+
assertTrue(fileContents.contains("property.log.dir = logs"));
41+
assertTrue(fileContents.contains("appender.rolling.fileName = ${log.dir}/mirth.log"));
42+
}
43+
44+
@Test
45+
public void testMigrateLog4jDoesNotRewriteCleanFile() throws Exception {
46+
File file = File.createTempFile("log4j2-clean", ".properties");
47+
file.deleteOnExit();
48+
String contents = String.join(System.lineSeparator(),
49+
"rootLogger = ERROR,stdout,fout",
50+
"property.log.dir = logs",
51+
"appender.rolling.fileName = ${log.dir}/mirth.log");
52+
Files.writeString(file.toPath(), contents, StandardCharsets.UTF_8);
53+
54+
FileTime expectedModifiedTime = FileTime.fromMillis(1_700_000_000_000L);
55+
Files.setLastModifiedTime(file.toPath(), expectedModifiedTime);
56+
57+
Log4jMigrations.migrateConfiguration(file);
58+
59+
assertEquals(expectedModifiedTime, Files.getLastModifiedTime(file.toPath()));
60+
assertEquals(contents, Files.readString(file.toPath(), StandardCharsets.UTF_8));
61+
}
62+
63+
@Test
64+
public void testMigrateLog4jFailsGracefullyWithReadOnlyFile() throws Exception {
65+
File file = File.createTempFile("log4j2-readonly", ".properties");
66+
file.deleteOnExit();
67+
String contents = String.join(System.lineSeparator(),
68+
"rootLogger = ERROR,stdout,fout",
69+
"dir.logs = logs",
70+
"property.log.dir = logs");
71+
Path path = file.toPath();
72+
Files.writeString(path, contents, StandardCharsets.UTF_8);
73+
74+
Assume.assumeTrue(Files.getFileStore(path).supportsFileAttributeView("posix"));
75+
76+
ByteArrayOutputStream errBytes = new ByteArrayOutputStream();
77+
PrintStream originalErr = System.err;
78+
Set<PosixFilePermission> originalPermissions = Files.getPosixFilePermissions(path);
79+
80+
try {
81+
Files.setPosixFilePermissions(path, EnumSet.of(PosixFilePermission.OWNER_READ));
82+
assertFalse(Files.isWritable(path));
83+
System.setErr(new PrintStream(errBytes, true, StandardCharsets.UTF_8.name()));
84+
85+
Log4jMigrations.migrateConfiguration(file);
86+
} finally {
87+
Files.setPosixFilePermissions(path, originalPermissions);
88+
System.setErr(originalErr);
89+
}
90+
91+
String errOutput = errBytes.toString(StandardCharsets.UTF_8.name());
92+
assertTrue(errOutput.contains("Failed to migrate Log4j configuration"));
93+
assertEquals(contents, Files.readString(path, StandardCharsets.UTF_8));
94+
}
95+
96+
@Test
97+
public void testMigrateLog4jIgnoresMissingFile() throws Exception {
98+
File parentDir = Files.createTempDirectory("log4j2-missing").toFile();
99+
parentDir.deleteOnExit();
100+
File file = new File(parentDir, "missing-log4j2.properties");
101+
102+
assertFalse(file.exists());
103+
104+
Log4jMigrations.migrateConfiguration(file);
105+
106+
assertFalse(file.exists());
107+
}
108+
}

server/test/com/mirth/connect/server/launcher/MirthLauncherTest.java

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)