diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 8dd5d34a2..c8e27c3f5 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -45,10 +45,65 @@
false
false
+
net.kyori.text
me.lucko.luckperms.lib.text
+
+ me.lucko.jarreloator
+ me.lucko.luckperms.lib.jarreloator
+
+
+
+
+ com.github.benmanes.caffeine
+ me.lucko.luckperms.lib.caffeine
+
+
+ org.mariadb.jdbc
+ me.lucko.luckperms.lib.mariadb
+
+
+ com.mysql
+ me.lucko.luckperms.lib.mysql
+
+
+ org.postgresql
+ me.lucko.luckperms.lib.postgresql
+
+
+ org.h2
+ me.lucko.luckperms.lib.h2
+
+
+ org.sqlite
+ me.lucko.luckperms.lib.sqlite
+
+
+ com.zaxxer.hikari
+ me.lucko.luckperms.lib.hikari
+
+
+ com.mongodb
+ me.lucko.luckperms.lib.mongodb
+
+
+ org.bson
+ me.lucko.luckperms.lib.bson
+
+
+ redis.clients.jedis.shaded
+ me.lucko.luckperms.lib.jedis
+
+
+ ninja.leaping.configurate
+ me.lucko.luckperms.lib.configurate
+
+
+ com.typesafe.config
+ me.lucko.luckperms.lib.hocon
+
diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java
index bd5686749..79d248aed 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java
@@ -57,6 +57,8 @@ import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.contexts.LuckPermsCalculator;
import me.lucko.luckperms.common.dependencies.Dependency;
import me.lucko.luckperms.common.dependencies.DependencyManager;
+import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
+import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
import me.lucko.luckperms.common.event.EventFactory;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.NoopLocaleManager;
@@ -124,6 +126,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private DefaultsProvider defaultsProvider;
private ChildPermissionProvider childPermissionProvider;
private LocaleManager localeManager;
+ private PluginClassLoader pluginClassLoader;
private DependencyManager dependencyManager;
private CachedStateManager cachedStateManager;
private ContextManager contextManager;
@@ -151,6 +154,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
this.senderFactory = new BukkitSenderFactory(this);
this.log = new SenderLogger(this, getConsoleSender());
+ this.pluginClassLoader = new ReflectionClassLoader(this);
this.dependencyManager = new DependencyManager(this);
this.dependencyManager.loadDependencies(Collections.singleton(Dependency.CAFFEINE));
}
@@ -633,6 +637,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return this.localeManager;
}
+ @Override
+ public PluginClassLoader getPluginClassLoader() {
+ return this.pluginClassLoader;
+ }
+
@Override
public DependencyManager getDependencyManager() {
return this.dependencyManager;
diff --git a/bungee/pom.xml b/bungee/pom.xml
index 1e2b1508d..9a13c36fc 100644
--- a/bungee/pom.xml
+++ b/bungee/pom.xml
@@ -45,10 +45,65 @@
false
false
+
net.kyori.text
me.lucko.luckperms.lib.text
+
+ me.lucko.jarreloator
+ me.lucko.luckperms.lib.jarreloator
+
+
+
+
+ com.github.benmanes.caffeine
+ me.lucko.luckperms.lib.caffeine
+
+
+ org.mariadb.jdbc
+ me.lucko.luckperms.lib.mariadb
+
+
+ com.mysql
+ me.lucko.luckperms.lib.mysql
+
+
+ org.postgresql
+ me.lucko.luckperms.lib.postgresql
+
+
+ org.h2
+ me.lucko.luckperms.lib.h2
+
+
+ org.sqlite
+ me.lucko.luckperms.lib.sqlite
+
+
+ com.zaxxer.hikari
+ me.lucko.luckperms.lib.hikari
+
+
+ com.mongodb
+ me.lucko.luckperms.lib.mongodb
+
+
+ org.bson
+ me.lucko.luckperms.lib.bson
+
+
+ redis.clients.jedis.shaded
+ me.lucko.luckperms.lib.jedis
+
+
+ ninja.leaping.configurate
+ me.lucko.luckperms.lib.configurate
+
+
+ com.typesafe.config
+ me.lucko.luckperms.lib.hocon
+
diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java
index 6db8cd13b..118ac3eb9 100644
--- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java
+++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java
@@ -51,6 +51,8 @@ import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.contexts.LuckPermsCalculator;
import me.lucko.luckperms.common.dependencies.Dependency;
import me.lucko.luckperms.common.dependencies.DependencyManager;
+import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
+import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
import me.lucko.luckperms.common.event.EventFactory;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.NoopLocaleManager;
@@ -109,6 +111,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private EventFactory eventFactory;
private Logger log;
private LocaleManager localeManager;
+ private PluginClassLoader pluginClassLoader;
private DependencyManager dependencyManager;
private CachedStateManager cachedStateManager;
private ContextManager contextManager;
@@ -128,6 +131,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
this.senderFactory = new BungeeSenderFactory(this);
this.log = new SenderLogger(this, getConsoleSender());
+ this.pluginClassLoader = new ReflectionClassLoader(this);
this.dependencyManager = new DependencyManager(this);
this.dependencyManager.loadDependencies(Collections.singleton(Dependency.CAFFEINE));
}
@@ -435,6 +439,11 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return this.localeManager;
}
+ @Override
+ public PluginClassLoader getPluginClassLoader() {
+ return this.pluginClassLoader;
+ }
+
@Override
public DependencyManager getDependencyManager() {
return this.dependencyManager;
diff --git a/common/pom.xml b/common/pom.xml
index 30379d12c..903be4885 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -44,6 +44,24 @@
provided
+
+
+ me.lucko
+ jar-relocator
+ 1.1
+ compile
+
+
+ org.ow2.asm
+ asm
+
+
+ org.ow2.asm
+ asm-commons
+
+
+
+
net.kyori
diff --git a/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java b/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java
index 02420e342..6eba82e0a 100644
--- a/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java
+++ b/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java
@@ -25,57 +25,83 @@
package me.lucko.luckperms.common.dependencies;
+import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
+import me.lucko.jarreloator.Relocation;
+import me.lucko.luckperms.common.dependencies.relocation.Relocations;
+
import java.io.InputStream;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
public enum Dependency {
+ ASM(
+ "org.ow2.asm",
+ "asm",
+ "5.2",
+ "Pl6g19osUVXvT0cNkJLULeNOP1PbZYnHwH1nIa30uj4="
+ ),
+ ASM_COMMONS(
+ "org.ow2.asm",
+ "asm-commons",
+ "5.2",
+ "zBMYiX4sdxy3l6aNX06mQcI6UfBDfKUXq+z5ZN2yZAs="
+ ),
+
CAFFEINE(
- "com.github.ben-manes.caffeine",
+ "com{}github{}ben-manes{}caffeine",
"caffeine",
"2.6.0",
- "JmT16VQnCnVBAjRJCQkkkjmSVx2jajpzeBuKwpbzDA8="
+ "JmT16VQnCnVBAjRJCQkkkjmSVx2jajpzeBuKwpbzDA8=",
+ Relocations.of("caffeine", "com{}github{}benmanes{}caffeine")
),
MARIADB_DRIVER(
- "org.mariadb.jdbc",
+ "org{}mariadb{}jdbc",
"mariadb-java-client",
"2.2.0",
- "/q0LPGHrp3L9rvKr7TuA6urbtXBqvXis92mP4KhxzUw="
+ "/q0LPGHrp3L9rvKr7TuA6urbtXBqvXis92mP4KhxzUw=",
+ Relocations.of("mariadb", "org{}mariadb{}jdbc")
),
MYSQL_DRIVER(
"mysql",
"mysql-connector-java",
"5.1.44",
- "d4RZVzTeWpoHBPB/tQP3mSafNy7L9MDUSOt4Ku9LGCc="
+ "d4RZVzTeWpoHBPB/tQP3mSafNy7L9MDUSOt4Ku9LGCc=",
+ Relocations.of("mysql", "com{}mysql")
),
POSTGRESQL_DRIVER(
- "org.postgresql",
+ "org{}postgresql",
"postgresql",
"9.4.1212",
- "DLKhWL4xrPIY4KThjI89usaKO8NIBkaHc/xECUsMNl0="
+ "DLKhWL4xrPIY4KThjI89usaKO8NIBkaHc/xECUsMNl0=",
+ Relocations.of("postgresql", "org{}postgresql")
),
H2_DRIVER(
"com.h2database",
"h2",
"1.4.196",
- "CgX0oNW4WEAUiq3OY6QjtdPDbvRHVjibT6rQjScz+vU="
+ "CgX0oNW4WEAUiq3OY6QjtdPDbvRHVjibT6rQjScz+vU=",
+ Relocations.of("h2", "org{}h2")
),
SQLITE_DRIVER(
"org.xerial",
"sqlite-jdbc",
"3.21.0",
- "bglRaH4Y+vQFZV7TfOdsVLO3rJpauJ+IwjuRULAb45Y="
+ "bglRaH4Y+vQFZV7TfOdsVLO3rJpauJ+IwjuRULAb45Y=",
+ Relocations.of("sqlite", "org{}sqlite")
),
HIKARI(
- "com.zaxxer",
+ "com{}zaxxer",
"HikariCP",
"2.7.4",
- "y9JE6/VmbydCqlV1z468+oqdkBswBk6aw+ECT178AT4="
+ "y9JE6/VmbydCqlV1z468+oqdkBswBk6aw+ECT178AT4=",
+ Relocations.of("hikari", "com{}zaxxer{}hikari")
),
SLF4J_SIMPLE(
"org.slf4j",
@@ -93,58 +119,90 @@ public enum Dependency {
"org.mongodb",
"mongo-java-driver",
"3.5.0",
- "gxrbKVSI/xM6r+6uL7g7I0DzNV+hlNTtfw4UL13XdK8="
+ "gxrbKVSI/xM6r+6uL7g7I0DzNV+hlNTtfw4UL13XdK8=",
+ ImmutableList.builder()
+ .addAll(Relocations.of("mongodb", "com{}mongodb"))
+ .addAll(Relocations.of("bson", "org{}bson"))
+ .build()
),
JEDIS(
"https://github.com/lucko/jedis/releases/download/jedis-2.9.1-shaded/jedis-2.9.1-shaded.jar",
"2.9.1-shaded",
- "mM19X6LyD97KP4RSbcCR5BTRAwQ0x9y02voX7ePOSjE="
+ "mM19X6LyD97KP4RSbcCR5BTRAwQ0x9y02voX7ePOSjE=",
+ Relocations.of("jedis", "redis{}clients{}jedis{}shaded")
),
CONFIGURATE_CORE(
- "ninja.leaping.configurate",
+ "ninja{}leaping{}configurate",
"configurate-core",
"3.3",
- "4leBJEqj1kVszaifZeKNl4hgHxG5M+Nk5TJKkPW2s4Y="
+ "4leBJEqj1kVszaifZeKNl4hgHxG5M+Nk5TJKkPW2s4Y=",
+ Relocations.of("configurate", "ninja{}leaping{}configurate")
),
CONFIGURATE_GSON(
- "ninja.leaping.configurate",
+ "ninja{}leaping{}configurate",
"configurate-gson",
"3.3",
- "4HxrW3/ZKdn095x/W4gylQMNskdmteXYVxVv0UKGJA4="
+ "4HxrW3/ZKdn095x/W4gylQMNskdmteXYVxVv0UKGJA4=",
+ Relocations.of("configurate", "ninja{}leaping{}configurate")
),
CONFIGURATE_YAML(
- "ninja.leaping.configurate",
+ "ninja{}leaping{}configurate",
"configurate-yaml",
"3.3",
- "hgADp3g+xHHPD34bAuxMWtB+OQ718Tlw69jVp2KPJNk="
+ "hgADp3g+xHHPD34bAuxMWtB+OQ718Tlw69jVp2KPJNk=",
+ Relocations.of("configurate", "ninja{}leaping{}configurate")
),
CONFIGURATE_HOCON(
- "ninja.leaping.configurate",
+ "ninja{}leaping{}configurate",
"configurate-hocon",
"3.3",
- "UIy5FVmsBUG6+Z1mpIEE2EXgtOI1ZL0p/eEW+BbtGLU="
+ "UIy5FVmsBUG6+Z1mpIEE2EXgtOI1ZL0p/eEW+BbtGLU=",
+ ImmutableList.builder()
+ .addAll(Relocations.of("configurate", "ninja{}leaping{}configurate"))
+ .addAll(Relocations.of("hocon", "com{}typesafe{}config"))
+ .build()
),
HOCON_CONFIG(
- "com.typesafe",
+ "com{}typesafe",
"config",
"1.3.1",
- "5vrfxhCCINOmuGqn5OFsnnu4V7pYlViGMIuxOXImSvA="
+ "5vrfxhCCINOmuGqn5OFsnnu4V7pYlViGMIuxOXImSvA=",
+ Relocations.of("hocon", "com{}typesafe{}config")
);
private final String url;
private final String version;
private final byte[] checksum;
+ private final List relocations;
private static final String MAVEN_CENTRAL_FORMAT = "https://repo1.maven.org/maven2/%s/%s/%s/%s-%s.jar";
Dependency(String groupId, String artifactId, String version, String checksum) {
- this(String.format(MAVEN_CENTRAL_FORMAT, groupId.replace(".", "/"), artifactId, version, artifactId, version), version, checksum);
+ this(groupId, artifactId, version, checksum, Collections.emptyList());
}
- Dependency(String url, String version, String checksum) {
+ Dependency(String groupId, String artifactId, String version, String checksum, List relocations) {
+ this(
+ String.format(MAVEN_CENTRAL_FORMAT,
+ rewriteEscaping(groupId).replace(".", "/"),
+ rewriteEscaping(artifactId),
+ version,
+ rewriteEscaping(artifactId),
+ version
+ ),
+ version, checksum, relocations
+ );
+ }
+
+ Dependency(String url, String version, String checksum, List relocations) {
this.url = url;
this.version = version;
this.checksum = Base64.getDecoder().decode(checksum);
+ this.relocations = relocations;
+ }
+
+ private static String rewriteEscaping(String s) {
+ return s.replace("{}", ".");
}
public static void main(String[] args) throws Exception {
@@ -180,4 +238,8 @@ public enum Dependency {
public byte[] getChecksum() {
return this.checksum;
}
+
+ public List getRelocations() {
+ return this.relocations;
+ }
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java b/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java
index 071ae8a6a..0cac64fa1 100644
--- a/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java
+++ b/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java
@@ -25,64 +25,34 @@
package me.lucko.luckperms.common.dependencies;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
-import me.lucko.luckperms.api.platform.PlatformType;
-import me.lucko.luckperms.common.config.ConfigKeys;
+import me.lucko.jarreloator.JarRelocator;
+import me.lucko.jarreloator.Relocation;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.StorageType;
import java.io.File;
import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLClassLoader;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
-import java.util.LinkedHashSet;
+import java.util.EnumSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
* Responsible for loading runtime dependencies.
*/
public class DependencyManager {
- private static final Method ADD_URL_METHOD;
-
- static {
- Method addUrlMethod;
- try {
- addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
- addUrlMethod.setAccessible(true);
- } catch (NoSuchMethodException e) {
- throw new ExceptionInInitializerError(e);
- }
- ADD_URL_METHOD = addUrlMethod;
- }
-
- private static final Map> STORAGE_DEPENDENCIES = ImmutableMap.>builder()
- .put(StorageType.JSON, ImmutableList.of(Dependency.CONFIGURATE_CORE, Dependency.CONFIGURATE_GSON))
- .put(StorageType.YAML, ImmutableList.of(Dependency.CONFIGURATE_CORE, Dependency.CONFIGURATE_YAML))
- .put(StorageType.HOCON, ImmutableList.of(Dependency.HOCON_CONFIG, Dependency.CONFIGURATE_CORE, Dependency.CONFIGURATE_HOCON))
- .put(StorageType.MONGODB, ImmutableList.of(Dependency.MONGODB_DRIVER))
- .put(StorageType.MARIADB, ImmutableList.of(Dependency.MARIADB_DRIVER, Dependency.SLF4J_API, Dependency.SLF4J_SIMPLE, Dependency.HIKARI))
- .put(StorageType.MYSQL, ImmutableList.of(Dependency.MYSQL_DRIVER, Dependency.SLF4J_API, Dependency.SLF4J_SIMPLE, Dependency.HIKARI))
- .put(StorageType.POSTGRESQL, ImmutableList.of(Dependency.POSTGRESQL_DRIVER, Dependency.SLF4J_API, Dependency.SLF4J_SIMPLE, Dependency.HIKARI))
- .put(StorageType.SQLITE, ImmutableList.of(Dependency.SQLITE_DRIVER))
- .put(StorageType.H2, ImmutableList.of(Dependency.H2_DRIVER))
- .build();
-
private final LuckPermsPlugin plugin;
private final MessageDigest digest;
+ private final DependencyRegistry registry;
+ private final EnumSet alreadyLoaded = EnumSet.noneOf(Dependency.class);
public DependencyManager(LuckPermsPlugin plugin) {
this.plugin = plugin;
@@ -91,94 +61,142 @@ public class DependencyManager {
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
+ this.registry = new DependencyRegistry(plugin);
}
public void loadStorageDependencies(Set storageTypes) {
- Set dependencies = new LinkedHashSet<>();
- for (StorageType storageType : storageTypes) {
- dependencies.addAll(STORAGE_DEPENDENCIES.get(storageType));
- }
-
- if (this.plugin.getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
- dependencies.add(Dependency.JEDIS);
- }
-
- // don't load slf4j if it's already present
- if (classExists("org.slf4j.Logger") && classExists("org.slf4j.LoggerFactory")) {
- dependencies.remove(Dependency.SLF4J_API);
- dependencies.remove(Dependency.SLF4J_SIMPLE);
- }
-
- // don't load configurate dependencies on sponge
- if (this.plugin.getServerType() == PlatformType.SPONGE) {
- dependencies.remove(Dependency.CONFIGURATE_CORE);
- dependencies.remove(Dependency.CONFIGURATE_GSON);
- dependencies.remove(Dependency.CONFIGURATE_YAML);
- dependencies.remove(Dependency.CONFIGURATE_HOCON);
- dependencies.remove(Dependency.HOCON_CONFIG);
- }
-
- loadDependencies(dependencies);
+ loadDependencies(this.registry.resolveStorageDependencies(storageTypes));
}
public void loadDependencies(Set dependencies) {
- this.plugin.getLog().info("Identified the following dependencies: " + dependencies.toString());
+ loadDependencies(dependencies, true);
+ }
- File libDir = new File(this.plugin.getDataDirectory(), "lib");
- if (!(libDir.exists() || libDir.mkdirs())) {
- throw new RuntimeException("Unable to create lib dir - " + libDir.getPath());
+ public void loadDependencies(Set dependencies, boolean applyRemapping) {
+ if (applyRemapping) {
+ this.plugin.getLog().info("Identified the following dependencies: " + dependencies.toString());
}
- // Download files.
- List filesToLoad = new ArrayList<>();
+ File saveDirectory = new File(this.plugin.getDataDirectory(), "lib");
+ if (!(saveDirectory.exists() || saveDirectory.mkdirs())) {
+ throw new RuntimeException("Unable to create lib dir - " + saveDirectory.getPath());
+ }
+
+ // create a list of file sources
+ List