13
0

Adding softreload

Dieser Commit ist enthalten in:
Travis CI 2019-06-22 22:28:59 +02:00
Ursprung ff83fa45bc
Commit cda5ef98da
2 geänderte Dateien mit 182 neuen und 2 gelöschten Zeilen

Datei anzeigen

@ -1,9 +1,22 @@
package de.steamwar.bungeecore;
import com.google.common.collect.Multimap;
import net.md_5.bungee.api.event.ProxyReloadEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.*;
import net.md_5.bungee.event.EventHandler;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Handler;
import java.util.logging.Level;
public class Persistent extends Plugin implements Listener {
@ -23,7 +36,104 @@ public class Persistent extends Plugin implements Listener {
@EventHandler
public void onGReload(ProxyReloadEvent e){
PluginManager pluginManager = getProxy().getPluginManager();
Plugin bungeecore = pluginManager.getPlugin("BungeeCore");
ClassLoader pluginClassLoader = bungeecore.getClass().getClassLoader();
bungeecore.onDisable();
for(Handler h : bungeecore.getLogger().getHandlers()){
h.close();
}
pluginManager.unregisterCommands(bungeecore);
pluginManager.unregisterListeners(bungeecore);
getProxy().getScheduler().cancel(bungeecore);
bungeecore.getExecutorService().shutdownNow();
Thread.getAllStackTraces().keySet().stream()
.filter(thread -> (thread.getClass().getClassLoader() == pluginClassLoader))
.forEach(thread -> {
try {
thread.interrupt();
thread.join(2000);
if (thread.isAlive()) {
throw new IllegalStateException("Thread " + thread.getName() + " still running");
}
} catch (Exception t) {
getProxy().getLogger().log(Level.SEVERE, "Failed to stop thread that belong to plugin", t);
}
});
//remove commands that were registered by plugin not through normal means
try {
Map<String, Command> commandMap = ReflectionUtils.getFieldValue(pluginManager, "commandMap");
if (commandMap != null) {
commandMap.entrySet().removeIf(entry -> entry.getValue().getClass().getClassLoader() == pluginClassLoader);
}
} catch (Exception t) {
getLogger().log(Level.SEVERE, "Failed to cleanup commandMap", t);
}
try {
Map<String, Plugin> pluginsMap = ReflectionUtils.getFieldValue(pluginManager, "plugins");
Multimap<Plugin, Command> commands = ReflectionUtils.getFieldValue(pluginManager, "commandsByPlugin");
Multimap<Plugin, Listener> listeners = ReflectionUtils.getFieldValue(pluginManager, "listenersByPlugin");
if (pluginsMap != null && commands != null && listeners != null) {
pluginsMap.values().remove(bungeecore);
commands.removeAll(bungeecore);
listeners.removeAll(bungeecore);
}
} catch (Exception t) {
getLogger().log(Level.SEVERE, "Failed to cleanup bungee internal maps from plugin refs", t);
}
if (pluginClassLoader instanceof URLClassLoader) {
try {
((URLClassLoader) pluginClassLoader).close();
} catch (Exception t) {
getLogger().log(Level.SEVERE, "Failed to close classloader", t);
}
}
Set<PluginClassloader> allLoaders = ReflectionUtils.getStaticFieldValue(PluginClassloader.class, "allLoaders");
if (allLoaders != null) {
allLoaders.remove(pluginClassLoader);
}
File pluginFile = new File(getProxy().getPluginsFolder(), "BungeeCore.jar");
try (JarFile jar = new JarFile(pluginFile)) {
JarEntry pdf = jar.getJarEntry("plugin.yml");
try (InputStream in = jar.getInputStream(pdf)) {
//load description
PluginDescription desc = new Yaml().loadAs(in, PluginDescription.class);
desc.setFile(pluginFile);
//check depends
HashSet<String> plugins = new HashSet<>();
getProxy().getPluginManager().getPlugins().forEach(plugin -> plugins.add(plugin.getDescription().getName()));
for (String dependency : desc.getDepends()) {
if (!plugins.contains(dependency)) {
getLogger().log(Level.WARNING, "{0} (required by {1}) is unavailable", new Object[]{dependency, desc.getName()});
return;
}
}
// do actual loading
Class<?> main;
try (URLClassLoader loader = new PluginClassloader(new URL[]{
pluginFile.toURI().toURL()
})) {
main = loader.loadClass(desc.getMain());
}
Plugin clazz = (Plugin) main.getDeclaredConstructor().newInstance();
// reflection
Map<String, Plugin> pluginsMap = ReflectionUtils.getFieldValue(getProxy().getPluginManager(), "plugins");
ReflectionUtils.invokeMethod(clazz, "init", getProxy(), desc);
pluginsMap.put(desc.getName(), clazz);
clazz.onLoad();
clazz.onEnable();
}
} catch (Exception t) {
getLogger().log(Level.SEVERE, "Failed to load plugin", t);
}
}
public static void setLobbyServer(String lobbyServer) {

Datei anzeigen

@ -0,0 +1,70 @@
package de.steamwar.bungeecore;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
final class ReflectionUtils {
private ReflectionUtils() {
throw new IllegalStateException("Utility class");
}
@SuppressWarnings("unchecked")
static <T> T getFieldValue(Object obj, String fieldName) {
Class<?> clazz = obj.getClass();
do {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(obj);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException error) {
// Ignored
}
} while ((clazz = clazz.getSuperclass()) != null);
return null;
}
static void setFieldValue(Object obj, String fieldName, Object value) {
Class<?> clazz = obj.getClass();
do {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException error) {
// Ignored
}
} while ((clazz = clazz.getSuperclass()) != null);
}
@SuppressWarnings("unchecked")
static <T> T getStaticFieldValue(Class<?> clazz, String fieldName) {
do {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(null);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException error) {
// Ignored
}
} while ((clazz = clazz.getSuperclass()) != null);
return null;
}
static void invokeMethod(Object obj, String methodName, Object... args) {
Class<?> clazz = obj.getClass();
do {
try {
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == args.length) {
method.setAccessible(true);
method.invoke(obj, args);
}
}
} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException error) {
// Ignore
}
} while ((clazz = clazz.getSuperclass()) != null);
}
}