mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-12-28 03:57:36 +01:00
Don't relocate H2 or SQLite depends in favour of loading into isolated classloaders (fixes #704)
This commit is contained in:
parent
1f70ad978f
commit
4858e59b70
@ -68,14 +68,6 @@
|
||||
<pattern>org.postgresql</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.postgresql</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.h2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.h2</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.sqlite</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.sqlite</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.hikari</shadedPattern>
|
||||
|
@ -68,14 +68,6 @@
|
||||
<pattern>org.postgresql</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.postgresql</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.h2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.h2</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.sqlite</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.sqlite</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.hikari</shadedPattern>
|
||||
|
@ -147,20 +147,6 @@
|
||||
<version>2.7.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- h2 -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.196</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- sqlite -->
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.21.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Jedis -->
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.dependencies;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import me.lucko.luckperms.common.dependencies.relocation.Relocation;
|
||||
@ -91,15 +90,17 @@ public enum Dependency {
|
||||
"com.h2database",
|
||||
"h2",
|
||||
"1.4.196",
|
||||
"CgX0oNW4WEAUiq3OY6QjtdPDbvRHVjibT6rQjScz+vU=",
|
||||
Relocation.of("h2", "org{}h2")
|
||||
"CgX0oNW4WEAUiq3OY6QjtdPDbvRHVjibT6rQjScz+vU="
|
||||
// we don't apply relocations to h2 - it gets loaded via
|
||||
// an isolated classloader
|
||||
),
|
||||
SQLITE_DRIVER(
|
||||
"org.xerial",
|
||||
"sqlite-jdbc",
|
||||
"3.21.0",
|
||||
"bglRaH4Y+vQFZV7TfOdsVLO3rJpauJ+IwjuRULAb45Y=",
|
||||
Relocation.of("sqlite", "org{}sqlite")
|
||||
"bglRaH4Y+vQFZV7TfOdsVLO3rJpauJ+IwjuRULAb45Y="
|
||||
// we don't apply relocations to sqlite - it gets loaded via
|
||||
// an isolated classloader
|
||||
),
|
||||
HIKARI(
|
||||
"com{}zaxxer",
|
||||
@ -125,20 +126,20 @@ public enum Dependency {
|
||||
"mongo-java-driver",
|
||||
"3.5.0",
|
||||
"gxrbKVSI/xM6r+6uL7g7I0DzNV+hlNTtfw4UL13XdK8=",
|
||||
ImmutableList.<Relocation>builder()
|
||||
.addAll(Relocation.of("mongodb", "com{}mongodb"))
|
||||
.addAll(Relocation.of("bson", "org{}bson"))
|
||||
.build()
|
||||
Relocation.allOf(
|
||||
Relocation.of("mongodb", "com{}mongodb"),
|
||||
Relocation.of("bson", "org{}bson")
|
||||
)
|
||||
),
|
||||
JEDIS(
|
||||
"redis.clients",
|
||||
"jedis",
|
||||
"2.9.0",
|
||||
"HqqWy45QVeTVF0Z/DzsrPLvGKn2dHotqI8YX7GDThvo=",
|
||||
ImmutableList.<Relocation>builder()
|
||||
.addAll(Relocation.of("jedis", "redis{}clients{}jedis"))
|
||||
.addAll(Relocation.of("commonspool2", "org{}apache{}commons{}pool2"))
|
||||
.build()
|
||||
Relocation.allOf(
|
||||
Relocation.of("jedis", "redis{}clients{}jedis"),
|
||||
Relocation.of("commonspool2", "org{}apache{}commons{}pool2")
|
||||
)
|
||||
),
|
||||
COMMONS_POOL_2(
|
||||
"org.apache.commons",
|
||||
@ -173,10 +174,10 @@ public enum Dependency {
|
||||
"configurate-hocon",
|
||||
"3.3",
|
||||
"UIy5FVmsBUG6+Z1mpIEE2EXgtOI1ZL0p/eEW+BbtGLU=",
|
||||
ImmutableList.<Relocation>builder()
|
||||
.addAll(Relocation.of("configurate", "ninja{}leaping{}configurate"))
|
||||
.addAll(Relocation.of("hocon", "com{}typesafe{}config"))
|
||||
.build()
|
||||
Relocation.allOf(
|
||||
Relocation.of("configurate", "ninja{}leaping{}configurate"),
|
||||
Relocation.of("hocon", "com{}typesafe{}config")
|
||||
)
|
||||
),
|
||||
HOCON_CONFIG(
|
||||
"com{}typesafe",
|
||||
@ -197,6 +198,10 @@ public enum Dependency {
|
||||
this(groupId, artifactId, version, checksum, Collections.emptyList());
|
||||
}
|
||||
|
||||
Dependency(String groupId, String artifactId, String version, String checksum, Relocation relocation) {
|
||||
this(groupId, artifactId, version, checksum, Collections.singletonList(relocation));
|
||||
}
|
||||
|
||||
Dependency(String groupId, String artifactId, String version, String checksum, List<Relocation> relocations) {
|
||||
this(
|
||||
String.format(MAVEN_CENTRAL_FORMAT,
|
||||
@ -210,6 +215,14 @@ public enum Dependency {
|
||||
);
|
||||
}
|
||||
|
||||
Dependency(String url, String version, String checksum) {
|
||||
this(url, version, checksum, Collections.emptyList());
|
||||
}
|
||||
|
||||
Dependency(String url, String version, String checksum, Relocation relocation) {
|
||||
this(url, version, checksum, Collections.singletonList(relocation));
|
||||
}
|
||||
|
||||
Dependency(String url, String version, String checksum, List<Relocation> relocations) {
|
||||
this.url = url;
|
||||
this.version = version;
|
||||
|
@ -25,8 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.dependencies;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import me.lucko.luckperms.common.dependencies.classloader.IsolatedClassLoader;
|
||||
import me.lucko.luckperms.common.dependencies.relocation.Relocation;
|
||||
import me.lucko.luckperms.common.dependencies.relocation.RelocationHandler;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
@ -34,6 +36,7 @@ import me.lucko.luckperms.common.storage.StorageType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.security.MessageDigest;
|
||||
@ -41,8 +44,10 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.EnumSet;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -52,7 +57,8 @@ public class DependencyManager {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final MessageDigest digest;
|
||||
private final DependencyRegistry registry;
|
||||
private final EnumSet<Dependency> alreadyLoaded = EnumSet.noneOf(Dependency.class);
|
||||
private final EnumMap<Dependency, File> loaded = new EnumMap<>(Dependency.class);
|
||||
private final Map<ImmutableSet<Dependency>, IsolatedClassLoader> loaders = new HashMap<>();
|
||||
private RelocationHandler relocationHandler = null;
|
||||
|
||||
public DependencyManager(LuckPermsPlugin plugin) {
|
||||
@ -72,7 +78,7 @@ public class DependencyManager {
|
||||
return this.relocationHandler;
|
||||
}
|
||||
|
||||
public File getSaveDirectory() {
|
||||
private File getSaveDirectory() {
|
||||
File saveDirectory = new File(this.plugin.getDataDirectory(), "lib");
|
||||
if (!(saveDirectory.exists() || saveDirectory.mkdirs())) {
|
||||
throw new RuntimeException("Unable to create lib dir - " + saveDirectory.getPath());
|
||||
@ -81,12 +87,43 @@ public class DependencyManager {
|
||||
return saveDirectory;
|
||||
}
|
||||
|
||||
public IsolatedClassLoader obtainClassLoaderWith(Set<Dependency> dependencies) {
|
||||
ImmutableSet<Dependency> set = ImmutableSet.copyOf(dependencies);
|
||||
|
||||
for (Dependency dependency : dependencies) {
|
||||
if (!this.loaded.containsKey(dependency)) {
|
||||
throw new IllegalStateException("Dependency " + dependency + " is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this.loaders) {
|
||||
IsolatedClassLoader classLoader = this.loaders.get(set);
|
||||
if (classLoader != null) {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
URL[] urls = set.stream()
|
||||
.map(this.loaded::get)
|
||||
.map(file -> {
|
||||
try {
|
||||
return file.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.toArray(URL[]::new);
|
||||
|
||||
classLoader = new IsolatedClassLoader(urls);
|
||||
this.loaders.put(set, classLoader);
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadStorageDependencies(Set<StorageType> storageTypes) {
|
||||
loadDependencies(this.registry.resolveStorageDependencies(storageTypes));
|
||||
}
|
||||
|
||||
public void loadDependencies(Set<Dependency> dependencies) {
|
||||
this.plugin.getLog().info("Identified the following dependencies: " + dependencies.toString());
|
||||
File saveDirectory = getSaveDirectory();
|
||||
|
||||
// create a list of file sources
|
||||
@ -94,7 +131,7 @@ public class DependencyManager {
|
||||
|
||||
// obtain a file for each of the dependencies
|
||||
for (Dependency dependency : dependencies) {
|
||||
if (!this.alreadyLoaded.add(dependency)) {
|
||||
if (this.loaded.containsKey(dependency)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -108,23 +145,23 @@ public class DependencyManager {
|
||||
}
|
||||
|
||||
// apply any remapping rules to the files
|
||||
List<File> remappedJars = new ArrayList<>(sources.size());
|
||||
List<Source> remappedJars = new ArrayList<>(sources.size());
|
||||
for (Source source : sources) {
|
||||
try {
|
||||
// apply remap rules
|
||||
List<Relocation> relocations = source.dependency.getRelocations();
|
||||
|
||||
if (relocations.isEmpty()) {
|
||||
remappedJars.add(source.file);
|
||||
remappedJars.add(source);
|
||||
continue;
|
||||
}
|
||||
|
||||
File input = source.file;
|
||||
File output = new File(input.getParentFile(), "remap-" + input.getName());
|
||||
File output = new File(input.getParentFile(), "remapped-" + input.getName());
|
||||
|
||||
// if the remapped file exists already, just use that.
|
||||
if (output.exists()) {
|
||||
remappedJars.add(output);
|
||||
remappedJars.add(new Source(source.dependency, output));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -135,7 +172,7 @@ public class DependencyManager {
|
||||
this.plugin.getLog().info("Attempting to apply relocations to " + input.getName() + "...");
|
||||
relocationHandler.remap(input, output, relocations);
|
||||
|
||||
remappedJars.add(output);
|
||||
remappedJars.add(new Source(source.dependency, output));
|
||||
} catch (Throwable e) {
|
||||
this.plugin.getLog().severe("Unable to remap the source file '" + source.dependency.name() + "'.");
|
||||
e.printStackTrace();
|
||||
@ -143,17 +180,23 @@ public class DependencyManager {
|
||||
}
|
||||
|
||||
// load each of the jars
|
||||
for (File file : remappedJars) {
|
||||
for (Source source : remappedJars) {
|
||||
if (!DependencyRegistry.shouldAutoLoad(source.dependency)) {
|
||||
this.loaded.put(source.dependency, source.file);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
this.plugin.getPluginClassLoader().loadJar(file);
|
||||
this.plugin.getPluginClassLoader().loadJar(source.file);
|
||||
this.loaded.put(source.dependency, source.file);
|
||||
} catch (Throwable e) {
|
||||
this.plugin.getLog().severe("Failed to load dependency jar '" + file.getName() + "'.");
|
||||
this.plugin.getLog().severe("Failed to load dependency jar '" + source.file.getName() + "'.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public File downloadDependency(File saveDirectory, Dependency dependency) throws Exception {
|
||||
private File downloadDependency(File saveDirectory, Dependency dependency) throws Exception {
|
||||
String fileName = dependency.name().toLowerCase() + "-" + dependency.getVersion() + ".jar";
|
||||
File file = new File(saveDirectory, fileName);
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class DependencyRegistry {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public static boolean classExists(String className) {
|
||||
private static boolean classExists(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
@ -100,17 +100,19 @@ public class DependencyRegistry {
|
||||
return classExists("org.slf4j.Logger") && classExists("org.slf4j.LoggerFactory");
|
||||
}
|
||||
|
||||
// used to remap dependencies - we check to see if they're present to avoid loading unnecessarily.
|
||||
|
||||
public static boolean asmPresent() {
|
||||
return classExists("org.objectweb.asm.ClassReader") &&
|
||||
classExists("org.objectweb.asm.ClassVisitor") &&
|
||||
classExists("org.objectweb.asm.ClassWriter");
|
||||
}
|
||||
|
||||
public static boolean asmCommonsPresent() {
|
||||
return classExists("org.objectweb.asm.commons.ClassRemapper") &&
|
||||
classExists("org.objectweb.asm.commons.Remapper");
|
||||
public static boolean shouldAutoLoad(Dependency dependency) {
|
||||
switch (dependency) {
|
||||
// all used within 'isolated' classloaders, and are therefore not
|
||||
// relocated.
|
||||
case ASM:
|
||||
case ASM_COMMONS:
|
||||
case JAR_RELOCATOR:
|
||||
case H2_DRIVER:
|
||||
case SQLITE_DRIVER:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.dependencies.classloader;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* A classloader "isolated" from the rest of the Minecraft server.
|
||||
*
|
||||
* <p>Used to load specific LuckPerms dependencies without causing conflicts
|
||||
* with other plugins, or libraries provided by the server implementation.</p>
|
||||
*/
|
||||
public class IsolatedClassLoader extends URLClassLoader {
|
||||
|
||||
public IsolatedClassLoader(URL[] urls) {
|
||||
super(urls, null);
|
||||
}
|
||||
|
||||
}
|
@ -25,23 +25,23 @@
|
||||
|
||||
package me.lucko.luckperms.common.dependencies.relocation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class Relocation {
|
||||
|
||||
public static List<Relocation> of(String name, String... packages) {
|
||||
List<Relocation> ret = new ArrayList<>();
|
||||
for (String p : packages) {
|
||||
ret.add(new Relocation(p.replace("{}", "."), "me.lucko.luckperms.lib." + name));
|
||||
}
|
||||
return ret;
|
||||
public static Relocation of(String id, String pattern) {
|
||||
return new Relocation(pattern.replace("{}", "."), "me.lucko.luckperms.lib." + id);
|
||||
}
|
||||
|
||||
public static List<Relocation> allOf(Relocation... relocations) {
|
||||
return Arrays.asList(relocations);
|
||||
}
|
||||
|
||||
private final String pattern;
|
||||
private final String relocatedPattern;
|
||||
|
||||
public Relocation(String pattern, String relocatedPattern) {
|
||||
private Relocation(String pattern, String relocatedPattern) {
|
||||
this.pattern = pattern;
|
||||
this.relocatedPattern = relocatedPattern;
|
||||
}
|
||||
|
@ -27,86 +27,55 @@ package me.lucko.luckperms.common.dependencies.relocation;
|
||||
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.dependencies.DependencyManager;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.IsolatedClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Handles class runtime relocation of packages in downloaded dependencies
|
||||
*/
|
||||
public class RelocationHandler implements AutoCloseable {
|
||||
private final DependencyManager dependencyManager;
|
||||
public class RelocationHandler {
|
||||
private static final Set<Dependency> DEPENDENCIES = EnumSet.of(Dependency.ASM, Dependency.ASM_COMMONS, Dependency.JAR_RELOCATOR);
|
||||
|
||||
private URLClassLoader classLoader;
|
||||
private Constructor<?> relocatorConstructor;
|
||||
private Method relocatorRunMethod;
|
||||
private final Constructor<?> jarRelocatorConstructor;
|
||||
private final Method jarRelocatorRunMethod;
|
||||
|
||||
public RelocationHandler(DependencyManager dependencyManager) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
try {
|
||||
setup();
|
||||
// download the required dependencies for remapping
|
||||
dependencyManager.loadDependencies(DEPENDENCIES);
|
||||
// get a classloader containing the required dependencies as sources
|
||||
IsolatedClassLoader classLoader = dependencyManager.obtainClassLoaderWith(DEPENDENCIES);
|
||||
|
||||
// load the relocator class
|
||||
Class<?> jarRelocatorClass = classLoader.loadClass("me.lucko.jarrelocator.JarRelocator");
|
||||
|
||||
// prepare the the reflected constructor & method instances
|
||||
this.jarRelocatorConstructor = jarRelocatorClass.getDeclaredConstructor(File.class, File.class, Map.class);
|
||||
this.jarRelocatorConstructor.setAccessible(true);
|
||||
|
||||
this.jarRelocatorRunMethod = jarRelocatorClass.getDeclaredMethod("run");
|
||||
this.jarRelocatorRunMethod.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setup() throws Exception {
|
||||
File saveDirectory = this.dependencyManager.getSaveDirectory();
|
||||
|
||||
// download the required dependencies for the remapping.
|
||||
File asm = this.dependencyManager.downloadDependency(saveDirectory, Dependency.ASM);
|
||||
File asmCommons = this.dependencyManager.downloadDependency(saveDirectory, Dependency.ASM_COMMONS);
|
||||
File jarRelocator = this.dependencyManager.downloadDependency(saveDirectory, Dependency.JAR_RELOCATOR);
|
||||
|
||||
URL[] urls = new URL[]{
|
||||
asm.toURI().toURL(),
|
||||
asmCommons.toURI().toURL(),
|
||||
jarRelocator.toURI().toURL()
|
||||
};
|
||||
|
||||
// construct an isolated classloader instance containing the dependencies needed
|
||||
this.classLoader = new URLClassLoader(urls, null);
|
||||
|
||||
// load the relocator class
|
||||
Class<?> relocatorClass = this.classLoader.loadClass("me.lucko.jarrelocator.JarRelocator");
|
||||
|
||||
// prepare the the reflected constructor & method instances
|
||||
this.relocatorConstructor = relocatorClass.getDeclaredConstructor(File.class, File.class, Map.class);
|
||||
this.relocatorConstructor.setAccessible(true);
|
||||
|
||||
this.relocatorRunMethod = relocatorClass.getDeclaredMethod("run");
|
||||
this.relocatorRunMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
public void remap(File input, File output, List<Relocation> relocations) throws Exception {
|
||||
if (this.classLoader == null) {
|
||||
throw new IllegalStateException("ClassLoader is closed");
|
||||
}
|
||||
|
||||
Map<String, String> mappings = new HashMap<>();
|
||||
for (Relocation relocation : relocations) {
|
||||
mappings.put(relocation.getPattern(), relocation.getRelocatedPattern());
|
||||
}
|
||||
|
||||
// create and invoke a new relocator
|
||||
Object relocator = this.relocatorConstructor.newInstance(input, output, mappings);
|
||||
this.relocatorRunMethod.invoke(relocator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (this.classLoader == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classLoader.close();
|
||||
this.classLoader = null;
|
||||
Object relocator = this.jarRelocatorConstructor.newInstance(input, output, mappings);
|
||||
this.jarRelocatorRunMethod.invoke(relocator);
|
||||
}
|
||||
}
|
||||
|
@ -122,28 +122,33 @@ public class StorageFactory {
|
||||
private AbstractDao makeDao(StorageType method) {
|
||||
switch (method) {
|
||||
case MARIADB:
|
||||
return new SqlDao(this.plugin, new MariaDbConnectionFactory(
|
||||
this.plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
|
||||
return new SqlDao(
|
||||
this.plugin,
|
||||
new MariaDbConnectionFactory(this.plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
||||
);
|
||||
case MYSQL:
|
||||
return new SqlDao(this.plugin, new MySqlConnectionFactory(
|
||||
this.plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
|
||||
return new SqlDao(
|
||||
this.plugin,
|
||||
new MySqlConnectionFactory(this.plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
||||
);
|
||||
case SQLITE:
|
||||
return new SqlDao(this.plugin, new SQLiteConnectionFactory(
|
||||
new File(this.plugin.getDataDirectory(), "luckperms-sqlite.db")),
|
||||
return new SqlDao(
|
||||
this.plugin,
|
||||
new SQLiteConnectionFactory(this.plugin, new File(this.plugin.getDataDirectory(), "luckperms-sqlite.db")),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
||||
);
|
||||
case H2:
|
||||
return new SqlDao(this.plugin, new H2ConnectionFactory(
|
||||
new File(this.plugin.getDataDirectory(), "luckperms-h2")),
|
||||
return new SqlDao(
|
||||
this.plugin,
|
||||
new H2ConnectionFactory(this.plugin, new File(this.plugin.getDataDirectory(), "luckperms-h2")),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
||||
);
|
||||
case POSTGRESQL:
|
||||
return new SqlDao(this.plugin, new PostgreConnectionFactory(
|
||||
this.plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
|
||||
return new SqlDao(
|
||||
this.plugin,
|
||||
new PostgreConnectionFactory(this.plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
||||
);
|
||||
case MONGODB:
|
||||
|
@ -25,19 +25,27 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.dao.sql.connection.file;
|
||||
|
||||
import org.h2.Driver;
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLClassLoader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.SQLException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class H2ConnectionFactory extends FlatfileConnectionFactory {
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
// the driver used to obtain connections
|
||||
private final Driver driver;
|
||||
// the active connection
|
||||
private NonClosableConnection connection;
|
||||
|
||||
public H2ConnectionFactory(File file) {
|
||||
public H2ConnectionFactory(LuckPermsPlugin plugin, File file) {
|
||||
super("H2", file);
|
||||
|
||||
// backwards compat
|
||||
@ -45,20 +53,25 @@ public class H2ConnectionFactory extends FlatfileConnectionFactory {
|
||||
if (data.exists()) {
|
||||
data.renameTo(new File(file.getParent(), file.getName() + ".mv.db"));
|
||||
}
|
||||
|
||||
// setup the classloader
|
||||
URLClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.H2_DRIVER));
|
||||
try {
|
||||
Class<?> driverClass = classLoader.loadClass("org.h2.Driver");
|
||||
Method loadMethod = driverClass.getMethod("load");
|
||||
this.driver = (Driver) loadMethod.invoke(null);
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
if (this.connection == null || this.connection.isClosed()) {
|
||||
Connection connection = Driver.load().connect("jdbc:h2:" + this.file.getAbsolutePath(), new Properties());
|
||||
if (connection != null) {
|
||||
this.connection = new NonClosableConnection(connection);
|
||||
}
|
||||
public synchronized Connection getConnection() throws SQLException {
|
||||
if (this.connection == null || this.connection.isClosed()) {
|
||||
Connection connection = this.driver.connect("jdbc:h2:" + this.file.getAbsolutePath(), new Properties());
|
||||
if (connection != null) {
|
||||
this.connection = new NonClosableConnection(connection);
|
||||
}
|
||||
} finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
|
||||
if (this.connection == null) {
|
||||
|
@ -25,19 +25,26 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.dao.sql.connection.file;
|
||||
|
||||
import org.sqlite.JDBC;
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLClassLoader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class SQLiteConnectionFactory extends FlatfileConnectionFactory {
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
// the method invoked to obtain new connection instances
|
||||
private final Method createConnectionMethod;
|
||||
// the active connection
|
||||
private NonClosableConnection connection;
|
||||
|
||||
public SQLiteConnectionFactory(File file) {
|
||||
public SQLiteConnectionFactory(LuckPermsPlugin plugin, File file) {
|
||||
super("SQLite", file);
|
||||
|
||||
// backwards compat
|
||||
@ -45,21 +52,37 @@ public class SQLiteConnectionFactory extends FlatfileConnectionFactory {
|
||||
if (data.exists()) {
|
||||
data.renameTo(file);
|
||||
}
|
||||
|
||||
// setup the classloader
|
||||
URLClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.SQLITE_DRIVER));
|
||||
try {
|
||||
Class<?> jdcbClass = classLoader.loadClass("org.sqlite.JDBC");
|
||||
this.createConnectionMethod = jdcbClass.getMethod("createConnection", String.class, Properties.class);
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Connection createConnection(String url) throws SQLException {
|
||||
try {
|
||||
return (Connection) this.createConnectionMethod.invoke(null, url, new Properties());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof SQLException) {
|
||||
throw ((SQLException) e.getCause());
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
if (this.connection == null || this.connection.isClosed()) {
|
||||
Connection connection = JDBC.createConnection("jdbc:sqlite:" + this.file.getAbsolutePath(), new Properties());
|
||||
if (connection != null) {
|
||||
this.connection = new NonClosableConnection(connection);
|
||||
}
|
||||
public synchronized Connection getConnection() throws SQLException {
|
||||
if (this.connection == null || this.connection.isClosed()) {
|
||||
Connection connection = createConnection("jdbc:sqlite:" + this.file.getAbsolutePath());
|
||||
if (connection != null) {
|
||||
this.connection = new NonClosableConnection(connection);
|
||||
}
|
||||
|
||||
} finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
|
||||
if (this.connection == null) {
|
||||
|
@ -64,14 +64,6 @@
|
||||
<pattern>org.postgresql</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.postgresql</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.h2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.h2</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.sqlite</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.sqlite</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.hikari</shadedPattern>
|
||||
|
Loading…
Reference in New Issue
Block a user