From 0088bc59c2c9508fb413339c19ab2c35d60ffd46 Mon Sep 17 00:00:00 2001 From: Pingex Date: Sat, 23 Jul 2016 21:30:01 +0200 Subject: [PATCH] Plugins event handling through IWithEventHandlers. --- .../pingex/dcf/core/CoreEventsHandler.java | 49 ++++++++ .../dcf/core/GatewayConnectionsManager.java | 5 +- .../pingex/dcf/modularity/PluginLoader.java | 9 +- .../pingex/dcf/modularity/PluginWrapper.java | 6 + .../dcf/modularity/events/EventManager.java | 105 ++++++++++++++++++ .../modularity/events/IWithEventHandlers.java | 15 +++ 6 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 src/main/java/net/pingex/dcf/modularity/events/EventManager.java create mode 100644 src/main/java/net/pingex/dcf/modularity/events/IWithEventHandlers.java diff --git a/src/main/java/net/pingex/dcf/core/CoreEventsHandler.java b/src/main/java/net/pingex/dcf/core/CoreEventsHandler.java index 5138637..d342ba2 100644 --- a/src/main/java/net/pingex/dcf/core/CoreEventsHandler.java +++ b/src/main/java/net/pingex/dcf/core/CoreEventsHandler.java @@ -1,5 +1,7 @@ package net.pingex.dcf.core; +import net.pingex.dcf.modularity.PluginWrapper; +import net.pingex.dcf.modularity.events.EventManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import sx.blah.discord.api.events.EventSubscriber; @@ -20,6 +22,7 @@ public class CoreEventsHandler public static void onReady(ReadyEvent event) { LOGGER.info("Connection with user #{} ready.", event.getClient().getOurUser().getID()); + EventManager.getInstance().updateConnectionHandlers(event.getClient()); } @EventSubscriber @@ -63,4 +66,50 @@ public class CoreEventsHandler { LOGGER.info("Joined guild #{}.", event.getGuild().getID()); } + + /** + * Called whenever a new plugin has been preloaded. + * @param plugin Target plugin + */ + public static void pluginPreloaded(PluginWrapper plugin) + { + + } + + /** + * Called whenever a new plugin has been laoded. + * @param plugin Target plugin + */ + public static void pluginLoaded(PluginWrapper plugin) + { + + } + + /** + * Called whenever a plugin is running. + * @param plugin Target plugin + */ + public static void pluginRunning(PluginWrapper plugin) + { + EventManager.getInstance().checkAndRegister(plugin); // Hook: event handlers + // TODO: Hook: commands + } + + /** + * Called whenever a plugin has stopped. + * @param plugin Target plugin + */ + public static void pluginStopped(PluginWrapper plugin) + { + EventManager.getInstance().unregister(plugin); // Hook: event handlers + } + + /** + * Called whenever a plugin has unloaded. + * @param plugin Target plugin + */ + public static void pluginUnloaded(PluginWrapper plugin) + { + + } } diff --git a/src/main/java/net/pingex/dcf/core/GatewayConnectionsManager.java b/src/main/java/net/pingex/dcf/core/GatewayConnectionsManager.java index c2e0a04..f843d42 100644 --- a/src/main/java/net/pingex/dcf/core/GatewayConnectionsManager.java +++ b/src/main/java/net/pingex/dcf/core/GatewayConnectionsManager.java @@ -66,7 +66,6 @@ public class GatewayConnectionsManager IDiscordClient builtConnection = builder.login(); connectionsDatastore.add(builtConnection); builtConnection.getDispatcher().registerListener(CoreEventsHandler.class); // Register the core event handler independently from the events package - //updateListeners(builtConnection, null); // TODO: EventRegistry } catch (DiscordException e) { @@ -92,7 +91,7 @@ public class GatewayConnectionsManager * @param target Target conection, must be registered * @param refListeners Reference listeners list */ - public void updateListeners(IDiscordClient target, Set refListeners) + public void updateListeners(IDiscordClient target, Set> refListeners) { LOGGER.debug("Updating listeners for target " + target.getOurUser().getID()); @@ -124,7 +123,7 @@ public class GatewayConnectionsManager * Update all connections listeners * @param refListeners Reference listeners list */ - public void updateAllListeners(Set refListeners) + public void updateAllListeners(Set> refListeners) { for(IDiscordClient i : connectionsDatastore) updateListeners(i, refListeners); } diff --git a/src/main/java/net/pingex/dcf/modularity/PluginLoader.java b/src/main/java/net/pingex/dcf/modularity/PluginLoader.java index 0560fe6..ee1271f 100644 --- a/src/main/java/net/pingex/dcf/modularity/PluginLoader.java +++ b/src/main/java/net/pingex/dcf/modularity/PluginLoader.java @@ -1,6 +1,7 @@ package net.pingex.dcf.modularity; import net.pingex.dcf.core.Configuration; +import net.pingex.dcf.core.CoreEventsHandler; import org.apache.commons.io.FilenameUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -128,9 +129,11 @@ public class PluginLoader { try { - plugins.put(clazz.getAnnotation(Plugin.class).id(), new PluginWrapper(clazz.asSubclass(IPlugin.class), classLoader)); + PluginWrapper plugin = new PluginWrapper(clazz.asSubclass(IPlugin.class), classLoader); + plugins.put(clazz.getAnnotation(Plugin.class).id(), plugin); LOGGER.debug("Plugin {} {} preloaded.", clazz.getAnnotation(Plugin.class).id(), clazz.getAnnotation(Plugin.class).version()); counter++; + CoreEventsHandler.pluginPreloaded(plugin); } catch(IllegalAccessException | InstantiationException e) { @@ -182,6 +185,7 @@ public class PluginLoader plugin.getInstance().load(Configuration.getStore()); plugin.setState(PluginState.LOADED); LOGGER.info("Loaded plugin {}.", id); + CoreEventsHandler.pluginLoaded(plugin); } catch(Throwable throwable) { @@ -229,6 +233,7 @@ public class PluginLoader plugin.getInstance().run(); LOGGER.info("Plugin {} is now running. (last state: {})", id, plugin.getState()); plugin.setState(PluginState.RUNNING); + CoreEventsHandler.pluginRunning(plugin); } catch(Throwable throwable) { @@ -263,6 +268,7 @@ public class PluginLoader plugin.getInstance().stop(); LOGGER.info("Stopped plugin {}.", id); plugin.setState(PluginState.STOPPED); + CoreEventsHandler.pluginStopped(plugin); } /** @@ -291,6 +297,7 @@ public class PluginLoader plugin.getInstance().unload(); LOGGER.info("Unloaded plugin {}.", id); plugin.setState(PluginState.UNLOADED); + CoreEventsHandler.pluginUnloaded(plugin); } /** diff --git a/src/main/java/net/pingex/dcf/modularity/PluginWrapper.java b/src/main/java/net/pingex/dcf/modularity/PluginWrapper.java index 788229f..81f1cd0 100644 --- a/src/main/java/net/pingex/dcf/modularity/PluginWrapper.java +++ b/src/main/java/net/pingex/dcf/modularity/PluginWrapper.java @@ -101,4 +101,10 @@ public class PluginWrapper { this.state = state; } + + @Override + public boolean equals(Object obj) + { + return obj instanceof PluginWrapper && id.equals(((PluginWrapper) obj).getId()); + } } diff --git a/src/main/java/net/pingex/dcf/modularity/events/EventManager.java b/src/main/java/net/pingex/dcf/modularity/events/EventManager.java new file mode 100644 index 0000000..fe93982 --- /dev/null +++ b/src/main/java/net/pingex/dcf/modularity/events/EventManager.java @@ -0,0 +1,105 @@ +package net.pingex.dcf.modularity.events; + +import net.pingex.dcf.core.GatewayConnectionsManager; +import net.pingex.dcf.modularity.PluginWrapper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import sx.blah.discord.api.IDiscordClient; +import java.util.HashSet; +import java.util.Set; + +/** + * Contains all foreign event handlers for D4J. + */ +public class EventManager +{ + /** + * Singleton instance. + */ + private static EventManager ourInstance = new EventManager(); + + /** + * Logger + */ + private static Logger LOGGER = LogManager.getLogger(EventManager.class); + + /** + * Get current instance + * @return The unique instance. + */ + public static EventManager getInstance() + { + return ourInstance; + } + + /** + * Contains all plugins which implements IWithEvents + */ + private Set handlers; + + /** + * Enforce singleton. + */ + private EventManager() + { + handlers = new HashSet<>(); + } + + /** + * Check that the plugin has event handlers and register it to active handlers pool. + * @param plugin Target plugin. + */ + public void checkAndRegister(PluginWrapper plugin) + { + LOGGER.trace("Checking {} for event handlers.", plugin.getId()); + + if(IWithEventHandlers.class.isAssignableFrom(plugin.getPluginClass())) + { + LOGGER.debug("Registering event handlers for plugin {}.", plugin.getId()); + handlers.add(plugin); + updateConnectionsHandlers(); // Trigger update + } + else LOGGER.trace("Plugin {} has no event handlers.", plugin.getId()); + } + + /** + * Unregister plugin from active handlers pool. + * @param plugin Target plugin. + */ + public void unregister(PluginWrapper plugin) + { + if(handlers.contains(plugin)) + { + LOGGER.debug("Unregistering event handlers for plugin {}.", plugin.getId()); + handlers.remove(plugin); + updateConnectionsHandlers(); // Trigger update + } + } + + /** + * Collect all event handlers into a single set + * @return Final set + */ + public Set> collectAllHandlers() + { + Set> toReturn = new HashSet<>(); + handlers.forEach(pluginWrapper -> toReturn.addAll(((IWithEventHandlers) pluginWrapper.getInstance()).getEventHandlers())); + return toReturn; + } + + /** + * Delegated method + */ + public void updateConnectionsHandlers() + { + GatewayConnectionsManager.getInstance().updateAllListeners(collectAllHandlers()); + } + + /** + * Delegated method + */ + public void updateConnectionHandlers(IDiscordClient target) + { + GatewayConnectionsManager.getInstance().updateListeners(target, collectAllHandlers()); + } +} diff --git a/src/main/java/net/pingex/dcf/modularity/events/IWithEventHandlers.java b/src/main/java/net/pingex/dcf/modularity/events/IWithEventHandlers.java new file mode 100644 index 0000000..126aad6 --- /dev/null +++ b/src/main/java/net/pingex/dcf/modularity/events/IWithEventHandlers.java @@ -0,0 +1,15 @@ +package net.pingex.dcf.modularity.events; + +import java.util.Set; + +/** + * Interface which indicates that the plugin has event handlers. + */ +public interface IWithEventHandlers +{ + /** + * Gives all event handlers classes for the plugin. + * @return All events handlers to submit to D4J. + */ + Set> getEventHandlers(); +}