From fcb613e3d60dc4f9cc9e101523426af8a2351c55 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Fri, 2 Feb 2024 18:54:34 +0100 Subject: [PATCH] refactor: Slight refactoring of DependencyLoader class I am too scared on touching too much logic and breaking something as I didn't work on this class or with that library much yet. So I'm just refactoring it a bit not changing a lot of logic --- .../java/com/craftaro/core/SongodaPlugin.java | 6 +- .../craftaro/core/dependency/Dependency.java | 42 +++---- .../core/dependency/DependencyLoader.java | 119 +++++++----------- .../craftaro/core/dependency/Relocation.java | 10 +- 4 files changed, 75 insertions(+), 102 deletions(-) diff --git a/Core/src/main/java/com/craftaro/core/SongodaPlugin.java b/Core/src/main/java/com/craftaro/core/SongodaPlugin.java index 7bbd5c2d..c2c7c22d 100644 --- a/Core/src/main/java/com/craftaro/core/SongodaPlugin.java +++ b/Core/src/main/java/com/craftaro/core/SongodaPlugin.java @@ -122,14 +122,14 @@ public abstract class SongodaPlugin extends JavaPlugin { dependencies.add(new Dependency("https://repo1.maven.org/maven2", "com;zaxxer", "HikariCP", "4.0.3")); dependencies.add(new Dependency("https://repo1.maven.org/maven2", "org;reactivestreams", "reactive-streams", "1.0.2", true)); dependencies.add(new Dependency("https://repo1.maven.org/maven2", "org;jooq", "jooq", "3.14.16", true, - new Relocation("org;reactivestreams", "com.craftaro.third_party.org.reactivestreams")) //Relocate reactive-streams to avoid conflicts + new Relocation("org;reactivestreams", "com.craftaro.third_party.org.reactivestreams")) // Relocate reactive-streams to avoid conflicts ); dependencies.add(new Dependency("https://repo1.maven.org/maven2", "org;mariadb;jdbc", "mariadb-java-client", "3.2.0")); dependencies.add(new Dependency("https://repo1.maven.org/maven2", "com;h2database", "h2", "1.4.200", false, - new Relocation("org;h2", "com;craftaro;third_party;org;h2")) //Custom relocation if the package names not match with the groupId + new Relocation("org;h2", "com;craftaro;third_party;org;h2")) // Custom relocation if the package names not match with the groupId ); dependencies.add(new Dependency("https://repo1.maven.org/maven2", "com;github;cryptomorin", "XSeries", "9.8.0", false, - new Relocation("com;cryptomorin;xseries", "com;craftaro;third_party;com;cryptomorin;xseries")) //Custom relocation if the package names not match with the groupId + new Relocation("com;cryptomorin;xseries", "com;craftaro;third_party;com;cryptomorin;xseries")) // Custom relocation if the package names not match with the groupId ); //Load plugin dependencies diff --git a/Core/src/main/java/com/craftaro/core/dependency/Dependency.java b/Core/src/main/java/com/craftaro/core/dependency/Dependency.java index beb57b64..7076428c 100644 --- a/Core/src/main/java/com/craftaro/core/dependency/Dependency.java +++ b/Core/src/main/java/com/craftaro/core/dependency/Dependency.java @@ -1,13 +1,8 @@ package com.craftaro.core.dependency; -import org.jetbrains.annotations.Nullable; - import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.Objects; public class Dependency { private final String repositoryUrl; @@ -18,35 +13,32 @@ public class Dependency { private final List relocations; /** - * * @param repositoryUrl The repository url to download the dependency from. - * @param groupId The groupId of the dependency. - * @param artifactId The artifactId of the dependency. - * @param version The version of the dependency. + * @param groupId The groupId of the dependency. + * @param artifactId The artifactId of the dependency. + * @param version The version of the dependency. */ public Dependency(String repositoryUrl, String groupId, String artifactId, String version) { this(repositoryUrl, groupId, artifactId, version, true); } /** - * * @param repositoryUrl The repository url to download the dependency from. - * @param groupId The groupId of the dependency. - * @param artifactId The artifactId of the dependency. - * @param version The version of the dependency. - * @param baseRelocate If the dependency should be relocated to com.craftaro.third_party. + * @param groupId The groupId of the dependency. + * @param artifactId The artifactId of the dependency. + * @param version The version of the dependency. + * @param baseRelocate If the dependency should be relocated to com.craftaro.third_party. */ public Dependency(String repositoryUrl, String groupId, String artifactId, String version, boolean baseRelocate) { this(repositoryUrl, groupId, artifactId, version, baseRelocate, new Relocation[0]); } /** - * - * @param repositoryUrl The repository url to download the dependency from. - * @param groupId The groupId of the dependency. - * @param artifactId The artifactId of the dependency. - * @param version The version of the dependency. - * @param baseRelocate If the dependency should be relocated to com.craftaro.third_party. + * @param repositoryUrl The repository url to download the dependency from. + * @param groupId The groupId of the dependency. + * @param artifactId The artifactId of the dependency. + * @param version The version of the dependency. + * @param baseRelocate If the dependency should be relocated to com.craftaro.third_party. * @param extraRelocations Extra relocations to apply to the dependency. */ public Dependency(String repositoryUrl, String groupId, String artifactId, String version, boolean baseRelocate, Relocation... extraRelocations) { @@ -85,6 +77,14 @@ public class Dependency { } public boolean shouldRelocate() { - return this.relocate || !relocations.isEmpty(); + return this.relocate || !this.relocations.isEmpty(); + } + + public String buildArtifactUrl() { + return this.repositoryUrl + "/" + + this.groupId.replace('.', '/') + "/" + + this.artifactId + "/" + + this.version + "/" + + this.artifactId + "-" + this.version + ".jar"; } } diff --git a/Core/src/main/java/com/craftaro/core/dependency/DependencyLoader.java b/Core/src/main/java/com/craftaro/core/dependency/DependencyLoader.java index c1871926..a53dd58d 100644 --- a/Core/src/main/java/com/craftaro/core/dependency/DependencyLoader.java +++ b/Core/src/main/java/com/craftaro/core/dependency/DependencyLoader.java @@ -10,11 +10,10 @@ import me.lucko.jarrelocator.Relocation; import org.bukkit.plugin.Plugin; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.net.URLConnection; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; @@ -42,135 +41,109 @@ public class DependencyLoader { } public void loadDependency(Dependency dependency) throws IOException { - String repositoryUrl = dependency.getRepositoryUrl(); - String groupId = dependency.getGroupId(); - String artifactId = dependency.getArtifactId(); - String version = dependency.getVersion(); - //Download dependency from the repositoryUrl - //Check if we have the dependency downloaded already String name = dependency.getArtifactId() + "-" + dependency.getVersion(); - File outputFile = new File(this.libraryLoader.getLibFolder(), dependency.getGroupId().replace(".", File.separator) + File.separator + dependency.getArtifactId().replace(".", File.separator) + File.separator + dependency.getVersion() + File.separator + "raw-" + name + ".jar"); File relocatedFile = new File(outputFile.getParentFile(), name.replace("raw-", "") + ".jar"); if (relocatedFile.exists()) { - //Check if the file is already loaded to the classpath if (isLoaded(relocatedFile)) { return; } - //Load dependency into the classpath loadJarIntoClasspath(relocatedFile, dependency); return; } - SongodaCore.getLogger().info("Downloading dependency " + groupId + ":" + artifactId + ":" + version + " from " + repositoryUrl); - // Construct the URL for the artifact in the Maven repository - String artifactUrl = repositoryUrl + "/" + - groupId.replace('.', '/') + "/" + - artifactId + "/" + - version + "/" + - artifactId + "-" + version + ".jar"; - - URL url = new URL(artifactUrl); - URLConnection connection = url.openConnection(); - InputStream in = connection.getInputStream(); - - // Define the output file - - outputFile.getParentFile().mkdirs(); - FileOutputStream out = new FileOutputStream(outputFile); - - // Read from the input stream and write to the output stream - byte[] buffer = new byte[1024]; - int length; - while ((length = in.read(buffer)) != -1) { - out.write(buffer, 0, length); + SongodaCore.getLogger().info(String.format("Downloading dependency %s:%s:%s from %s", dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), dependency.getRepositoryUrl())); + Files.createDirectories(outputFile.getParentFile().toPath()); + try (InputStream is = new URL(dependency.buildArtifactUrl()).openStream()) { + Files.copy(is, outputFile.toPath()); } - // Close both streams - in.close(); - out.close(); - - //Load dependency into the classpath - SongodaCore.getLogger().info("Downloaded dependency " + groupId + ":" + artifactId + ":" + version); loadJarIntoClasspath(outputFile, dependency); } public void loadJarIntoClasspath(File file, Dependency dependency) throws IOException { if (!isRelocated(file) && dependency.shouldRelocate()) { SongodaCore.getLogger().info("Loading dependency for relocation " + file); - //relocate package to com.craftaro.core.third_party to avoid conflicts + // relocate package to com.craftaro.core.third_party to avoid conflicts List relocations = new ArrayList<>(); for (com.craftaro.core.dependency.Relocation r : dependency.getRelocations()) { relocations.add(new Relocation(r.getFrom(), r.getTo())); } - //Relocate the classes + // Relocate the classes File finalJar = new File(file.getParentFile(), file.getName().replace("raw-", "")); JarRelocator relocator = new JarRelocator(file, finalJar, relocations); try { relocator.run(); SongodaCore.getLogger().info("Relocated dependency " + file); - //Delete the old jar - file.delete(); - } catch (Exception e) { - SongodaCore.getLogger().severe("Failed to relocate dependency1 " + file); - if (e.getMessage().contains("zip file is empty")) { - SongodaCore.getLogger().severe("Try deleting the 'server root/craftaro' folder and restarting the server"); - } - //Delete the new jar cuz it's probably corrupted - finalJar.delete(); + // Delete the old jar + Files.deleteIfExists(file.toPath()); + } catch (Exception e) { + SongodaCore.getLogger().severe("Failed to relocate dependency " + file); + if (e.getMessage().contains("zip file is empty")) { + SongodaCore.getLogger().severe("Try deleting '" + this.libraryLoader.getLibFolder().getParent() + "' and restarting the server"); + } + + // Delete the new jar cuz it's probably corrupted + Files.deleteIfExists(finalJar.toPath()); throw e; } - } + try { this.libraryLoader.load(new LibraryLoader.Dependency(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), dependency.getRepositoryUrl()), true); } catch (InvalidDependencyException ignored) { - //already loaded + // Already loaded } catch (UnknownDependencyException ex) { throw new RuntimeException(ex); } SongodaCore.getLogger().info("----------------------------"); } - private boolean isRelocated(File file) throws IOException { - try (ZipFile zipFile = new ZipFile(file)) { - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - + private boolean isRelocated(File jarFile) throws IOException { + try (ZipFile zipFile = new ZipFile(jarFile)) { + Enumeration zipEntries = zipFile.entries(); + while (zipEntries.hasMoreElements()) { + ZipEntry entry = zipEntries.nextElement(); if (entry.getName().startsWith("com/craftaro/third_party")) { return true; } } } + return false; } - private boolean isLoaded(File file) throws IOException { - //Find the first class file in the jar and try Class.forName - try (ZipFile zipFile = new ZipFile(file)) { - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - if (entry.getName().startsWith("META-INF")) { + /** + * Finds the first .class file in the jar and check if it's loaded + */ + private boolean isLoaded(File jarFile) throws IOException { + try (ZipFile zipFile = new ZipFile(jarFile)) { + Enumeration zipEntries = zipFile.entries(); + while (zipEntries.hasMoreElements()) { + ZipEntry zipEntry = zipEntries.nextElement(); + if (zipEntry.getName().startsWith("META-INF")) { + continue; + } + if (!zipEntry.getName().endsWith(".class")) { continue; } - if (entry.getName().endsWith(".class")) { - String className = entry.getName().replace("/", ".").replace(".class", ""); - try { - Class.forName(className); - return true; - } catch (Exception | Error e) { - return false; - } + String className = zipEntry.getName() + .substring(0, zipEntry.getName().length() - ".class".length()) + .replace("/", "."); + try { + Class.forName(className); + return true; + } catch (Throwable th) { + return false; } } } + return false; } diff --git a/Core/src/main/java/com/craftaro/core/dependency/Relocation.java b/Core/src/main/java/com/craftaro/core/dependency/Relocation.java index 8d533663..2e135641 100644 --- a/Core/src/main/java/com/craftaro/core/dependency/Relocation.java +++ b/Core/src/main/java/com/craftaro/core/dependency/Relocation.java @@ -1,26 +1,26 @@ package com.craftaro.core.dependency; public class Relocation { - private final String from; private final String to; public Relocation(String from, String to) { if (from == null) { - throw new IllegalArgumentException("from cannot be null"); + throw new IllegalArgumentException("'from' cannot be null"); } if (to == null) { - throw new IllegalArgumentException("to cannot be null"); + throw new IllegalArgumentException("'to' cannot be null"); } + this.from = from.replaceAll(";", "."); this.to = to.replaceAll(";", "."); } public String getFrom() { - return from; + return this.from; } public String getTo() { - return to; + return this.to; } }