From ece5b6d992fc479c5a97834d17055ca4da970007 Mon Sep 17 00:00:00 2001 From: federico Date: Tue, 22 Sep 2026 21:39:26 +0800 Subject: [PATCH 1/2] fix(config): close resource streams on release v4.8.3 Port the remaining changes from Federico2014/java-tron#48 (9bbf15fa74813b575d48cfdbb07787f56e918ed1). Skip GetTransactionByIdSolidityServletTest because release_v4.8.3 replaced its file-backed response handling in 0d19485318. Preserve the updated BroadcastServletTest error-response assertion. --- .../org/tron/core/config/Configuration.java | 3 +- .../java/org/tron/core/config/args/Args.java | 10 +++---- .../org/tron/core/zen/ZksnarkInitService.java | 9 ++++-- .../org/tron/common/utils/FileUtilTest.java | 28 ++++++++----------- .../services/http/BroadcastServletTest.java | 16 +++++------ .../org/tron/plugins/utils/FileUtils.java | 13 ++++++--- 6 files changed, 40 insertions(+), 39 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/Configuration.java b/common/src/main/java/org/tron/core/config/Configuration.java index 80735290b8c..a36c9825470 100644 --- a/common/src/main/java/org/tron/core/config/Configuration.java +++ b/common/src/main/java/org/tron/core/config/Configuration.java @@ -50,7 +50,7 @@ private static void resolveConfigFile(String fileName, File confFile) { if (confFile.exists()) { config = ConfigFactory.parseFile(confFile) .withFallback(ConfigFactory.defaultReference()); - } else if (Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName) + } else if (Thread.currentThread().getContextClassLoader().getResource(fileName) != null) { config = ConfigFactory.load(fileName); } else { @@ -59,4 +59,3 @@ private static void resolveConfigFile(String fileName, File confFile) { } } } - diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 8d56a2193f0..b47ef76657b 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -1188,9 +1188,8 @@ public String getOutputDirectory() { private static void printVersion() { Properties properties = new Properties(); boolean noGitProperties = true; - try { - InputStream in = Thread.currentThread() - .getContextClassLoader().getResourceAsStream("git.properties"); + try (InputStream in = Thread.currentThread() + .getContextClassLoader().getResourceAsStream("git.properties")) { if (in != null) { noGitProperties = false; properties.load(in); @@ -1278,9 +1277,8 @@ public static String upperFirst(String name) { private static String getCommitIdAbbrev() { Properties properties = new Properties(); - try { - InputStream in = Thread.currentThread() - .getContextClassLoader().getResourceAsStream("git.properties"); + try (InputStream in = Thread.currentThread() + .getContextClassLoader().getResourceAsStream("git.properties")) { if (in == null) { logger.warn("git.properties not found on classpath"); return ""; diff --git a/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java b/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java index dfc4b428836..e0748e99f3b 100644 --- a/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java +++ b/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java @@ -57,11 +57,14 @@ public static void librustzcashInitZksnarkParams() { } private static String getParamsFile(String fileName) { - InputStream in = Thread.currentThread().getContextClassLoader() - .getResourceAsStream("params" + File.separator + fileName); + String resourcePath = "params" + File.separator + fileName; File fileOut = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName + "." + System.currentTimeMillis()); - try { + try (InputStream in = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(resourcePath)) { + if (in == null) { + throw new IllegalStateException("Resource not found: " + resourcePath); + } FileUtils.copyToFile(in, fileOut); } catch (IOException e) { logger.error(e.getMessage(), e); diff --git a/framework/src/test/java/org/tron/common/utils/FileUtilTest.java b/framework/src/test/java/org/tron/common/utils/FileUtilTest.java index c22e83760a1..b062c8c394e 100644 --- a/framework/src/test/java/org/tron/common/utils/FileUtilTest.java +++ b/framework/src/test/java/org/tron/common/utils/FileUtilTest.java @@ -8,18 +8,13 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.stream.Stream; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -39,15 +34,16 @@ public void setUp() throws IOException { @After public void tearDown() throws IOException { - Files.walk(tempDir) - .sorted(Comparator.reverseOrder()) - .forEach(path -> { - try { - Files.delete(path); - } catch (IOException e) { - e.printStackTrace(); - } - }); + try (Stream paths = Files.walk(tempDir)) { + paths.sorted(Comparator.reverseOrder()) + .forEach(path -> { + try { + Files.delete(path); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } } @Test @@ -126,4 +122,4 @@ public void testCreateDirIfNotExists() { } -} \ No newline at end of file +} diff --git a/framework/src/test/java/org/tron/core/services/http/BroadcastServletTest.java b/framework/src/test/java/org/tron/core/services/http/BroadcastServletTest.java index 532ddcd5521..da04563bf94 100644 --- a/framework/src/test/java/org/tron/core/services/http/BroadcastServletTest.java +++ b/framework/src/test/java/org/tron/core/services/http/BroadcastServletTest.java @@ -146,17 +146,17 @@ public void doPostTest() throws IOException { } Assert.assertNotNull(result); in.close(); - writer.flush(); - FileInputStream fileInputStream = new FileInputStream("temp.txt"); - InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + writer.close(); StringBuilder sb = new StringBuilder(); - String text; - while ((text = bufferedReader.readLine()) != null) { - sb.append(text); + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( + new FileInputStream("temp.txt"), StandardCharsets.UTF_8))) { + String text; + while ((text = bufferedReader.readLine()) != null) { + sb.append(text); + } } Assert.assertTrue(sb.toString().contains("{\"Error\":\"internal server error\"}")); httpUrlConnection.disconnect(); } -} \ No newline at end of file +} diff --git a/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java b/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java index b07b4469dc3..04b2efa476a 100644 --- a/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java +++ b/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java @@ -20,6 +20,7 @@ import java.nio.file.StandardCopyOption; import java.util.List; import java.util.Properties; +import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -141,8 +142,10 @@ public static void copyDatabases(Path src, Path dest, List subDirs) subDirs.forEach(dir -> { if (isExists(Paths.get(src.toString(), dir).toString())) { try { - Files.walk(Paths.get(src.toString(), dir), FileVisitOption.FOLLOW_LINKS) - .forEach(source -> copy(source, dest.resolve(src.relativize(source)))); + try (Stream paths = Files.walk( + Paths.get(src.toString(), dir), FileVisitOption.FOLLOW_LINKS)) { + paths.forEach(source -> copy(source, dest.resolve(src.relativize(source)))); + } } catch (IOException e) { logger.error("copy database failed, src: {}, dest: {}, error: {}", Paths.get(src.toString(), dir), Paths.get(dest.toString(), dir), e.getMessage()); @@ -156,8 +159,10 @@ public static void copyDir(Path src, Path dest, String dir) { if (isExists(Paths.get(src.toString(), dir).toString())) { try { if (createDirIfNotExists(Paths.get(dest.toString(), dir).toString())) { - Files.walk(Paths.get(src.toString(), dir), FileVisitOption.FOLLOW_LINKS) - .forEach(source -> copy(source, dest.resolve(src.relativize(source)))); + try (Stream paths = Files.walk( + Paths.get(src.toString(), dir), FileVisitOption.FOLLOW_LINKS)) { + paths.forEach(source -> copy(source, dest.resolve(src.relativize(source)))); + } } else { throw new IOException(String.format("dest %s create fail ", Paths.get(dest.toString(), dir))); From a78fdcf0f11fd8636dcc4bb6f9a8dbb605fbfc40 Mon Sep 17 00:00:00 2001 From: federico Date: Tue, 29 Sep 2026 10:48:04 +0800 Subject: [PATCH 2/2] refactor(plugins): share directory traversal --- .../org/tron/plugins/utils/FileUtils.java | 57 +++++------ .../org/tron/plugins/utils/FileUtilsTest.java | 99 +++++++++++++++++++ 2 files changed, 128 insertions(+), 28 deletions(-) create mode 100644 plugins/src/test/java/org/tron/plugins/utils/FileUtilsTest.java diff --git a/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java b/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java index 04b2efa476a..4bf41bb4d70 100644 --- a/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java +++ b/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java @@ -138,43 +138,44 @@ public static boolean isSymbolicLink(File file) throws IOException { */ public static void copyDatabases(Path src, Path dest, List subDirs) throws IOException { - // create subdirs, as using parallel() to run, so should create dirs first. - subDirs.forEach(dir -> { - if (isExists(Paths.get(src.toString(), dir).toString())) { - try { - try (Stream paths = Files.walk( - Paths.get(src.toString(), dir), FileVisitOption.FOLLOW_LINKS)) { - paths.forEach(source -> copy(source, dest.resolve(src.relativize(source)))); - } - } catch (IOException e) { - logger.error("copy database failed, src: {}, dest: {}, error: {}", - Paths.get(src.toString(), dir), Paths.get(dest.toString(), dir), e.getMessage()); - throw new RuntimeException(e); - } + for (String dir : subDirs) { + if (!isExists(Paths.get(src.toString(), dir).toString())) { + continue; } - }); - } - - public static void copyDir(Path src, Path dest, String dir) { - if (isExists(Paths.get(src.toString(), dir).toString())) { try { - if (createDirIfNotExists(Paths.get(dest.toString(), dir).toString())) { - try (Stream paths = Files.walk( - Paths.get(src.toString(), dir), FileVisitOption.FOLLOW_LINKS)) { - paths.forEach(source -> copy(source, dest.resolve(src.relativize(source)))); - } - } else { - throw new IOException(String.format("dest %s create fail ", - Paths.get(dest.toString(), dir))); - } + copyTree(src, dest, dir); } catch (IOException e) { - logger.error("copy dir failed, src: {}, dest: {}, error: {}", + logger.error("copy database failed, src: {}, dest: {}, error: {}", Paths.get(src.toString(), dir), Paths.get(dest.toString(), dir), e.getMessage()); throw new RuntimeException(e); } } } + public static void copyDir(Path src, Path dest, String dir) { + if (!isExists(Paths.get(src.toString(), dir).toString())) { + return; + } + try { + if (!createDirIfNotExists(Paths.get(dest.toString(), dir).toString())) { + throw new IOException(String.format("dest %s create fail ", + Paths.get(dest.toString(), dir))); + } + copyTree(src, dest, dir); + } catch (IOException e) { + logger.error("copy dir failed, src: {}, dest: {}, error: {}", + Paths.get(src.toString(), dir), Paths.get(dest.toString(), dir), e.getMessage()); + throw new RuntimeException(e); + } + } + + private static void copyTree(Path src, Path dest, String dir) throws IOException { + try (Stream paths = Files.walk( + Paths.get(src.toString(), dir), FileVisitOption.FOLLOW_LINKS)) { + paths.forEach(source -> copy(source, dest.resolve(src.relativize(source)))); + } + } + public static void copy(Path source, Path dest) { try { // create hard link when file is .sst diff --git a/plugins/src/test/java/org/tron/plugins/utils/FileUtilsTest.java b/plugins/src/test/java/org/tron/plugins/utils/FileUtilsTest.java new file mode 100644 index 00000000000..ed50cc8b5af --- /dev/null +++ b/plugins/src/test/java/org/tron/plugins/utils/FileUtilsTest.java @@ -0,0 +1,99 @@ +package org.tron.plugins.utils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class FileUtilsTest { + + @Rule + public final TemporaryFolder folder = new TemporaryFolder(); + + @Test + public void testCopyDatabasesCopiesTreeAfterMissingDirectory() throws IOException { + Path src = createSourceTree(); + Path dest = folder.newFolder().toPath(); + + FileUtils.copyDatabases(src, dest, Arrays.asList("missing", "database")); + + Assert.assertFalse(Files.exists(dest.resolve("missing"))); + Assert.assertArrayEquals(new byte[]{1, 2, 3}, + Files.readAllBytes(dest.resolve("database/nested/data"))); + } + + @Test + public void testCopyMethodsSkipMissingSource() throws IOException { + Path src = folder.newFolder().toPath(); + Path dest = folder.getRoot().toPath().resolve("missing-dest"); + + FileUtils.copyDatabases(src, dest, Collections.singletonList("missing")); + FileUtils.copyDir(src, dest, "missing"); + + Assert.assertFalse(Files.exists(dest)); + } + + @Test + public void testCopyDatabasesDoesNotCreateDestinationParents() throws IOException { + Path src = createSourceTree(); + Path dest = folder.getRoot().toPath().resolve("missing-parent/dest"); + + RuntimeException error = Assert.assertThrows(RuntimeException.class, + () -> FileUtils.copyDatabases(src, dest, Collections.singletonList("database"))); + + Assert.assertTrue(error.getCause() instanceof IOException); + Assert.assertFalse(Files.exists(dest.getParent())); + } + + @Test + public void testCopyDirCreatesDestinationParents() throws IOException { + Path src = createSourceTree(); + Path dest = folder.getRoot().toPath().resolve("missing-parent/dest"); + + FileUtils.copyDir(src, dest, "database"); + + Assert.assertArrayEquals(new byte[]{1, 2, 3}, + Files.readAllBytes(dest.resolve("database/nested/data"))); + } + + @Test + public void testCopyMethodsPreserveLeadingSeparatorInDirectory() throws IOException { + Path src = createSourceTree(); + Path databasesDest = folder.newFolder().toPath(); + Path directoryDest = folder.newFolder().toPath(); + String dir = File.separator + "database"; + + FileUtils.copyDatabases(src, databasesDest, Collections.singletonList(dir)); + FileUtils.copyDir(src, directoryDest, dir); + + Assert.assertArrayEquals(new byte[]{1, 2, 3}, + Files.readAllBytes(databasesDest.resolve("database/nested/data"))); + Assert.assertArrayEquals(new byte[]{1, 2, 3}, + Files.readAllBytes(directoryDest.resolve("database/nested/data"))); + } + + @Test + public void testCopyDirWrapsDestinationCreationFailure() throws IOException { + Path src = createSourceTree(); + Path dest = folder.newFile().toPath(); + + RuntimeException error = Assert.assertThrows(RuntimeException.class, + () -> FileUtils.copyDir(src, dest, "database")); + + Assert.assertTrue(error.getCause() instanceof IOException); + Assert.assertTrue(error.getCause().getMessage().contains("create fail")); + } + + private Path createSourceTree() throws IOException { + Path src = folder.newFolder().toPath(); + Path nested = Files.createDirectories(src.resolve("database/nested")); + Files.write(nested.resolve("data"), new byte[]{1, 2, 3}); + return src; + } +}