Commit 292b1719 authored by Adam Gausmann's avatar Adam Gausmann

Add plugin system implementation

parent 5f22f990
......@@ -4,6 +4,7 @@ import ninja.nonemu.samurai.command.CommandSystem;
import ninja.nonemu.samurai.connection.ConnectionManager;
import ninja.nonemu.samurai.event.EventHandler;
import ninja.nonemu.samurai.event.EventSystem;
import ninja.nonemu.samurai.plugin.PluginManager;
import org.apache.logging.log4j.Logger;
/**
......@@ -24,6 +25,8 @@ public interface Bot {
CommandSystem getCommandSystem();
PluginManager getPluginManager();
String getProperty(String name);
void quit(int status);
......
......@@ -9,6 +9,7 @@ import ninja.nonemu.samurai.Bot;
import ninja.nonemu.samurai.command.CommandExecutor;
import ninja.nonemu.samurai.command.CommandInfo;
import ninja.nonemu.samurai.command.CommandSender;
import org.apache.logging.log4j.Logger;
/**
* A highly-recommended subclass for plugins that are implemented using the JAR loading mechanism.
......@@ -23,11 +24,13 @@ public abstract class PluginBase implements Plugin, CommandExecutor {
}
private final Bot bot;
private final Logger logger;
private final Properties properties;
private final String name;
protected PluginBase(String name) {
bot = defaultBot;
logger = bot.getLogger();
properties = new Properties();
this.name = name;
}
......@@ -91,6 +94,13 @@ public abstract class PluginBase implements Plugin, CommandExecutor {
return name;
}
/**
* Gets the logger associated with this plugin.
*/
protected Logger getLogger() {
return logger;
}
@Override
public boolean onCommand(CommandSender sender, CommandInfo info, String label, String[] args) throws Exception {
return false;
......
......@@ -8,6 +8,8 @@ import java.util.Properties;
import ninja.nonemu.samurai.command.CommandSystemImpl;
import ninja.nonemu.samurai.connection.ConnectionManagerImpl;
import ninja.nonemu.samurai.event.EventSystemImpl;
import ninja.nonemu.samurai.plugin.PluginManager;
import ninja.nonemu.samurai.plugin.PluginManagerImpl;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -18,11 +20,14 @@ public class BotImpl implements Bot {
bot.init();
while (bot.isRunning()) {
try {
while (bot.isRunning()) {
bot.run();
}
} finally {
bot.cleanup();
}
bot.cleanup();
System.exit(bot.exitCode);
}
......@@ -31,6 +36,7 @@ public class BotImpl implements Bot {
private final EventSystemImpl eventSystem;
private final ConnectionManagerImpl connectionManager;
private final CommandSystemImpl commandSystem;
private final PluginManagerImpl pluginManager;
private boolean running;
private int exitCode;
......@@ -40,6 +46,7 @@ public class BotImpl implements Bot {
eventSystem = new EventSystemImpl(this);
connectionManager = new ConnectionManagerImpl(this);
commandSystem = new CommandSystemImpl(this);
pluginManager = new PluginManagerImpl(this);
}
public void init() {
......@@ -64,18 +71,22 @@ public class BotImpl implements Bot {
eventSystem.init();
connectionManager.init();
commandSystem.init();
pluginManager.init();
}
public void run() {
pluginManager.run();
commandSystem.run();
connectionManager.run();
eventSystem.run();
commandSystem.run();
}
public void cleanup() {
logger.debug("Cleaning up bot");
pluginManager.cleanup();
commandSystem.cleanup();
connectionManager.cleanup();
eventSystem.cleanup();
......@@ -107,6 +118,11 @@ public class BotImpl implements Bot {
return commandSystem;
}
@Override
public PluginManager getPluginManager() {
return pluginManager;
}
@Override
public String getProperty(String name) {
return properties.getProperty(name);
......
package ninja.nonemu.samurai.plugin;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.TreeMap;
import java.util.jar.JarFile;
import ninja.nonemu.samurai.BotImpl;
import org.apache.logging.log4j.Logger;
public class PluginManagerImpl implements PluginManager {
private final BotImpl bot;
private final Logger logger;
private final Map<String, Plugin> plugins;
public PluginManagerImpl(BotImpl bot) {
this.bot = bot;
logger = bot.getLogger();
plugins = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
}
public void init() {
logger.trace("Initializing plugin manager");
logger.debug("Loading JAR plugins");
File pluginDir = new File("./plugins");
if (pluginDir.exists()) {
File[] files = pluginDir.listFiles((dir, name) -> name.matches(".jar$"));
if (files != null) {
for (File file : files) {
try {
JarFile jarFile = new JarFile(file);
String className = jarFile.getManifest().getMainAttributes().getValue("Plugin-Class");
logger.info("Loading plugin " + className);
URLClassLoader classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}, getClass().getClassLoader());
Class<?> pluginClass = classLoader.loadClass(className);
if (!PluginBase.class.isAssignableFrom(pluginClass)) {
logger.error("Plugin class does not extend PluginBase, skipping");
continue;
}
PluginBase.setDefaultBot(bot);
PluginBase plugin = (PluginBase) pluginClass.getConstructor().newInstance();
registerPlugin(plugin);
} catch (IOException e) {
logger.error("I/O error while loading plugin. Check to see that your manifest file exists.", e);
} catch (ClassNotFoundException e) {
logger.error("Cannot find the specified plugin class", e);
} catch (NoSuchMethodException e) {
logger.error("Cannot load plugin. Make sure it has a constructor with no arguments.", e);
} catch (InstantiationException e) {
logger.error("Cannot load plugin. Make sure it it is not abstract and has a proper constructor.", e);
} catch (InvocationTargetException e) {
logger.error("Cannot load plugin. It threw an error during construction.", e);
} catch (IllegalAccessException e) {
logger.error("Cannot load plugin. Make sure the bot can access the plugin class.", e);
}
}
}
} else {
pluginDir.mkdir();
}
}
public void run() {
}
public void cleanup() {
logger.trace("Cleaning up plugin manager");
}
@Override
public void registerPlugin(Plugin plugin, String name) {
if (plugins.containsKey(name)) {
throw new IllegalStateException("A plugin is already registered with that name");
}
plugins.put(name, plugin);
plugin.init();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment