配置文件及文件监听变化

This commit is contained in:
Izzel_Aliz 2018-04-06 15:09:36 +08:00
parent 4bb5df7cbb
commit d8f8ffc5a3
7 changed files with 142 additions and 27 deletions

View File

@ -4,6 +4,7 @@ import com.ilummc.tlib.annotations.Config;
import com.ilummc.tlib.annotations.Dependency; import com.ilummc.tlib.annotations.Dependency;
import com.ilummc.tlib.annotations.Logger; import com.ilummc.tlib.annotations.Logger;
import com.ilummc.tlib.inject.DependencyInjector; import com.ilummc.tlib.inject.DependencyInjector;
import com.ilummc.tlib.inject.TConfigWatcher;
import com.ilummc.tlib.inject.TLibPluginManager; import com.ilummc.tlib.inject.TLibPluginManager;
import com.ilummc.tlib.util.TLogger; import com.ilummc.tlib.util.TLogger;
import me.skymc.taboolib.Main; import me.skymc.taboolib.Main;
@ -23,6 +24,8 @@ public class TLib {
private TLibConfig config; private TLibConfig config;
private TConfigWatcher configWatcher = new TConfigWatcher();
private TLib() { private TLib() {
} }
@ -34,6 +37,10 @@ public class TLib {
return tLogger; return tLogger;
} }
public TConfigWatcher getConfigWatcher() {
return configWatcher;
}
public static TLib getTLib() { public static TLib getTLib() {
return tLib; return tLib;
} }
@ -55,8 +62,13 @@ public class TLib {
} }
} }
@Config(name = "tlib.yml") public static void unload() {
public class TLibConfig { tLib.getConfigWatcher().unregisterAll();
DependencyInjector.eject(Main.getInst(), tLib);
}
@Config(name = "tlib.yml", listenChanges = true)
public static class TLibConfig {
private int downloadPoolSize = 4; private int downloadPoolSize = 4;

View File

@ -8,6 +8,8 @@ import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class DependencyInjector { public class DependencyInjector {
@ -24,7 +26,26 @@ public class DependencyInjector {
} }
static void onDisable(Plugin plugin) { static void onDisable(Plugin plugin) {
ejectConfig(plugin, plugin);
}
public static void eject(Plugin plugin, Object o) {
ejectConfig(plugin, o);
}
private static void ejectConfig(Plugin plugin, Object o) {
for (Field field : o.getClass().getDeclaredFields()) {
Config config;
if ((config = field.getType().getAnnotation(Config.class)) != null) {
try {
field.setAccessible(true);
TConfigInjector.saveConfig(plugin, o);
TLib.getTLib().getLogger().info("插件 " + plugin + " 的配置 " + config.name() + " 已保存");
} catch (IOException e) {
TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置 " + config.name() + " 保存失败");
}
}
}
} }
private static void injectConfig(Plugin plugin, Object o) { private static void injectConfig(Plugin plugin, Object o) {
@ -37,6 +58,25 @@ public class DependencyInjector {
if (obj != null) { if (obj != null) {
TLib.getTLib().getLogger().info("插件 " + plugin.getName() + "" + config.name() + " 配置文件成功加载"); TLib.getTLib().getLogger().info("插件 " + plugin.getName() + "" + config.name() + " 配置文件成功加载");
field.set(o, obj); field.set(o, obj);
if (config.listenChanges()) {
TLib.getTLib().getLogger().info("开始监听插件 " + plugin.getName() + "" + config.name() + " 配置文件");
TLib.getTLib().getConfigWatcher().addOnListen(
new File(plugin.getDataFolder(), config.name()),
obj,
object -> {
try {
Object newObj = TConfigInjector.loadConfig(plugin, object.getClass());
for (Field f : newObj.getClass().getDeclaredFields()) {
f.setAccessible(true);
f.set(obj, f.get(newObj));
}
TLib.getTLib().getLogger().info("插件 " + plugin.getName() + "" + config.name() + " 配置文件成功重载");
} catch (Exception ignored) {
TLib.getTLib().getLogger().warn("插件 " + plugin.getName() + "" + config.name() + " 配置文件重载时发生错误");
}
}
);
}
} }
} }
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {

View File

@ -10,6 +10,7 @@ import com.ilummc.tlib.annotations.Config;
import com.ilummc.tlib.bean.Property; import com.ilummc.tlib.bean.Property;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
@ -17,9 +18,7 @@ import org.yaml.snakeyaml.Yaml;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -50,7 +49,7 @@ public class TConfigInjector {
.create().fromJson(new Gson().toJson(new Yaml() .create().fromJson(new Gson().toJson(new Yaml()
.dump(Files.toString(new File(plugin.getDataFolder(), config.name()), Charset.forName(config.charset())))), clazz); .dump(Files.toString(new File(plugin.getDataFolder(), config.name()), Charset.forName(config.charset())))), clazz);
} catch (NullPointerException e) { } catch (NullPointerException e) {
TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + clazz.getSimpleName() + " 加载失败:没有 @Config 注解"); TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + clazz.getSimpleName() + " 加载失败:没有 @Config 注解或文件不存在");
return null; return null;
} catch (Exception e) { } catch (Exception e) {
try { try {
@ -62,28 +61,24 @@ public class TConfigInjector {
} }
} }
public static Map<String, Object> serialize(Plugin plugin, Class<?> clazz) { public static Map<String, Object> serialize(Plugin plugin, Object object) {
try { try {
Constructor constructor = clazz.getConstructor(); Config config = object.getClass().getAnnotation(Config.class);
constructor.setAccessible(true);
Config config = clazz.getAnnotation(Config.class);
Validate.notNull(config); Validate.notNull(config);
return new Serializer(new LinkedHashMap<>(), constructor.newInstance(), config.excludeModifiers()).get(); return new Serializer(new LinkedHashMap<>(), object, config.excludeModifiers()).get();
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + clazz.getSimpleName() + " 序列化失败:没有无参构造方法");
} catch (NullPointerException e) { } catch (NullPointerException e) {
TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + clazz.getSimpleName() + " 序列化失败:没有 @Config 注解"); TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + object.getClass().getSimpleName() + " 序列化失败:没有 @Config 注解");
} catch (Exception e) { } catch (Exception e) {
TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + clazz.getSimpleName() + " 序列化失败"); TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + object.getClass().getSimpleName() + " 序列化失败");
} }
return null; return null;
} }
public static void saveConfig(Plugin plugin, Class<?> clazz) throws IOException, NullPointerException { public static void saveConfig(Plugin plugin, Object object) throws IOException, NullPointerException {
Object obj = serialize(plugin, clazz); Config config = object.getClass().getAnnotation(Config.class);
Validate.notNull(obj);
Config config = clazz.getAnnotation(Config.class);
Validate.notNull(config); Validate.notNull(config);
Object obj = serialize(plugin, object);
Validate.notNull(obj);
File target = new File(plugin.getDataFolder(), config.name()); File target = new File(plugin.getDataFolder(), config.name());
if (!target.exists()) target.createNewFile(); if (!target.exists()) target.createNewFile();
DumperOptions options = new DumperOptions(); DumperOptions options = new DumperOptions();
@ -143,7 +138,8 @@ public class TConfigInjector {
return map; return map;
} else if (o instanceof ConfigurationSerializable) { } else if (o instanceof ConfigurationSerializable) {
Map map = new LinkedHashMap(); Map map = new LinkedHashMap();
map.put("==", o.getClass().getName()); map.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY,
ConfigurationSerialization.getAlias((Class<? extends ConfigurationSerializable>) o.getClass()));
map.putAll(((ConfigurationSerializable) o).serialize()); map.putAll(((ConfigurationSerializable) o).serialize());
return map; return map;
} else if (o instanceof Property) { } else if (o instanceof Property) {

View File

@ -0,0 +1,59 @@
package com.ilummc.tlib.inject;
import com.ilummc.tlib.TLib;
import org.apache.commons.lang3.tuple.Triple;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class TConfigWatcher {
private ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
private Map<WatchService, Triple<File, Object, Consumer<Object>>> map = new HashMap<>();
public TConfigWatcher() {
service.scheduleAtFixedRate(() -> {
map.forEach((service, triple) -> {
WatchKey key;
while ((key = service.poll()) != null) {
for (WatchEvent<?> watchEvent : key.pollEvents()) {
if (triple.getLeft().getName().equals(Objects.toString(watchEvent.context())))
triple.getRight().accept(triple.getMiddle());
}
key.reset();
}
});
}, 1000, 100, TimeUnit.MILLISECONDS);
}
public void addOnListen(File file, Object obj, Consumer<Object> consumer) {
try {
WatchService service = FileSystems.getDefault().newWatchService();
file.getParentFile().toPath().register(service, StandardWatchEventKinds.ENTRY_MODIFY);
map.put(service, Triple.of(file, obj, consumer));
} catch (IOException e) {
e.printStackTrace();
}
}
public void unregisterAll() {
service.shutdown();
map.forEach((service, pair) -> {
try {
service.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}

View File

@ -1,5 +1,6 @@
package com.ilummc.tlib.inject; package com.ilummc.tlib.inject;
import me.skymc.taboolib.Main;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@ -15,6 +16,8 @@ public class TLibPluginManager implements PluginManager {
private final PluginManager instance; private final PluginManager instance;
private final Main main = (Main) Main.getInst();
public TLibPluginManager() { public TLibPluginManager() {
instance = Bukkit.getPluginManager(); instance = Bukkit.getPluginManager();
} }
@ -56,7 +59,10 @@ public class TLibPluginManager implements PluginManager {
@Override @Override
public void disablePlugins() { public void disablePlugins() {
instance.disablePlugins(); for (Plugin plugin : getPlugins()) {
if (plugin != main) disablePlugin(plugin);
}
disablePlugin(main);
} }
@Override @Override

View File

@ -26,37 +26,37 @@ public class TLogger {
} }
public void verbose(String msg) { public void verbose(String msg) {
if (level >= VERBOSE) if (level <= VERBOSE)
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§f全部", msg)); Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§f全部", msg));
} }
public void finest(String msg) { public void finest(String msg) {
if (level >= FINEST) if (level <= FINEST)
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§e良好", msg)); Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§e良好", msg));
} }
public void fine(String msg) { public void fine(String msg) {
if (level >= FINE) if (level <= FINE)
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§a正常", msg)); Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§a正常", msg));
} }
public void info(String msg) { public void info(String msg) {
if (level >= INFO) if (level <= INFO)
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§b信息", msg)); Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§b信息", msg));
} }
public void warn(String msg) { public void warn(String msg) {
if (level >= WARN) if (level <= WARN)
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§6警告", msg)); Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§6警告", msg));
} }
public void error(String msg) { public void error(String msg) {
if (level >= ERROR) if (level <= ERROR)
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§c错误", msg)); Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§c错误", msg));
} }
public void fatal(String msg) { public void fatal(String msg) {
if (level >= FATAL) if (level <= FATAL)
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§4致命错误", msg)); Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, plugin.getName(), "§4致命错误", msg));
} }

View File

@ -275,6 +275,8 @@ public class Main extends JavaPlugin implements Listener {
connection.closeConnection(); connection.closeConnection();
} }
TLib.unload();
// 关闭服务器 // 关闭服务器
Bukkit.shutdown(); Bukkit.shutdown();
} }