mirror of
https://github.com/lucko/LuckPerms.git
synced 2025-09-03 11:22:33 +02:00
Implement jar-in-jar loader system (#2899)
This fixes an issue that prevented LuckPerms from loading on Java 16
This commit is contained in:
1
common/loader-utils/build.gradle
Normal file
1
common/loader-utils/build.gradle
Normal file
@@ -0,0 +1 @@
|
||||
// nothing special to do here (yet)!
|
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.loader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
/**
|
||||
* Classloader that can load a jar from within another jar file.
|
||||
*
|
||||
* <p>The "loader" jar contains the loading code & public API classes,
|
||||
* and is class-loaded by the platform.</p>
|
||||
*
|
||||
* <p>The inner "plugin" jar contains the plugin itself, and is class-loaded
|
||||
* by the loading code & this classloader.</p>
|
||||
*/
|
||||
public class JarInJarClassLoader extends URLClassLoader {
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new jar-in-jar class loader.
|
||||
*
|
||||
* @param loaderClassLoader the loader plugin's classloader (setup and created by the platform)
|
||||
* @param jarResourcePath the path to the jar-in-jar resource within the loader jar
|
||||
* @throws LoadingException if something unexpectedly bad happens
|
||||
*/
|
||||
public JarInJarClassLoader(ClassLoader loaderClassLoader, String jarResourcePath) throws LoadingException {
|
||||
super(new URL[]{extractJar(loaderClassLoader, jarResourcePath)}, loaderClassLoader);
|
||||
}
|
||||
|
||||
public void addJarToClasspath(URL url) {
|
||||
addURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new plugin instance.
|
||||
*
|
||||
* @param bootstrapClass the name of the bootstrap plugin class
|
||||
* @param loaderPluginType the type of the loader plugin, the only parameter of the bootstrap
|
||||
* plugin constructor
|
||||
* @param loaderPlugin the loader plugin instance
|
||||
* @param <T> the type of the loader plugin
|
||||
* @return the instantiated bootstrap plugin
|
||||
*/
|
||||
public <T> LoaderBootstrap instantiatePlugin(String bootstrapClass, Class<T> loaderPluginType, T loaderPlugin) throws LoadingException {
|
||||
Class<? extends LoaderBootstrap> plugin;
|
||||
try {
|
||||
plugin = loadClass(bootstrapClass).asSubclass(LoaderBootstrap.class);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new LoadingException("Unable to load bootstrap class", e);
|
||||
}
|
||||
|
||||
Constructor<? extends LoaderBootstrap> constructor;
|
||||
try {
|
||||
constructor = plugin.getConstructor(loaderPluginType);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new LoadingException("Unable to get bootstrap constructor", e);
|
||||
}
|
||||
|
||||
try {
|
||||
return constructor.newInstance(loaderPlugin);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new LoadingException("Unable to create bootstrap plugin instance", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the "jar-in-jar" from the loader plugin into a temporary file,
|
||||
* then returns a URL that can be used by the {@link JarInJarClassLoader}.
|
||||
*
|
||||
* @param loaderClassLoader the classloader for the "host" loader plugin
|
||||
* @param jarResourcePath the inner jar resource path
|
||||
* @return a URL to the extracted file
|
||||
*/
|
||||
private static URL extractJar(ClassLoader loaderClassLoader, String jarResourcePath) throws LoadingException {
|
||||
// get the jar-in-jar resource
|
||||
URL jarInJar = loaderClassLoader.getResource(jarResourcePath);
|
||||
if (jarInJar == null) {
|
||||
throw new LoadingException("Could not locate jar-in-jar");
|
||||
}
|
||||
|
||||
// create a temporary file
|
||||
// on posix systems by default this is only read/writable by the process owner
|
||||
Path path;
|
||||
try {
|
||||
path = Files.createTempFile("luckperms-jarinjar", ".jar.tmp");
|
||||
} catch (IOException e) {
|
||||
throw new LoadingException("Unable to create a temporary file", e);
|
||||
}
|
||||
|
||||
// mark that the file should be deleted on exit
|
||||
path.toFile().deleteOnExit();
|
||||
|
||||
// copy the jar-in-jar to the temporary file path
|
||||
try (InputStream in = jarInJar.openStream()) {
|
||||
Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new LoadingException("Unable to copy jar-in-jar to temporary path", e);
|
||||
}
|
||||
|
||||
try {
|
||||
return path.toUri().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new LoadingException("Unable to get URL from path", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.loader;
|
||||
|
||||
/**
|
||||
* Minimal bootstrap plugin, called by the loader plugin.
|
||||
*/
|
||||
public interface LoaderBootstrap {
|
||||
|
||||
void onLoad();
|
||||
|
||||
void onEnable();
|
||||
|
||||
void onDisable();
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.loader;
|
||||
|
||||
/**
|
||||
* Runtime exception used if there is a problem during loading
|
||||
*/
|
||||
public class LoadingException extends RuntimeException {
|
||||
|
||||
public LoadingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LoadingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user