diff --git a/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java b/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java index 3d1ccb4..27958bc 100644 --- a/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java +++ b/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java @@ -27,6 +27,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.Set; /** * Classloader that can load a jar from within another jar file. @@ -38,6 +42,26 @@ import java.util.Arrays; * by the loading code & this classloader.

*/ public class JarInJarClassLoader extends URLClassLoader { + private static final String[] PARENT_FIRST_PACKAGES = { + "java.", + "javax.", + "jdk.", + "sun.", + "com.sun.", + "org.w3c.", + "org.xml.", + "org.slf4j.", + "com.google.inject.", + "javax.inject.", + "com.velocitypowered.", + "org.bukkit.", + "net.md_5.bungee.", + "org.spongepowered.", + "org.bstats.", + "dev.brighten.antivpn.velocity.org.bstats.", + "dev.brighten.antivpn.loader." + }; + static { ClassLoader.registerAsParallelCapable(); } @@ -59,6 +83,74 @@ public class JarInJarClassLoader extends URLClassLoader { addURL(url); } + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + synchronized (getClassLoadingLock(name)) { + Class loadedClass = findLoadedClass(name); + if (loadedClass == null) { + loadedClass = shouldLoadParentFirst(name) ? loadParentThenChild(name) : loadChildThenParent(name); + } + + if (resolve) { + resolveClass(loadedClass); + } + + return loadedClass; + } + } + + @Override + public URL getResource(String name) { + URL resource = findResource(name); + if (resource != null) { + return resource; + } + return super.getResource(name); + } + + @Override + public Enumeration getResources(String name) throws IOException { + Set resources = new LinkedHashSet<>(); + Enumeration childResources = findResources(name); + while (childResources.hasMoreElements()) { + resources.add(childResources.nextElement()); + } + + Enumeration parentResources = getParent() == null + ? ClassLoader.getSystemResources(name) + : getParent().getResources(name); + while (parentResources.hasMoreElements()) { + resources.add(parentResources.nextElement()); + } + + return Collections.enumeration(resources); + } + + private Class loadChildThenParent(String name) throws ClassNotFoundException { + try { + return findClass(name); + } catch (ClassNotFoundException ignored) { + return super.loadClass(name, false); + } + } + + private Class loadParentThenChild(String name) throws ClassNotFoundException { + try { + return super.loadClass(name, false); + } catch (ClassNotFoundException ignored) { + return findClass(name); + } + } + + private static boolean shouldLoadParentFirst(String className) { + for (String prefix : PARENT_FIRST_PACKAGES) { + if (className.startsWith(prefix)) { + return true; + } + } + return false; + } + public void deleteJarResource() { URL[] urls = getURLs(); if (urls.length == 0) { diff --git a/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java b/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java index 9bf68ba..bf9885b 100644 --- a/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java +++ b/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java @@ -40,6 +40,7 @@ public class VelocityPluginLoader { private static final String BOOTSTRAP_CLASS = "dev.brighten.antivpn.velocity.VelocityPlugin"; private final LoaderBootstrap plugin; + private final ClassLoader pluginClassLoader; @Inject public VelocityPluginLoader(ProxyServer server, Logger logger, @DataDirectory Path path, Metrics.Factory metricsFactory) { @@ -50,18 +51,30 @@ public class VelocityPluginLoader { instances.put(String.class, metricsFactory); instances.put(LoaderBootstrap.class, this); JarInJarClassLoader loader = new JarInJarClassLoader(getClass().getClassLoader(), JAR_NAME, SOURCE_NAME); + this.pluginClassLoader = loader; this.plugin = loader.instantiatePlugin(BOOTSTRAP_CLASS, Map.class, instances); - plugin.onLoad(path.toFile()); + runWithPluginClassLoader(() -> plugin.onLoad(path.toFile())); } @Subscribe public void onInit(ProxyInitializeEvent event) { - plugin.onEnable(); + runWithPluginClassLoader(plugin::onEnable); } @Subscribe public void onDisable(ProxyShutdownEvent event) { - plugin.onDisable(); + runWithPluginClassLoader(plugin::onDisable); + } + + private void runWithPluginClassLoader(Runnable action) { + Thread thread = Thread.currentThread(); + ClassLoader previousClassLoader = thread.getContextClassLoader(); + thread.setContextClassLoader(pluginClassLoader); + try { + action.run(); + } finally { + thread.setContextClassLoader(previousClassLoader); + } } }