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
This commit is contained in:
Christian Koop 2024-02-02 18:54:34 +01:00
parent 193af915e9
commit fcb613e3d6
No known key found for this signature in database
GPG Key ID: 89A8181384E010A3
4 changed files with 75 additions and 102 deletions

View File

@ -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

View File

@ -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<Relocation> 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";
}
}

View File

@ -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<Relocation> 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<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
private boolean isRelocated(File jarFile) throws IOException {
try (ZipFile zipFile = new ZipFile(jarFile)) {
Enumeration<? extends ZipEntry> 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<? extends ZipEntry> 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<? extends ZipEntry> 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;
}

View File

@ -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;
}
}