Add initial multi plugin management
This commit is contained in:
parent
df55162d73
commit
94e4693b5e
54 changed files with 1988 additions and 937 deletions
|
|
@ -3,13 +3,15 @@ package net.frankheijden.serverutils.common;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import net.frankheijden.serverutils.common.entities.CloseableResult;
|
||||
import net.frankheijden.serverutils.common.entities.Result;
|
||||
import java.util.Optional;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription;
|
||||
import net.frankheijden.serverutils.common.entities.results.CloseablePluginResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.PluginResult;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
import net.frankheijden.serverutils.common.tasks.UpdateCheckerTask;
|
||||
|
||||
public class ServerUtilsApp<U extends ServerUtilsPlugin<P, T, C, S>, P, T, C extends ServerCommandSender<S>, S> {
|
||||
public class ServerUtilsApp<U extends ServerUtilsPlugin<P, T, C, S, D>, P, T, C extends ServerCommandSender<S>, S, D extends ServerUtilsPluginDescription> {
|
||||
|
||||
public static final int BSTATS_METRICS_ID = 7790;
|
||||
public static final String VERSION = "{version}";
|
||||
|
|
@ -25,7 +27,14 @@ public class ServerUtilsApp<U extends ServerUtilsPlugin<P, T, C, S>, P, T, C ext
|
|||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public static <U extends ServerUtilsPlugin<P, T, C, S>, P, T, C extends ServerCommandSender<S>, S> void init(
|
||||
public static <
|
||||
U extends ServerUtilsPlugin<P, T, C, S, D>,
|
||||
P,
|
||||
T,
|
||||
C extends ServerCommandSender<S>,
|
||||
S,
|
||||
D extends ServerUtilsPluginDescription
|
||||
> void init(
|
||||
Object platformPlugin,
|
||||
U plugin
|
||||
) {
|
||||
|
|
@ -42,30 +51,31 @@ public class ServerUtilsApp<U extends ServerUtilsPlugin<P, T, C, S>, P, T, C ext
|
|||
/**
|
||||
* Unloads the ServerUtilsUpdater and deletes the file.
|
||||
*/
|
||||
public static <U extends ServerUtilsPlugin<P, T, C, S>, P, T, C extends ServerCommandSender<S>, S>
|
||||
void unloadServerUtilsUpdater() {
|
||||
U plugin = getPlugin();
|
||||
public static <P> void unloadServerUtilsUpdater() {
|
||||
ServerUtilsPlugin<P, ?, ?, ?, ?> plugin = getPlugin();
|
||||
plugin.getTaskManager().runTaskLater(() -> {
|
||||
String updaterName = plugin.getPlatform() == ServerUtilsPlugin.Platform.VELOCITY
|
||||
? "serverutilsupdater"
|
||||
: "ServerUtilsUpdater";
|
||||
P updaterPlugin = plugin.getPluginManager().getPlugin(updaterName);
|
||||
if (updaterPlugin == null) return;
|
||||
Optional<P> updaterPluginOptional = plugin.getPluginManager().getPlugin(updaterName);
|
||||
if (!updaterPluginOptional.isPresent()) return;
|
||||
P updaterPlugin = updaterPluginOptional.get();
|
||||
|
||||
@SuppressWarnings("VariableDeclarationUsageDistance")
|
||||
File file = plugin.getPluginManager().getPluginFile(updaterPlugin);
|
||||
Result result = plugin.getPluginManager().disablePlugin(updaterPlugin);
|
||||
if (result != Result.SUCCESS) {
|
||||
result.sendTo(plugin.getChatProvider().getConsoleSender(), "disabl", updaterName);
|
||||
PluginResult<P> disableResult = plugin.getPluginManager().disablePlugin(updaterPlugin);
|
||||
if (!disableResult.isSuccess()) {
|
||||
disableResult.getResult().sendTo(plugin.getChatProvider().getConsoleSender(), "disabl", updaterName);
|
||||
return;
|
||||
}
|
||||
|
||||
CloseableResult closeableResult = plugin.getPluginManager().unloadPlugin(updaterName);
|
||||
if (closeableResult.getResult() != Result.SUCCESS) {
|
||||
closeableResult.getResult().sendTo(plugin.getChatProvider().getConsoleSender(), "unload", updaterName);
|
||||
CloseablePluginResult<P> unloadResult = plugin.getPluginManager().unloadPlugin(disableResult.getPlugin());
|
||||
if (!unloadResult.isSuccess()) {
|
||||
unloadResult.getResult().sendTo(plugin.getChatProvider().getConsoleSender(), "unload", updaterName);
|
||||
return;
|
||||
}
|
||||
|
||||
closeableResult.tryClose();
|
||||
unloadResult.tryClose();
|
||||
|
||||
if (Files.exists(file.toPath())) {
|
||||
try {
|
||||
|
|
@ -82,8 +92,14 @@ public class ServerUtilsApp<U extends ServerUtilsPlugin<P, T, C, S>, P, T, C ext
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <U extends ServerUtilsPlugin<P, T, C, S>, P, T, C extends ServerCommandSender<S>, S>
|
||||
U getPlugin() {
|
||||
public static <
|
||||
U extends ServerUtilsPlugin<P, T, C, S, D>,
|
||||
P,
|
||||
T,
|
||||
C extends ServerCommandSender<S>,
|
||||
S,
|
||||
D extends ServerUtilsPluginDescription
|
||||
> U getPlugin() {
|
||||
return (U) instance.plugin;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
|||
import net.frankheijden.serverutils.common.utils.ListBuilder;
|
||||
import net.frankheijden.serverutils.common.utils.ListFormat;
|
||||
|
||||
public abstract class CommandPlugins<U extends ServerUtilsPlugin<P, ?, C, ?>, P, C extends ServerCommandSender<?>>
|
||||
public abstract class CommandPlugins<U extends ServerUtilsPlugin<P, ?, C, ?, ?>, P, C extends ServerCommandSender<?>>
|
||||
extends ServerUtilsCommand<U, C> {
|
||||
|
||||
protected CommandPlugins(U plugin) {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,22 @@ import cloud.commandframework.Command;
|
|||
import cloud.commandframework.CommandManager;
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import net.frankheijden.serverutils.common.commands.arguments.JarFilesArgument;
|
||||
import net.frankheijden.serverutils.common.commands.arguments.PluginArgument;
|
||||
import net.frankheijden.serverutils.common.commands.arguments.PluginsArgument;
|
||||
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||
import net.frankheijden.serverutils.common.entities.AbstractResult;
|
||||
import net.frankheijden.serverutils.common.entities.CloseableResult;
|
||||
import net.frankheijden.serverutils.common.entities.LoadResult;
|
||||
import net.frankheijden.serverutils.common.entities.Result;
|
||||
import net.frankheijden.serverutils.common.entities.results.AbstractResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.CloseablePluginResults;
|
||||
import net.frankheijden.serverutils.common.entities.results.PluginResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.PluginResults;
|
||||
import net.frankheijden.serverutils.common.entities.results.Result;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
import net.frankheijden.serverutils.common.managers.AbstractPluginManager;
|
||||
|
|
@ -19,23 +27,21 @@ import net.frankheijden.serverutils.common.utils.FormatBuilder;
|
|||
import net.frankheijden.serverutils.common.utils.ListBuilder;
|
||||
import net.frankheijden.serverutils.common.utils.ListFormat;
|
||||
|
||||
public abstract class CommandServerUtils<U extends ServerUtilsPlugin<P, ?, C, ?>, P, C extends ServerCommandSender<?>>
|
||||
public abstract class CommandServerUtils<U extends ServerUtilsPlugin<P, ?, C, ?, ?>, P, C extends ServerCommandSender<?>>
|
||||
extends ServerUtilsCommand<U, C> {
|
||||
|
||||
protected CommandServerUtils(U plugin) {
|
||||
private final IntFunction<P[]> arrayCreator;
|
||||
|
||||
protected CommandServerUtils(U plugin, IntFunction<P[]> arrayCreator) {
|
||||
super(plugin, "serverutils");
|
||||
this.arrayCreator = arrayCreator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(CommandManager<C> manager, Command.Builder<C> builder) {
|
||||
addArgument(CommandArgument.<C, String>ofType(String.class, "jarFile")
|
||||
.manager(manager)
|
||||
.withSuggestionsProvider((context, s) -> plugin.getPluginManager().getPluginFileNames())
|
||||
.build());
|
||||
addArgument(CommandArgument.<C, String>ofType(String.class, "plugin")
|
||||
.manager(manager)
|
||||
.withSuggestionsProvider((context, s) -> plugin.getPluginManager().getPluginNames())
|
||||
.build());
|
||||
addArgument(new JarFilesArgument<>(true, "jarFiles", plugin));
|
||||
addArgument(new PluginsArgument<>(true, "plugins", plugin, arrayCreator));
|
||||
addArgument(new PluginArgument<>(true, "plugin", plugin));
|
||||
addArgument(CommandArgument.<C, String>ofType(String.class, "command")
|
||||
.manager(manager)
|
||||
.withSuggestionsProvider((context, s) -> new ArrayList<>(plugin.getPluginManager().getCommands()))
|
||||
|
|
@ -48,13 +54,13 @@ public abstract class CommandServerUtils<U extends ServerUtilsPlugin<P, ?, C, ?>
|
|||
manager.command(buildSubcommand(builder, "reload")
|
||||
.handler(this::handleReload));
|
||||
manager.command(buildSubcommand(builder, "loadplugin")
|
||||
.argument(getArgument("jarFile"))
|
||||
.argument(getArgument("jarFiles"))
|
||||
.handler(this::handleLoadPlugin));
|
||||
manager.command(buildSubcommand(builder, "unloadplugin")
|
||||
.argument(getArgument("plugin"))
|
||||
.argument(getArgument("plugins"))
|
||||
.handler(this::handleUnloadPlugin));
|
||||
manager.command(buildSubcommand(builder, "reloadplugin")
|
||||
.argument(getArgument("plugin"))
|
||||
.argument(getArgument("plugins"))
|
||||
.handler(this::handleReloadPlugin));
|
||||
manager.command(buildSubcommand(builder, "watchplugin")
|
||||
.argument(getArgument("plugin"))
|
||||
|
|
@ -146,69 +152,78 @@ public abstract class CommandServerUtils<U extends ServerUtilsPlugin<P, ?, C, ?>
|
|||
|
||||
private void handleLoadPlugin(CommandContext<C> context) {
|
||||
C sender = context.getSender();
|
||||
String jarFile = context.get("jarFile");
|
||||
List<File> jarFiles = Arrays.asList(context.get("jarFiles"));
|
||||
|
||||
AbstractPluginManager<P> pluginManager = plugin.getPluginManager();
|
||||
LoadResult<P> loadResult = pluginManager.loadPlugin(jarFile);
|
||||
if (!loadResult.isSuccess()) {
|
||||
loadResult.getResult().sendTo(sender, "load", jarFile);
|
||||
AbstractPluginManager<P, ?> pluginManager = plugin.getPluginManager();
|
||||
PluginResults<P> loadResults = pluginManager.loadPlugins(jarFiles);
|
||||
if (!loadResults.isSuccess()) {
|
||||
PluginResult<P> failedResult = loadResults.last();
|
||||
failedResult.getResult().sendTo(sender, "load", failedResult.getPluginId());
|
||||
return;
|
||||
}
|
||||
|
||||
P loadedPlugin = loadResult.get();
|
||||
Result result = pluginManager.enablePlugin(loadedPlugin);
|
||||
result.sendTo(sender, "load", pluginManager.getPluginName(loadedPlugin));
|
||||
PluginResults<P> enableResults = pluginManager.enablePlugins(loadResults.getPlugins());
|
||||
enableResults.sendTo(sender, "load");
|
||||
}
|
||||
|
||||
private void handleUnloadPlugin(CommandContext<C> context) {
|
||||
C sender = context.getSender();
|
||||
String pluginName = context.get("plugin");
|
||||
List<P> plugins = Arrays.asList(context.get("plugins"));
|
||||
|
||||
CloseableResult result = plugin.getPluginManager().unloadPlugin(pluginName);
|
||||
result.getResult().sendTo(sender, "unload", pluginName);
|
||||
result.tryClose();
|
||||
PluginResults<P> disableResults = plugin.getPluginManager().disablePlugins(plugins);
|
||||
for (PluginResult<P> disableResult : disableResults.getResults()) {
|
||||
if (!disableResult.isSuccess() && disableResult.getResult() != Result.ALREADY_DISABLED) {
|
||||
disableResult.getResult().sendTo(sender, "disabl", disableResult.getPluginId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CloseablePluginResults<P> unloadResults = plugin.getPluginManager().unloadPlugins(plugins);
|
||||
unloadResults.tryClose();
|
||||
unloadResults.sendTo(sender, "unload");
|
||||
}
|
||||
|
||||
private void handleReloadPlugin(CommandContext<C> context) {
|
||||
C sender = context.getSender();
|
||||
String pluginName = context.get("plugin");
|
||||
List<P> plugins = Arrays.asList(context.get("plugins"));
|
||||
|
||||
Result result = plugin.getPluginManager().reloadPlugin(pluginName);
|
||||
result.sendTo(sender, "reload", pluginName);
|
||||
PluginResults<P> reloadResult = plugin.getPluginManager().reloadPlugins(plugins);
|
||||
reloadResult.sendTo(sender, "reload");
|
||||
}
|
||||
|
||||
private void handleWatchPlugin(CommandContext<C> context) {
|
||||
C sender = context.getSender();
|
||||
String pluginName = context.get("plugin");
|
||||
P pluginArg = context.get("plugin");
|
||||
|
||||
AbstractResult result = plugin.getPluginManager().watchPlugin(sender, pluginName);
|
||||
result.sendTo(sender, "watch", pluginName);
|
||||
AbstractPluginManager<P, ?> pluginManager = plugin.getPluginManager();
|
||||
String pluginId = pluginManager.getPluginId(pluginArg);
|
||||
|
||||
AbstractResult result = pluginManager.watchPlugin(sender, pluginId);
|
||||
result.sendTo(sender, "watch", pluginId);
|
||||
}
|
||||
|
||||
private void handleUnwatchPlugin(CommandContext<C> context) {
|
||||
C sender = context.getSender();
|
||||
String pluginName = context.get("plugin");
|
||||
P pluginArg = context.get("plugin");
|
||||
|
||||
AbstractResult result = plugin.getPluginManager().unwatchPlugin(pluginName);
|
||||
result.sendTo(sender, "unwatch", pluginName);
|
||||
AbstractPluginManager<P, ?> pluginManager = plugin.getPluginManager();
|
||||
String pluginId = pluginManager.getPluginId(pluginArg);
|
||||
|
||||
AbstractResult result = pluginManager.unwatchPlugin(pluginId);
|
||||
result.sendTo(sender, "unwatch", pluginId);
|
||||
}
|
||||
|
||||
private void handlePluginInfo(CommandContext<C> context) {
|
||||
C sender = context.getSender();
|
||||
String pluginName = context.get("plugin");
|
||||
P pluginArg = context.get("plugin");
|
||||
|
||||
if (this.plugin.getPluginManager().getPlugin(pluginName) == null) {
|
||||
Result.NOT_EXISTS.sendTo(sender, "fetch", pluginName);
|
||||
return;
|
||||
}
|
||||
|
||||
createInfo(sender, "plugininfo", pluginName, this::createPluginInfo);
|
||||
createInfo(sender, "plugininfo", pluginArg, this::createPluginInfo);
|
||||
}
|
||||
|
||||
protected abstract FormatBuilder createPluginInfo(
|
||||
FormatBuilder builder,
|
||||
Function<Consumer<ListBuilder<String>>, String> listBuilderFunction,
|
||||
String pluginName
|
||||
P pluginArg
|
||||
);
|
||||
|
||||
private void handleCommandInfo(CommandContext<C> context) {
|
||||
|
|
@ -229,7 +244,7 @@ public abstract class CommandServerUtils<U extends ServerUtilsPlugin<P, ?, C, ?>
|
|||
String commandName
|
||||
);
|
||||
|
||||
private void createInfo(C sender, String command, String item, InfoCreator creator) {
|
||||
private <T> void createInfo(C sender, String command, T item, InfoCreator<T> creator) {
|
||||
String messagePrefix = "serverutils." + command;
|
||||
String format = plugin.getMessagesResource().getMessage(messagePrefix + ".format");
|
||||
String listFormatString = plugin.getMessagesResource().getMessage(messagePrefix + ".list_format");
|
||||
|
|
@ -256,12 +271,12 @@ public abstract class CommandServerUtils<U extends ServerUtilsPlugin<P, ?, C, ?>
|
|||
plugin.getMessagesResource().sendMessage(sender, messagePrefix + ".footer");
|
||||
}
|
||||
|
||||
private interface InfoCreator {
|
||||
private interface InfoCreator<T> {
|
||||
|
||||
FormatBuilder createInfo(
|
||||
FormatBuilder builder,
|
||||
Function<Consumer<ListBuilder<String>>, String> listBuilderFunction,
|
||||
String item
|
||||
T item
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
|||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
|
||||
public abstract class ServerUtilsCommand<U extends ServerUtilsPlugin<?, ?, C, ?>, C extends ServerCommandSender<?>> {
|
||||
public abstract class ServerUtilsCommand<U extends ServerUtilsPlugin<?, ?, C, ?, ?>, C extends ServerCommandSender<?>> {
|
||||
|
||||
protected final U plugin;
|
||||
protected final String commandName;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
package net.frankheijden.serverutils.common.commands.arguments;
|
||||
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
||||
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
|
||||
public class JarFilesArgument<C extends ServerCommandSender<?>> extends CommandArgument<C, File[]> {
|
||||
|
||||
/**
|
||||
* Constructs a Jar Files argument.
|
||||
*/
|
||||
public JarFilesArgument(boolean required, String name, ServerUtilsPlugin<?, ?, C, ?, ?> plugin) {
|
||||
super(
|
||||
required,
|
||||
name,
|
||||
new JarFilesParser<>(plugin),
|
||||
"",
|
||||
new TypeToken<File[]>() {},
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static final class JarFilesParser<C extends ServerCommandSender<?>> implements ArgumentParser<C, File[]> {
|
||||
|
||||
private final ServerUtilsPlugin<?, ?, C, ?, ?> plugin;
|
||||
|
||||
public JarFilesParser(ServerUtilsPlugin<?, ?, C, ?, ?> plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentParseResult<File[]> parse(CommandContext<C> context, Queue<String> inputQueue) {
|
||||
if (inputQueue.isEmpty()) {
|
||||
return ArgumentParseResult.failure(new NoInputProvidedException(JarFilesParser.class, context));
|
||||
}
|
||||
|
||||
Set<String> pluginFiles = new HashSet<>(plugin.getPluginManager().getPluginFileNames());
|
||||
File[] files = new File[inputQueue.size()];
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (!pluginFiles.contains(inputQueue.peek())) {
|
||||
return ArgumentParseResult.failure(new IllegalArgumentException(
|
||||
"Plugin '" + inputQueue.peek() + "' does not exist!"
|
||||
));
|
||||
}
|
||||
|
||||
files[i] = new File(plugin.getPluginManager().getPluginsFolder(), inputQueue.remove());
|
||||
}
|
||||
|
||||
return ArgumentParseResult.success(files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggestions(CommandContext<C> context, String input) {
|
||||
return plugin.getPluginManager().getPluginFileNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContextFree() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package net.frankheijden.serverutils.common.commands.arguments;
|
||||
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
||||
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
|
||||
public class PluginArgument<C extends ServerCommandSender<?>, P> extends CommandArgument<C, P> {
|
||||
|
||||
/**
|
||||
* Constructs a Plugin argument.
|
||||
*/
|
||||
public PluginArgument(boolean required, String name, ServerUtilsPlugin<P, ?, C, ?, ?> plugin) {
|
||||
super(
|
||||
required,
|
||||
name,
|
||||
new PluginParser<>(plugin),
|
||||
"",
|
||||
new TypeToken<P>() {},
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static final class PluginParser<C extends ServerCommandSender<?>, P> implements ArgumentParser<C, P> {
|
||||
|
||||
private final ServerUtilsPlugin<P, ?, C, ?, ?> plugin;
|
||||
|
||||
public PluginParser(ServerUtilsPlugin<P, ?, C, ?, ?> plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentParseResult<P> parse(CommandContext<C> context, Queue<String> inputQueue) {
|
||||
if (inputQueue.isEmpty()) {
|
||||
return ArgumentParseResult.failure(new NoInputProvidedException(PluginParser.class, context));
|
||||
}
|
||||
|
||||
Optional<P> pluginOptional = plugin.getPluginManager().getPlugin(inputQueue.peek());
|
||||
if (!pluginOptional.isPresent()) {
|
||||
return ArgumentParseResult.failure(new IllegalArgumentException(
|
||||
"Plugin '" + inputQueue.peek() + "' does not exist!"
|
||||
));
|
||||
}
|
||||
|
||||
inputQueue.remove();
|
||||
return ArgumentParseResult.success(pluginOptional.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggestions(CommandContext<C> context, String input) {
|
||||
return plugin.getPluginManager().getPluginNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContextFree() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package net.frankheijden.serverutils.common.commands.arguments;
|
||||
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
||||
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||
import cloud.commandframework.context.CommandContext;
|
||||
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.function.IntFunction;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
|
||||
public class PluginsArgument<C extends ServerCommandSender<?>, P> extends CommandArgument<C, P[]> {
|
||||
|
||||
/**
|
||||
* Constructs a Plugins argument.
|
||||
*/
|
||||
public PluginsArgument(
|
||||
boolean required,
|
||||
String name,
|
||||
ServerUtilsPlugin<P, ?, C, ?, ?> plugin,
|
||||
IntFunction<P[]> arrayCreator
|
||||
) {
|
||||
super(
|
||||
required,
|
||||
name,
|
||||
new PluginsParser<>(plugin, arrayCreator),
|
||||
"",
|
||||
new TypeToken<P[]>() {},
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static final class PluginsParser<C extends ServerCommandSender<?>, P> implements ArgumentParser<C, P[]> {
|
||||
|
||||
private final ServerUtilsPlugin<P, ?, C, ?, ?> plugin;
|
||||
private final IntFunction<P[]> arrayCreator;
|
||||
|
||||
public PluginsParser(ServerUtilsPlugin<P, ?, C, ?, ?> plugin, IntFunction<P[]> arrayCreator) {
|
||||
this.plugin = plugin;
|
||||
this.arrayCreator = arrayCreator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentParseResult<P[]> parse(CommandContext<C> context, Queue<String> inputQueue) {
|
||||
if (inputQueue.isEmpty()) {
|
||||
return ArgumentParseResult.failure(new NoInputProvidedException(PluginsParser.class, context));
|
||||
}
|
||||
|
||||
P[] plugins = arrayCreator.apply(inputQueue.size());
|
||||
for (int i = 0; i < plugins.length; i++) {
|
||||
Optional<P> pluginOptional = plugin.getPluginManager().getPlugin(inputQueue.peek());
|
||||
if (!pluginOptional.isPresent()) {
|
||||
return ArgumentParseResult.failure(new IllegalArgumentException(
|
||||
"Plugin '" + inputQueue.peek() + "' does not exist!"
|
||||
));
|
||||
}
|
||||
|
||||
inputQueue.remove();
|
||||
plugins[i] = pluginOptional.get();
|
||||
}
|
||||
|
||||
return ArgumentParseResult.success(plugins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggestions(CommandContext<C> context, String input) {
|
||||
return plugin.getPluginManager().getPluginNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContextFree() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package net.frankheijden.serverutils.common.commands.brigadier;
|
||||
|
||||
import cloud.commandframework.brigadier.CloudBrigadierManager;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import net.frankheijden.serverutils.common.commands.arguments.JarFilesArgument;
|
||||
import net.frankheijden.serverutils.common.commands.arguments.PluginsArgument;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
|
||||
public class BrigadierHandler<C extends ServerCommandSender<?>, P> {
|
||||
|
||||
private final CloudBrigadierManager<C, ?> brigadierManager;
|
||||
|
||||
public BrigadierHandler(CloudBrigadierManager<C, ?> brigadierManager) {
|
||||
this.brigadierManager = brigadierManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers types with the cloud brigadier manager.
|
||||
*/
|
||||
public void registerTypes() {
|
||||
brigadierManager.registerMapping(
|
||||
new TypeToken<JarFilesArgument.JarFilesParser<C>>() {},
|
||||
builder -> builder.toConstant(StringArgumentType.greedyString())
|
||||
);
|
||||
brigadierManager.registerMapping(
|
||||
new TypeToken<PluginsArgument.PluginsParser<C, P>>() {},
|
||||
builder -> builder.toConstant(StringArgumentType.greedyString())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ public class CommandsResource extends ServerUtilsResource {
|
|||
|
||||
private static final String COMMANDS_RESOURCE = "commands";
|
||||
|
||||
public CommandsResource(ServerUtilsPlugin<?, ?, ?, ?> plugin) {
|
||||
public CommandsResource(ServerUtilsPlugin<?, ?, ?, ?, ?> plugin) {
|
||||
super(plugin, COMMANDS_RESOURCE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ public class ConfigResource extends ServerUtilsResource {
|
|||
|
||||
private static final String CONFIG_RESOURCE = "config";
|
||||
|
||||
public ConfigResource(ServerUtilsPlugin<?, ?, ?, ?> plugin) {
|
||||
public ConfigResource(ServerUtilsPlugin<?, ?, ?, ?, ?> plugin) {
|
||||
super(plugin, CONFIG_RESOURCE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public class MessagesResource extends ServerUtilsResource {
|
|||
|
||||
public static final String MESSAGES_RESOURCE = "messages";
|
||||
|
||||
public MessagesResource(ServerUtilsPlugin<?, ?, ?, ?> plugin) {
|
||||
public MessagesResource(ServerUtilsPlugin<?, ?, ?, ?, ?> plugin) {
|
||||
super(plugin, MESSAGES_RESOURCE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
|||
|
||||
public abstract class ServerUtilsResource {
|
||||
|
||||
protected final ServerUtilsPlugin<?, ?, ?, ?> plugin;
|
||||
protected final ServerUtilsPlugin<?, ?, ?, ?, ?> plugin;
|
||||
protected final ServerUtilsConfig config;
|
||||
protected final JsonConfig defaultConfig;
|
||||
|
||||
protected ServerUtilsResource(
|
||||
ServerUtilsPlugin<?, ?, ?, ?> plugin,
|
||||
ServerUtilsPlugin<?, ?, ?, ?, ?> plugin,
|
||||
ServerUtilsConfig config,
|
||||
JsonConfig defaultConfig
|
||||
) {
|
||||
|
|
@ -19,7 +19,7 @@ public abstract class ServerUtilsResource {
|
|||
this.defaultConfig = defaultConfig;
|
||||
}
|
||||
|
||||
protected ServerUtilsResource(ServerUtilsPlugin<?, ?, ?, ?> plugin, String resourceName) {
|
||||
protected ServerUtilsResource(ServerUtilsPlugin<?, ?, ?, ?, ?> plugin, String resourceName) {
|
||||
this.plugin = plugin;
|
||||
this.defaultConfig = JsonConfig.load(plugin.getResourceProvider(), plugin.getPlatform(), resourceName);
|
||||
this.config = ServerUtilsConfig.init(
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
package net.frankheijden.serverutils.common.entities;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A result which should be closed when done.
|
||||
*/
|
||||
public class CloseableResult implements Closeable {
|
||||
|
||||
private Result result;
|
||||
private final List<Closeable> closeables;
|
||||
|
||||
/**
|
||||
* Constructs a new closable result.
|
||||
* Used for unloading / reloading a plugin.
|
||||
* NB: The closable needs to be closed to fully ensure that the old plugin doesn't work anymore!
|
||||
* @param result The result of the procedure
|
||||
* @param closeables The list of closable's of the procedure.
|
||||
*/
|
||||
public CloseableResult(Result result, List<Closeable> closeables) {
|
||||
this.result = result;
|
||||
this.closeables = closeables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new closable result with no closable instance.
|
||||
* @param result The result of the procedure
|
||||
*/
|
||||
public CloseableResult(Result result) {
|
||||
this(result, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new closable result with a closable instance and success result.
|
||||
* @param closeable The closable of the procedure.
|
||||
*/
|
||||
public CloseableResult(Closeable closeable) {
|
||||
this(Result.SUCCESS, Collections.singletonList(closeable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new closable result with a closable instance and success result.
|
||||
* @param closeables The list of closable's of the procedure.
|
||||
*/
|
||||
public CloseableResult(List<Closeable> closeables) {
|
||||
this(Result.SUCCESS, closeables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the result.
|
||||
* @return The result.
|
||||
*/
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the result of this instance.
|
||||
* @param result The result to set.
|
||||
* @return The current instance.
|
||||
*/
|
||||
public CloseableResult set(Result result) {
|
||||
this.result = result;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to close the closable, essentially wrapping it with try-catch.
|
||||
*/
|
||||
public void tryClose() {
|
||||
if (closeables == null) return;
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the closable.
|
||||
* @throws IOException Iff an I/O error occurred.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
for (Closeable closeable : closeables) {
|
||||
closeable.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
package net.frankheijden.serverutils.common.entities;
|
||||
|
||||
/**
|
||||
* A result which contains a loaded object from a load operation.
|
||||
* @param <T> The loaded object type
|
||||
*/
|
||||
public class LoadResult<T> {
|
||||
|
||||
private final T obj;
|
||||
private final Result result;
|
||||
|
||||
/**
|
||||
* Constructs a new LoadResult with an object and a result.
|
||||
* @param obj The object of the load operation.
|
||||
* @param result The result of the load operation.
|
||||
*/
|
||||
public LoadResult(T obj, Result result) {
|
||||
this.obj = obj;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new LoadResult with an object and a success result.
|
||||
* @param obj The object of the load operation.
|
||||
*/
|
||||
public LoadResult(T obj) {
|
||||
this(obj, Result.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new LoadResult without a loaded object, just a result.
|
||||
* @param result The result of the load operation.
|
||||
*/
|
||||
public LoadResult(Result result) {
|
||||
this(null, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the loaded object.
|
||||
* @return The loaded object.
|
||||
*/
|
||||
public T get() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* The result of the LoadResult.
|
||||
* @return The result.
|
||||
*/
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the result is a success.
|
||||
* @return Whether there is success or not.
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return obj != null && result == Result.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package net.frankheijden.serverutils.common.entities;
|
|||
|
||||
import cloud.commandframework.Command;
|
||||
import cloud.commandframework.CommandManager;
|
||||
import cloud.commandframework.brigadier.CloudBrigadierManager;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
|
@ -9,6 +10,7 @@ import java.nio.file.Path;
|
|||
import java.util.Collection;
|
||||
import java.util.logging.Logger;
|
||||
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||
import net.frankheijden.serverutils.common.commands.brigadier.BrigadierHandler;
|
||||
import net.frankheijden.serverutils.common.config.CommandsResource;
|
||||
import net.frankheijden.serverutils.common.config.ConfigResource;
|
||||
import net.frankheijden.serverutils.common.config.MessagesResource;
|
||||
|
|
@ -19,7 +21,7 @@ import net.frankheijden.serverutils.common.providers.ChatProvider;
|
|||
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
||||
import net.frankheijden.serverutils.common.utils.FileUtils;
|
||||
|
||||
public abstract class ServerUtilsPlugin<P, T, C extends ServerCommandSender<S>, S> {
|
||||
public abstract class ServerUtilsPlugin<P, T, C extends ServerCommandSender<S>, S, D extends ServerUtilsPluginDescription> {
|
||||
|
||||
private final UpdateManager updateManager = new UpdateManager();
|
||||
private CommandsResource commandsResource;
|
||||
|
|
@ -43,7 +45,7 @@ public abstract class ServerUtilsPlugin<P, T, C extends ServerCommandSender<S>,
|
|||
return messagesResource;
|
||||
}
|
||||
|
||||
public abstract AbstractPluginManager<P> getPluginManager();
|
||||
public abstract AbstractPluginManager<P, D> getPluginManager();
|
||||
|
||||
public abstract AbstractTaskManager<T> getTaskManager();
|
||||
|
||||
|
|
@ -91,6 +93,11 @@ public abstract class ServerUtilsPlugin<P, T, C extends ServerCommandSender<S>,
|
|||
|
||||
protected abstract CommandManager<C> newCommandManager();
|
||||
|
||||
protected void handleBrigadier(CloudBrigadierManager<C, ?> brigadierManager) {
|
||||
BrigadierHandler<C, P> handler = new BrigadierHandler<>(brigadierManager);
|
||||
handler.registerTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the plugin.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package net.frankheijden.serverutils.common.entities;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ServerUtilsPluginDescription {
|
||||
|
||||
String getId();
|
||||
|
||||
String getName();
|
||||
|
||||
String getVersion();
|
||||
|
||||
String getAuthor();
|
||||
|
||||
File getFile();
|
||||
|
||||
Set<String> getDependencies();
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package net.frankheijden.serverutils.common.entities.exceptions;
|
||||
|
||||
public class InvalidPluginDescriptionException extends RuntimeException {
|
||||
|
||||
public InvalidPluginDescriptionException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidPluginDescriptionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidPluginDescriptionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
package net.frankheijden.serverutils.common.entities;
|
||||
package net.frankheijden.serverutils.common.entities.results;
|
||||
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
|
||||
public interface AbstractResult {
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package net.frankheijden.serverutils.common.entities.results;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CloseablePluginResult<T> extends PluginResult<T> implements Closeable {
|
||||
|
||||
private final List<Closeable> closeables;
|
||||
|
||||
public CloseablePluginResult(String pluginId, Result result) {
|
||||
super(pluginId, result);
|
||||
this.closeables = Collections.emptyList();
|
||||
}
|
||||
|
||||
public CloseablePluginResult(String pluginId, T plugin, Result result, List<Closeable> closeables) {
|
||||
super(pluginId, plugin, result);
|
||||
this.closeables = closeables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to close the closable, essentially wrapping it with try-catch.
|
||||
*/
|
||||
public void tryClose() {
|
||||
if (closeables == null) return;
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the closable.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
for (Closeable closeable : closeables) {
|
||||
closeable.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package net.frankheijden.serverutils.common.entities.results;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class CloseablePluginResults<T> extends PluginResults<T> implements Closeable {
|
||||
|
||||
@Override
|
||||
public CloseablePluginResults<T> addResult(PluginResult<T> pluginResult) {
|
||||
if (!(pluginResult instanceof CloseablePluginResult)) {
|
||||
throw new IllegalArgumentException("Not an instance of CloseablePluginResult: " + pluginResult);
|
||||
}
|
||||
results.add(pluginResult);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloseablePluginResults<T> addResult(String pluginId, Result result) {
|
||||
super.addResult(pluginId, result);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloseablePluginResults<T> addResult(String pluginId, T plugin) {
|
||||
super.addResult(pluginId, plugin);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CloseablePluginResults<T> addResult(String pluginId, T plugin, Result result) {
|
||||
super.addResult(pluginId, plugin, result);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloseablePluginResults<T> addResult(String pluginId, T plugin, List<Closeable> closeables) {
|
||||
return addResult(new CloseablePluginResult<>(pluginId, plugin, Result.SUCCESS, closeables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloseablePluginResult<T> first() {
|
||||
PluginResult<T> pluginResult = super.first();
|
||||
if (!(pluginResult instanceof CloseablePluginResult)) {
|
||||
throw new IllegalArgumentException("Not an instance of CloseablePluginResult: " + pluginResult);
|
||||
}
|
||||
return (CloseablePluginResult<T>) pluginResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloseablePluginResult<T> last() {
|
||||
PluginResult<T> pluginResult = super.last();
|
||||
if (!(pluginResult instanceof CloseablePluginResult)) {
|
||||
throw new IllegalArgumentException("Not an instance of CloseablePluginResult: " + pluginResult);
|
||||
}
|
||||
return (CloseablePluginResult<T>) pluginResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to close the {@link CloseablePluginResult}'s enclosed.
|
||||
*/
|
||||
public void tryClose() {
|
||||
try {
|
||||
for (PluginResult<T> pluginResult : this) {
|
||||
if (pluginResult instanceof CloseablePluginResult) {
|
||||
((CloseablePluginResult<T>) pluginResult).close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
for (PluginResult<T> pluginResult : this) {
|
||||
if (pluginResult instanceof CloseablePluginResult) {
|
||||
((CloseablePluginResult<T>) pluginResult).close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package net.frankheijden.serverutils.common.entities.results;
|
||||
|
||||
public class PluginResult<T> {
|
||||
|
||||
private final String pluginId;
|
||||
private final T plugin;
|
||||
private final Result result;
|
||||
|
||||
public PluginResult(String pluginId, Result result) {
|
||||
this(pluginId, null, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new PluginResult.
|
||||
*/
|
||||
public PluginResult(String pluginId, T plugin, Result result) {
|
||||
this.pluginId = pluginId;
|
||||
this.plugin = plugin;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public String getPluginId() {
|
||||
return pluginId;
|
||||
}
|
||||
|
||||
public T getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return plugin != null && result == Result.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package net.frankheijden.serverutils.common.entities.results;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
|
||||
public class PluginResults<T> implements Iterable<PluginResult<T>> {
|
||||
|
||||
protected final List<PluginResult<T>> results;
|
||||
|
||||
public PluginResults() {
|
||||
this.results = new ArrayList<>();
|
||||
}
|
||||
|
||||
public PluginResults<T> addResult(String pluginId, Result result) {
|
||||
addResult(pluginId, null, result);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PluginResults<T> addResult(String pluginId, T plugin) {
|
||||
addResult(pluginId, plugin, Result.SUCCESS);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected PluginResults<T> addResult(String pluginId, T plugin, Result result) {
|
||||
addResult(new PluginResult<>(pluginId, plugin, result));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PluginResults<T> addResult(PluginResult<T> pluginResult) {
|
||||
this.results.add(pluginResult);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return results.stream().allMatch(PluginResult::isSuccess);
|
||||
}
|
||||
|
||||
public List<PluginResult<T>> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of all plugins.
|
||||
* @throws IllegalArgumentException Iff a result was not successful (check {@link PluginResults#isSuccess()} first!)
|
||||
*/
|
||||
public List<T> getPlugins() {
|
||||
List<T> plugins = new ArrayList<>(results.size());
|
||||
for (PluginResult<T> result : results) {
|
||||
if (!result.isSuccess()) throw new IllegalArgumentException(
|
||||
"Result after handling plugin '" + result.getPluginId() + "' was not successful!"
|
||||
);
|
||||
plugins.add(result.getPlugin());
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
|
||||
public PluginResult<T> first() {
|
||||
return results.get(0);
|
||||
}
|
||||
|
||||
public PluginResult<T> last() {
|
||||
return results.get(results.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the results to given receiver.
|
||||
*/
|
||||
public void sendTo(ServerCommandSender<?> sender, String action) {
|
||||
for (PluginResult<T> result : results) {
|
||||
result.getResult().sendTo(sender, action, result.getPluginId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PluginResult<T>> iterator() {
|
||||
return results.iterator();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package net.frankheijden.serverutils.common.entities;
|
||||
package net.frankheijden.serverutils.common.entities.results;
|
||||
|
||||
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
|
||||
/**
|
||||
* An enum containing possible results.
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package net.frankheijden.serverutils.common.entities;
|
||||
package net.frankheijden.serverutils.common.entities.results;
|
||||
|
||||
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
|
||||
public enum WatchResult implements AbstractResult {
|
||||
|
||||
|
|
@ -4,7 +4,7 @@ import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
|||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
import net.frankheijden.serverutils.common.tasks.UpdateCheckerTask;
|
||||
|
||||
public abstract class PlayerListener<U extends ServerUtilsPlugin<P, ?, C, ?>, P, C extends ServerCommandSender<?>>
|
||||
public abstract class PlayerListener<U extends ServerUtilsPlugin<P, ?, C, ?, ?>, P, C extends ServerCommandSender<?>>
|
||||
extends ServerUtilsListener<U, C> {
|
||||
|
||||
protected PlayerListener(U plugin) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package net.frankheijden.serverutils.common.listeners;
|
|||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
|
||||
public abstract class ServerUtilsListener<U extends ServerUtilsPlugin<?, ?, C, ?>, C extends ServerCommandSender<?>> {
|
||||
public abstract class ServerUtilsListener<U extends ServerUtilsPlugin<?, ?, C, ?, ?>, C extends ServerCommandSender<?>> {
|
||||
|
||||
protected final U plugin;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,54 +1,316 @@
|
|||
package net.frankheijden.serverutils.common.managers;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||
import net.frankheijden.serverutils.common.entities.AbstractResult;
|
||||
import net.frankheijden.serverutils.common.entities.CloseableResult;
|
||||
import net.frankheijden.serverutils.common.entities.LoadResult;
|
||||
import net.frankheijden.serverutils.common.entities.Result;
|
||||
import net.frankheijden.serverutils.common.entities.results.AbstractResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.CloseablePluginResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.CloseablePluginResults;
|
||||
import net.frankheijden.serverutils.common.entities.results.PluginResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.PluginResults;
|
||||
import net.frankheijden.serverutils.common.entities.results.Result;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.WatchResult;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription;
|
||||
import net.frankheijden.serverutils.common.entities.results.WatchResult;
|
||||
import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException;
|
||||
import net.frankheijden.serverutils.common.providers.PluginProvider;
|
||||
import net.frankheijden.serverutils.common.tasks.PluginWatcherTask;
|
||||
import net.frankheijden.serverutils.common.utils.DependencyUtils;
|
||||
|
||||
public interface AbstractPluginManager<P> extends PluginProvider<P> {
|
||||
public abstract class AbstractPluginManager<P, D extends ServerUtilsPluginDescription> implements PluginProvider<P, D> {
|
||||
|
||||
LoadResult<P> loadPlugin(String pluginFile);
|
||||
/**
|
||||
* Loads the given plugin by their jar file.
|
||||
*/
|
||||
public PluginResult<P> loadPlugin(String pluginFile) {
|
||||
File file = new File(getPluginsFolder(), pluginFile);
|
||||
if (!file.exists()) return new PluginResult<>(pluginFile, Result.NOT_EXISTS);
|
||||
return loadPlugin(file);
|
||||
}
|
||||
|
||||
LoadResult<P> loadPlugin(File file);
|
||||
public PluginResult<P> loadPlugin(File file) {
|
||||
return loadPlugins(Collections.singletonList(file)).first();
|
||||
}
|
||||
|
||||
Result enablePlugin(P plugin);
|
||||
/**
|
||||
* Loads a list of files as plugins.
|
||||
*/
|
||||
public PluginResults<P> loadPlugins(List<File> files) {
|
||||
List<D> descriptions = new ArrayList<>(files.size());
|
||||
|
||||
Result disablePlugin(P plugin);
|
||||
for (File file : files) {
|
||||
D description;
|
||||
try {
|
||||
Optional<D> descriptionOptional = getPluginDescription(file);
|
||||
if (!descriptionOptional.isPresent()) {
|
||||
return new PluginResults<P>().addResult(file.getName(), Result.NOT_EXISTS);
|
||||
}
|
||||
|
||||
Result reloadPlugin(String pluginName);
|
||||
description = descriptionOptional.get();
|
||||
} catch (InvalidPluginDescriptionException ex) {
|
||||
return new PluginResults<P>().addResult(file.getName(), Result.INVALID_DESCRIPTION);
|
||||
}
|
||||
|
||||
Result reloadPlugin(P plugin);
|
||||
if (getPlugin(description.getId()).isPresent()) {
|
||||
return new PluginResults<P>().addResult(description.getId(), Result.ALREADY_LOADED);
|
||||
}
|
||||
|
||||
CloseableResult unloadPlugin(String pluginName);
|
||||
descriptions.add(description);
|
||||
}
|
||||
|
||||
CloseableResult unloadPlugin(P plugin);
|
||||
List<D> orderedDescriptions;
|
||||
try {
|
||||
orderedDescriptions = determineLoadOrder(descriptions);
|
||||
} catch (IllegalStateException ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (File file : files) {
|
||||
sb.append(", ").append(file.getName());
|
||||
}
|
||||
|
||||
return new PluginResults<P>().addResult(sb.substring(2), Result.ERROR);
|
||||
}
|
||||
|
||||
return loadPluginDescriptions(orderedDescriptions);
|
||||
}
|
||||
|
||||
protected abstract PluginResults<P> loadPluginDescriptions(List<D> descriptions);
|
||||
|
||||
/**
|
||||
* Enables the given plugin by name.
|
||||
*/
|
||||
public PluginResult<P> enablePlugin(String pluginId) {
|
||||
return getPlugin(pluginId)
|
||||
.map(this::enablePlugin)
|
||||
.orElse(new PluginResult<>(pluginId, Result.NOT_EXISTS));
|
||||
}
|
||||
|
||||
public PluginResult<P> enablePlugin(P plugin) {
|
||||
return enablePlugins(Collections.singletonList(plugin)).first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a list of plugins.
|
||||
*/
|
||||
public PluginResults<P> enablePlugins(List<P> plugins) {
|
||||
for (P plugin : plugins) {
|
||||
String pluginId = getPluginId(plugin);
|
||||
if (isPluginEnabled(pluginId)) {
|
||||
return new PluginResults<P>().addResult(pluginId, Result.ALREADY_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
return enableOrderedPlugins(determineLoadOrder(plugins));
|
||||
}
|
||||
|
||||
protected abstract PluginResults<P> enableOrderedPlugins(List<P> plugins);
|
||||
|
||||
public boolean isPluginEnabled(P plugin) {
|
||||
return isPluginEnabled(getPluginId(plugin));
|
||||
}
|
||||
|
||||
public abstract boolean isPluginEnabled(String pluginId);
|
||||
|
||||
/**
|
||||
* Disables the given plugin by name.
|
||||
*/
|
||||
public PluginResult<P> disablePlugin(String pluginId) {
|
||||
return getPlugin(pluginId)
|
||||
.map(this::disablePlugin)
|
||||
.orElse(new PluginResult<>(pluginId, Result.NOT_EXISTS));
|
||||
}
|
||||
|
||||
public PluginResult<P> disablePlugin(P plugin) {
|
||||
return disablePlugins(Collections.singletonList(plugin)).first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables a list of plugins.
|
||||
*/
|
||||
public PluginResults<P> disablePlugins(List<P> plugins) {
|
||||
for (P plugin : plugins) {
|
||||
if (!isPluginEnabled(plugin)) {
|
||||
return new PluginResults<P>().addResult(getPluginId(plugin), Result.ALREADY_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
List<P> orderedPlugins;
|
||||
try {
|
||||
orderedPlugins = determineLoadOrder(plugins);
|
||||
} catch (IllegalStateException ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (P plugin : plugins) {
|
||||
sb.append(", ").append(getPluginId(plugin));
|
||||
}
|
||||
|
||||
return new PluginResults<P>().addResult(sb.substring(2), Result.ERROR);
|
||||
}
|
||||
|
||||
Collections.reverse(orderedPlugins);
|
||||
return disableOrderedPlugins(orderedPlugins);
|
||||
}
|
||||
|
||||
public abstract PluginResults<P> disableOrderedPlugins(List<P> plugins);
|
||||
|
||||
/**
|
||||
* Reloads the given plugin by name.
|
||||
*/
|
||||
public PluginResult<P> reloadPlugin(String pluginId) {
|
||||
return getPlugin(pluginId)
|
||||
.map(this::reloadPlugin)
|
||||
.orElse(new PluginResult<>(pluginId, Result.NOT_EXISTS));
|
||||
}
|
||||
|
||||
public PluginResult<P> reloadPlugin(P plugin) {
|
||||
return reloadPlugins(Collections.singletonList(plugin)).first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the given plugins.
|
||||
*/
|
||||
public PluginResults<P> reloadPlugins(List<P> plugins) {
|
||||
PluginResults<P> disableResults = disablePlugins(plugins);
|
||||
for (PluginResult<P> disableResult : disableResults.getResults()) {
|
||||
if (!disableResult.isSuccess() && disableResult.getResult() != Result.ALREADY_DISABLED) {
|
||||
return disableResults;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> pluginIds = new ArrayList<>(plugins.size());
|
||||
for (P plugin : plugins) {
|
||||
pluginIds.add(getPluginId(plugin));
|
||||
}
|
||||
|
||||
CloseablePluginResults<P> unloadResults = unloadPlugins(plugins);
|
||||
if (!unloadResults.isSuccess()) return unloadResults;
|
||||
unloadResults.tryClose();
|
||||
|
||||
List<File> pluginFiles = new ArrayList<>(plugins.size());
|
||||
for (String pluginId : pluginIds) {
|
||||
Optional<File> pluginFile = getPluginFile(pluginId);
|
||||
if (!pluginFile.isPresent()) return new PluginResults<P>().addResult(pluginId, Result.FILE_DELETED);
|
||||
pluginFiles.add(pluginFile.get());
|
||||
}
|
||||
|
||||
PluginResults<P> loadResults = loadPlugins(pluginFiles);
|
||||
if (!loadResults.isSuccess()) return loadResults;
|
||||
|
||||
List<P> loadedPlugins = new ArrayList<>(pluginIds.size());
|
||||
for (PluginResult<P> loadResult : loadResults) {
|
||||
loadedPlugins.add(loadResult.getPlugin());
|
||||
}
|
||||
|
||||
return enablePlugins(loadedPlugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads the given plugin by name.
|
||||
*/
|
||||
public CloseablePluginResult<P> unloadPlugin(String pluginId) {
|
||||
return getPlugin(pluginId)
|
||||
.map(this::unloadPlugin)
|
||||
.orElse(new CloseablePluginResult<>(pluginId, Result.NOT_EXISTS));
|
||||
}
|
||||
|
||||
public CloseablePluginResult<P> unloadPlugin(P plugin) {
|
||||
return unloadPlugins(Collections.singletonList(plugin)).first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads a list of plugins.
|
||||
*/
|
||||
public CloseablePluginResults<P> unloadPlugins(List<P> plugins) {
|
||||
List<P> orderedPlugins;
|
||||
try {
|
||||
orderedPlugins = determineLoadOrder(plugins);
|
||||
} catch (IllegalStateException ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (P plugin : plugins) {
|
||||
sb.append(", ").append(getPluginId(plugin));
|
||||
}
|
||||
|
||||
return new CloseablePluginResults<P>().addResult(sb.substring(2), Result.ERROR);
|
||||
}
|
||||
|
||||
Collections.reverse(orderedPlugins);
|
||||
return unloadOrderedPlugins(orderedPlugins);
|
||||
}
|
||||
|
||||
public abstract CloseablePluginResults<P> unloadOrderedPlugins(List<P> plugins);
|
||||
|
||||
/**
|
||||
* Determines the load order of a list of plugins.
|
||||
*/
|
||||
public List<P> determineLoadOrder(List<P> plugins) throws IllegalStateException {
|
||||
Map<D, P> descriptionMap = new HashMap<>(plugins.size());
|
||||
for (P plugin : plugins) {
|
||||
descriptionMap.put(getLoadedPluginDescription(plugin), plugin);
|
||||
}
|
||||
|
||||
List<P> orderedPlugins = new ArrayList<>(plugins.size());
|
||||
for (D description : determineLoadOrder(descriptionMap.keySet())) {
|
||||
orderedPlugins.add(descriptionMap.get(description));
|
||||
}
|
||||
return orderedPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the load order for a given collection of descriptions.
|
||||
* @throws IllegalStateException Iff circular dependency
|
||||
*/
|
||||
public List<D> determineLoadOrder(Collection<? extends D> descriptions) throws IllegalStateException {
|
||||
Map<String, D> pluginIdToDescriptionMap = new HashMap<>();
|
||||
for (D description : descriptions) {
|
||||
pluginIdToDescriptionMap.put(description.getId(), description);
|
||||
}
|
||||
|
||||
Map<D, Set<D>> dependencyMap = new HashMap<>(descriptions.size());
|
||||
for (D description : descriptions) {
|
||||
Set<String> dependencyStrings = description.getDependencies();
|
||||
Set<D> dependencies = new HashSet<>();
|
||||
|
||||
for (String dependencyString : dependencyStrings) {
|
||||
D dependency = pluginIdToDescriptionMap.get(dependencyString);
|
||||
if (dependency != null) {
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
dependencyMap.put(description, dependencies);
|
||||
}
|
||||
|
||||
return DependencyUtils.determineOrder(dependencyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts watching the specified plugin for changes.
|
||||
* Reloads the plugin if a change is detected.
|
||||
* @param pluginName The plugin to watch.
|
||||
* @return The result of the action.
|
||||
*/
|
||||
default AbstractResult watchPlugin(ServerCommandSender<?> sender, String pluginName) {
|
||||
if (getPlugin(pluginName) == null) return Result.NOT_EXISTS;
|
||||
public AbstractResult watchPlugin(ServerCommandSender<?> sender, String pluginId) {
|
||||
if (getPlugin(pluginId).isPresent()) return Result.NOT_EXISTS;
|
||||
ServerUtilsApp.getPlugin().getTaskManager()
|
||||
.runTaskAsynchronously(pluginName, new PluginWatcherTask(sender, pluginName));
|
||||
.runTaskAsynchronously(pluginId, new PluginWatcherTask(sender, pluginId));
|
||||
return WatchResult.START;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops watching the plugin for changes.
|
||||
* @param pluginName The plugin to stop watching.
|
||||
* @return The result of the action.
|
||||
*/
|
||||
default AbstractResult unwatchPlugin(String pluginName) {
|
||||
if (ServerUtilsApp.getPlugin().getTaskManager().cancelTask(pluginName)) return WatchResult.STOPPED;
|
||||
public AbstractResult unwatchPlugin(String pluginId) {
|
||||
if (ServerUtilsApp.getPlugin().getTaskManager().cancelTask(pluginId)) return WatchResult.STOPPED;
|
||||
return WatchResult.NOT_WATCHING;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@ import java.io.File;
|
|||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription;
|
||||
import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException;
|
||||
|
||||
public interface PluginProvider<P> {
|
||||
public interface PluginProvider<P, D extends ServerUtilsPluginDescription> {
|
||||
|
||||
default File getPluginsFolder() {
|
||||
return ServerUtilsApp.getPlugin().getDataFolder().getParentFile();
|
||||
|
|
@ -16,13 +19,43 @@ public interface PluginProvider<P> {
|
|||
|
||||
List<P> getPlugins();
|
||||
|
||||
String getPluginName(P plugin);
|
||||
default String getPluginId(P plugin) {
|
||||
return getLoadedPluginDescription(plugin).getId();
|
||||
}
|
||||
|
||||
File getPluginFile(P plugin);
|
||||
default File getPluginFile(P plugin) {
|
||||
return getLoadedPluginDescription(plugin).getFile();
|
||||
}
|
||||
|
||||
File getPluginFile(String pluginName);
|
||||
/**
|
||||
* Attempts to find the file for a given plugin id.
|
||||
*/
|
||||
default Optional<File> getPluginFile(String pluginId) {
|
||||
for (File file : getPluginJars()) {
|
||||
Optional<D> pluginDescriptionOptional;
|
||||
try {
|
||||
pluginDescriptionOptional = getPluginDescription(file);
|
||||
} catch (InvalidPluginDescriptionException ex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
P getPlugin(String pluginName);
|
||||
if (pluginDescriptionOptional.isPresent() && pluginDescriptionOptional.get().getId().equals(pluginId)) {
|
||||
return Optional.of(file);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Optional<P> getPlugin(String pluginId);
|
||||
|
||||
D getLoadedPluginDescription(P plugin);
|
||||
|
||||
default Optional<D> getPluginDescription(String pluginId) throws InvalidPluginDescriptionException {
|
||||
Optional<File> fileOptional = getPluginFile(pluginId);
|
||||
return fileOptional.flatMap(this::getPluginDescription);
|
||||
}
|
||||
|
||||
Optional<D> getPluginDescription(File file) throws InvalidPluginDescriptionException;
|
||||
|
||||
Object getInstance(P plugin);
|
||||
|
||||
|
|
@ -34,7 +67,7 @@ public interface PluginProvider<P> {
|
|||
*/
|
||||
default List<P> getPluginsSorted() {
|
||||
List<P> plugins = getPlugins();
|
||||
plugins.sort(Comparator.comparing(this::getPluginName));
|
||||
plugins.sort(Comparator.comparing(this::getPluginId));
|
||||
return plugins;
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +77,7 @@ public interface PluginProvider<P> {
|
|||
*/
|
||||
default List<String> getPluginNames() {
|
||||
return getPlugins().stream()
|
||||
.map(this::getPluginName)
|
||||
.map(this::getPluginId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import net.frankheijden.serverutils.common.ServerUtilsApp;
|
|||
import net.frankheijden.serverutils.common.entities.AbstractTask;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
import net.frankheijden.serverutils.common.entities.WatchResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.WatchResult;
|
||||
import net.frankheijden.serverutils.common.managers.AbstractPluginManager;
|
||||
import net.frankheijden.serverutils.common.managers.AbstractTaskManager;
|
||||
import net.frankheijden.serverutils.common.providers.ChatProvider;
|
||||
|
|
@ -28,8 +28,8 @@ public class PluginWatcherTask extends AbstractTask {
|
|||
StandardWatchEventKinds.ENTRY_DELETE
|
||||
};
|
||||
|
||||
private final ServerUtilsPlugin<?, ?, ?, ?> plugin = ServerUtilsApp.getPlugin();
|
||||
private final AbstractPluginManager<?> pluginManager = plugin.getPluginManager();
|
||||
private final ServerUtilsPlugin<?, ?, ?, ?, ?> plugin = ServerUtilsApp.getPlugin();
|
||||
private final AbstractPluginManager<?, ?> pluginManager = plugin.getPluginManager();
|
||||
private final ChatProvider<?, ?> chatProvider = plugin.getChatProvider();
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final AbstractTaskManager taskManager = plugin.getTaskManager();
|
||||
|
|
@ -52,7 +52,7 @@ public class PluginWatcherTask extends AbstractTask {
|
|||
public PluginWatcherTask(ServerCommandSender<?> sender, String pluginName) {
|
||||
this.sender = sender;
|
||||
this.pluginName = pluginName;
|
||||
this.file = pluginManager.getPluginFile(pluginName);
|
||||
this.file = pluginManager.getPluginFile(pluginName).orElse(null);
|
||||
this.run = new AtomicBoolean(true);
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ public class PluginWatcherTask extends AbstractTask {
|
|||
send(WatchResult.CHANGE);
|
||||
|
||||
pluginManager.reloadPlugin(pluginName);
|
||||
file = pluginManager.getPluginFile(pluginName);
|
||||
file = pluginManager.getPluginFile(pluginName).orElse(null);
|
||||
}
|
||||
}, 10L);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import java.net.UnknownHostException;
|
|||
import java.util.logging.Level;
|
||||
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||
import net.frankheijden.serverutils.common.entities.LoadResult;
|
||||
import net.frankheijden.serverutils.common.entities.Result;
|
||||
import net.frankheijden.serverutils.common.entities.results.PluginResult;
|
||||
import net.frankheijden.serverutils.common.entities.results.Result;
|
||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||
import net.frankheijden.serverutils.common.entities.http.GitHubAsset;
|
||||
|
|
@ -22,7 +22,7 @@ import net.frankheijden.serverutils.common.utils.GitHubUtils;
|
|||
import net.frankheijden.serverutils.common.utils.VersionUtils;
|
||||
import net.frankheijden.serverutilsupdater.common.Updater;
|
||||
|
||||
public class UpdateCheckerTask<U extends ServerUtilsPlugin<P, ?, ?, ?>, P> implements Runnable {
|
||||
public class UpdateCheckerTask<U extends ServerUtilsPlugin<P, ?, ?, ?, ?>, P> implements Runnable {
|
||||
|
||||
private final U plugin;
|
||||
private final ServerCommandSender<?> sender;
|
||||
|
|
@ -60,7 +60,7 @@ public class UpdateCheckerTask<U extends ServerUtilsPlugin<P, ?, ?, ?>, P> imple
|
|||
* Checks for updates if enabled per config for the specific action.
|
||||
* Action must be 'login' or 'boot'.
|
||||
*/
|
||||
public static <U extends ServerUtilsPlugin<P, ?, ?, ?>, P> void tryStart(
|
||||
public static <U extends ServerUtilsPlugin<P, ?, ?, ?, ?>, P> void tryStart(
|
||||
U plugin,
|
||||
ServerCommandSender<?> sender,
|
||||
String action
|
||||
|
|
@ -75,7 +75,7 @@ public class UpdateCheckerTask<U extends ServerUtilsPlugin<P, ?, ?, ?>, P> imple
|
|||
* Checks for updates and downloads/installs if configured.
|
||||
* Action must be 'login' or 'boot'.
|
||||
*/
|
||||
public static <U extends ServerUtilsPlugin<P, ?, ?, ?>, P> void start(
|
||||
public static <U extends ServerUtilsPlugin<P, ?, ?, ?, ?>, P> void start(
|
||||
U plugin,
|
||||
ServerCommandSender<?> sender,
|
||||
String action
|
||||
|
|
@ -241,21 +241,19 @@ public class UpdateCheckerTask<U extends ServerUtilsPlugin<P, ?, ?, ?>, P> imple
|
|||
|
||||
private void tryReloadPlugin(File pluginFile, File updaterFile) {
|
||||
plugin.getTaskManager().runTask(() -> {
|
||||
LoadResult<P> loadResult = plugin.getPluginManager().loadPlugin(updaterFile);
|
||||
PluginResult<P> loadResult = plugin.getPluginManager().loadPlugin(updaterFile);
|
||||
if (!loadResult.isSuccess()) {
|
||||
plugin.getLogger().log(Level.INFO, UPDATER_LOAD_ERROR,
|
||||
loadResult.getResult().name());
|
||||
plugin.getLogger().log(Level.INFO, UPDATER_LOAD_ERROR, loadResult.getResult().name());
|
||||
return;
|
||||
}
|
||||
|
||||
P updaterPlugin = loadResult.get();
|
||||
Result result = plugin.getPluginManager().enablePlugin(updaterPlugin);
|
||||
if (result != Result.SUCCESS && result != Result.ALREADY_ENABLED) {
|
||||
plugin.getLogger().log(Level.INFO, UPDATER_ENABLE_ERROR, result.name());
|
||||
PluginResult<P> enableResult = plugin.getPluginManager().enablePlugin(loadResult.getPlugin());
|
||||
if (!enableResult.isSuccess() && enableResult.getResult() != Result.ALREADY_ENABLED) {
|
||||
plugin.getLogger().log(Level.INFO, UPDATER_ENABLE_ERROR, enableResult.getResult().name());
|
||||
return;
|
||||
}
|
||||
|
||||
Updater updater = (Updater) plugin.getPluginManager().getInstance(updaterPlugin);
|
||||
Updater updater = (Updater) plugin.getPluginManager().getInstance(enableResult.getPlugin());
|
||||
updater.update(pluginFile);
|
||||
updaterFile.delete();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
package net.frankheijden.serverutils.common.utils;
|
||||
|
||||
import com.google.common.graph.Graph;
|
||||
import com.google.common.graph.GraphBuilder;
|
||||
import com.google.common.graph.MutableGraph;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class DependencyUtils {
|
||||
|
||||
private DependencyUtils() {}
|
||||
|
||||
/**
|
||||
* Determines the topological order of a dependency map.
|
||||
* Adapted from https://github.com/VelocityPowered/Velocity.
|
||||
* @throws IllegalStateException Iff circular dependency.
|
||||
*/
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public static <T> List<T> determineOrder(Map<T, Set<T>> dependencyMap) throws IllegalStateException {
|
||||
MutableGraph<T> dependencyGraph = GraphBuilder.directed().allowsSelfLoops(true).build();
|
||||
for (T node : dependencyMap.keySet()) {
|
||||
dependencyGraph.addNode(node);
|
||||
}
|
||||
|
||||
for (Map.Entry<T, Set<T>> entry : dependencyMap.entrySet()) {
|
||||
for (T dependency : entry.getValue()) {
|
||||
dependencyGraph.putEdge(entry.getKey(), dependency);
|
||||
}
|
||||
}
|
||||
|
||||
List<T> orderedList = new ArrayList<>(dependencyMap.size());
|
||||
Map<T, Mark> marks = new HashMap<>(dependencyMap.size());
|
||||
|
||||
for (T node : dependencyGraph.nodes()) {
|
||||
visitNode(dependencyGraph, node, marks, orderedList, new LinkedList<>());
|
||||
}
|
||||
|
||||
return orderedList;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
private static <T> void visitNode(
|
||||
Graph<T> dependencyGraph,
|
||||
T node,
|
||||
Map<T, Mark> marks,
|
||||
List<T> orderedList,
|
||||
Deque<T> currentIteration
|
||||
) throws IllegalStateException {
|
||||
Mark mark = marks.getOrDefault(node, Mark.NOT_VISITED);
|
||||
if (mark == Mark.PERMANENT) {
|
||||
return;
|
||||
} else if (mark == Mark.TEMPORARY) {
|
||||
currentIteration.addLast(node);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (T currentNode : currentIteration) {
|
||||
sb.append(" -> ").append(currentNode);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Circular dependency detected: " + sb.substring(4));
|
||||
}
|
||||
|
||||
currentIteration.addLast(node);
|
||||
marks.put(node, Mark.TEMPORARY);
|
||||
|
||||
for (T successorNode : dependencyGraph.successors(node)) {
|
||||
visitNode(dependencyGraph, successorNode, marks, orderedList, currentIteration);
|
||||
}
|
||||
|
||||
marks.put(node, Mark.PERMANENT);
|
||||
currentIteration.removeLast();
|
||||
orderedList.add(node);
|
||||
}
|
||||
|
||||
private enum Mark {
|
||||
NOT_VISITED,
|
||||
TEMPORARY,
|
||||
PERMANENT
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -41,21 +41,21 @@
|
|||
"main": "loadplugin",
|
||||
"aliases": ["lp"],
|
||||
"permission": "serverutils.loadplugin",
|
||||
"description": "Loads the specified jar file as a plugin.",
|
||||
"description": "Loads the specified jar file(s).",
|
||||
"display-in-help": true
|
||||
},
|
||||
"unloadplugin": {
|
||||
"main": "unloadplugin",
|
||||
"aliases": ["up"],
|
||||
"permission": "serverutils.unloadplugin",
|
||||
"description": "Disables and unloads the specified plugin.",
|
||||
"description": "Disables and unloads the specified plugin(s).",
|
||||
"display-in-help": true
|
||||
},
|
||||
"reloadplugin": {
|
||||
"main": "reloadplugin",
|
||||
"aliases": ["rp"],
|
||||
"permission": "serverutils.reloadplugin",
|
||||
"description": "Reloads the specified plugin.",
|
||||
"description": "Reloads the specified plugin(s).",
|
||||
"display-in-help": true
|
||||
},
|
||||
"watchplugin": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package net.frankheijden.serverutils.common.utils;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.junit.jupiter.params.provider.Arguments.of;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
class DependencyUtilsTest {
|
||||
|
||||
@ParameterizedTest(name = "dependencyMap = {0}, expected = {1}")
|
||||
@MethodSource("dependencyGenerator")
|
||||
void determineOrderDependencies(
|
||||
Map<String, Set<String>> dependencyMap,
|
||||
List<String> expected
|
||||
) {
|
||||
assertThat(DependencyUtils.determineOrder(dependencyMap)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "dependencyMap = {0}")
|
||||
@MethodSource("circularDependencyGenerator")
|
||||
void determineOrderCircularDependencies(
|
||||
Map<String, Set<String>> dependencyMap
|
||||
) {
|
||||
assertThatIllegalStateException().isThrownBy(() -> DependencyUtils.determineOrder(dependencyMap));
|
||||
}
|
||||
|
||||
private static Stream<Arguments> dependencyGenerator() {
|
||||
return Stream.of(
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("B", asSet("A"))
|
||||
),
|
||||
asList("A", "B")
|
||||
),
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("B", asSet("A")),
|
||||
new Pair<>("C", asSet("A", "B"))
|
||||
),
|
||||
asList("A", "B", "C")
|
||||
),
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("A", asSet("B")),
|
||||
new Pair<>("B", asSet("C", "D")),
|
||||
new Pair<>("C", asSet()),
|
||||
new Pair<>("D", asSet("C", "E")),
|
||||
new Pair<>("E", asSet("F")),
|
||||
new Pair<>("F", asSet("C"))
|
||||
),
|
||||
asList("C", "F", "E", "D", "B", "A")
|
||||
),
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("A", asSet()),
|
||||
new Pair<>("B", asSet()),
|
||||
new Pair<>("C", asSet()),
|
||||
new Pair<>("D", asSet("C"))
|
||||
),
|
||||
asList("A", "B", "C", "D")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> circularDependencyGenerator() {
|
||||
return Stream.of(
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("A", asSet("A"))
|
||||
)
|
||||
),
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("A", asSet("B")),
|
||||
new Pair<>("B", asSet("A"))
|
||||
)
|
||||
),
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("B", asSet("A")),
|
||||
new Pair<>("C", asSet("A", "B")),
|
||||
new Pair<>("A", asSet("C"))
|
||||
)
|
||||
),
|
||||
of(
|
||||
mapOf(
|
||||
new Pair<>("A", asSet("B")),
|
||||
new Pair<>("B", asSet("C")),
|
||||
new Pair<>("C", asSet("D")),
|
||||
new Pair<>("D", asSet("A"))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static <T> Set<T> asSet(T... elements) {
|
||||
return new HashSet<>(asList(elements));
|
||||
}
|
||||
|
||||
private static <K, V> Map<K, V> mapOf(Pair<K, V>... pairs) {
|
||||
Map<K, V> map = new HashMap<>();
|
||||
for (Pair<K, V> pair : pairs) {
|
||||
map.put(pair.first, pair.second);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static final class Pair<A, B> {
|
||||
private final A first;
|
||||
private final B second;
|
||||
|
||||
private Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue