mirror of
https://github.com/PaperMC/Waterfall.git
synced 2024-11-16 07:15:14 +01:00
700 lines
29 KiB
Diff
700 lines
29 KiB
Diff
From 47a27d5323e96b3cb1bbcee998d413017eff43b0 Mon Sep 17 00:00:00 2001
|
|
From: theminecoder <theminecoder.dev@gmail.com>
|
|
Date: Wed, 22 Apr 2020 14:00:44 +1000
|
|
Subject: [PATCH] Add exception reporting event
|
|
|
|
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/event/ProxyExceptionEvent.java b/api/src/main/java/io/github/waterfallmc/waterfall/event/ProxyExceptionEvent.java
|
|
new file mode 100644
|
|
index 00000000..ee6cb5dd
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/event/ProxyExceptionEvent.java
|
|
@@ -0,0 +1,27 @@
|
|
+package io.github.waterfallmc.waterfall.event;
|
|
+
|
|
+import com.google.common.base.Preconditions;
|
|
+import io.github.waterfallmc.waterfall.exception.ProxyException;
|
|
+import net.md_5.bungee.api.plugin.Event;
|
|
+
|
|
+/**
|
|
+ * Called whenever an exception is thrown in a recoverable section of the server.
|
|
+ */
|
|
+public class ProxyExceptionEvent extends Event {
|
|
+
|
|
+ private ProxyException exception;
|
|
+
|
|
+ public ProxyExceptionEvent(ProxyException exception) {
|
|
+ this.exception = Preconditions.checkNotNull(exception, "exception");
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the wrapped exception that was thrown.
|
|
+ *
|
|
+ * @return Exception thrown
|
|
+ */
|
|
+ public ProxyException getException() {
|
|
+ return exception;
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyCommandException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyCommandException.java
|
|
new file mode 100644
|
|
index 00000000..644a4cd6
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyCommandException.java
|
|
@@ -0,0 +1,64 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import net.md_5.bungee.api.CommandSender;
|
|
+import net.md_5.bungee.api.plugin.Command;
|
|
+
|
|
+import static com.google.common.base.Preconditions.checkNotNull;
|
|
+
|
|
+/**
|
|
+ * Thrown when a command throws an exception
|
|
+ */
|
|
+public class ProxyCommandException extends ProxyException {
|
|
+
|
|
+ private final Command command;
|
|
+ private final CommandSender commandSender;
|
|
+ private final String[] arguments;
|
|
+
|
|
+ public ProxyCommandException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
|
+ super(message, cause);
|
|
+ this.commandSender = checkNotNull(commandSender, "commandSender");
|
|
+ this.arguments = checkNotNull(arguments, "arguments");
|
|
+ this.command = checkNotNull(command, "command");
|
|
+ }
|
|
+
|
|
+ public ProxyCommandException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
|
+ super(cause);
|
|
+ this.commandSender = checkNotNull(commandSender, "commandSender");
|
|
+ this.arguments = checkNotNull(arguments, "arguments");
|
|
+ this.command = checkNotNull(command, "command");
|
|
+ }
|
|
+
|
|
+ protected ProxyCommandException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace);
|
|
+ this.commandSender = checkNotNull(commandSender, "commandSender");
|
|
+ this.arguments = checkNotNull(arguments, "arguments");
|
|
+ this.command = checkNotNull(command, "command");
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the command which threw the exception
|
|
+ *
|
|
+ * @return exception throwing command
|
|
+ */
|
|
+ public Command getCommand() {
|
|
+ return command;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the command sender which executed the command request
|
|
+ *
|
|
+ * @return command sender of exception thrown command request
|
|
+ */
|
|
+ public CommandSender getCommandSender() {
|
|
+ return commandSender;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the arguments which threw the exception for the command
|
|
+ *
|
|
+ * @return arguments of exception thrown command request
|
|
+ */
|
|
+ public String[] getArguments() {
|
|
+ return arguments;
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyEventException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyEventException.java
|
|
new file mode 100644
|
|
index 00000000..b9842dc5
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyEventException.java
|
|
@@ -0,0 +1,53 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import net.md_5.bungee.api.plugin.Event;
|
|
+import net.md_5.bungee.api.plugin.Listener;
|
|
+
|
|
+import static com.google.common.base.Preconditions.checkNotNull;
|
|
+
|
|
+/**
|
|
+ * Exception thrown when a server event listener throws an exception
|
|
+ */
|
|
+//TODO Find a better way to retrieve the plugin for this. Currently the event register/bake process
|
|
+// doesnt leave a reference to the plugin so there's no way to know what one is being used at any given time
|
|
+public class ProxyEventException extends ProxyException {
|
|
+
|
|
+ private final Listener listener;
|
|
+ private final Event event;
|
|
+
|
|
+ public ProxyEventException(String message, Throwable cause, Listener listener, Event event) {
|
|
+ super(message, cause);
|
|
+ this.listener = checkNotNull(listener, "listener");
|
|
+ this.event = checkNotNull(event, "event");
|
|
+ }
|
|
+
|
|
+ public ProxyEventException(Throwable cause, Listener listener, Event event) {
|
|
+ super(cause);
|
|
+ this.listener = checkNotNull(listener, "listener");
|
|
+ this.event = checkNotNull(event, "event");
|
|
+ }
|
|
+
|
|
+ protected ProxyEventException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Listener listener, Event event) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace);
|
|
+ this.listener = checkNotNull(listener, "listener");
|
|
+ this.event = checkNotNull(event, "event");
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the listener which threw the exception
|
|
+ *
|
|
+ * @return event listener
|
|
+ */
|
|
+ public Listener getListener() {
|
|
+ return listener;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the event which caused the exception
|
|
+ *
|
|
+ * @return event
|
|
+ */
|
|
+ public Event getEvent() {
|
|
+ return event;
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyException.java
|
|
new file mode 100644
|
|
index 00000000..b9fbbbe8
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyException.java
|
|
@@ -0,0 +1,23 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+/**
|
|
+ * Wrapper exception for all exceptions that are thrown by the server.
|
|
+ */
|
|
+public class ProxyException extends Exception {
|
|
+
|
|
+ public ProxyException(String message) {
|
|
+ super(message);
|
|
+ }
|
|
+
|
|
+ public ProxyException(String message, Throwable cause) {
|
|
+ super(message, cause);
|
|
+ }
|
|
+
|
|
+ public ProxyException(Throwable cause) {
|
|
+ super(cause);
|
|
+ }
|
|
+
|
|
+ protected ProxyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace);
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyInternalException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyInternalException.java
|
|
new file mode 100644
|
|
index 00000000..acc64c29
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyInternalException.java
|
|
@@ -0,0 +1,34 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import io.github.waterfallmc.waterfall.event.ProxyExceptionEvent;
|
|
+import net.md_5.bungee.api.ProxyServer;
|
|
+
|
|
+/**
|
|
+ * Thrown when the internal server throws a recoverable exception.
|
|
+ */
|
|
+public class ProxyInternalException extends ProxyException {
|
|
+
|
|
+ public ProxyInternalException(String message) {
|
|
+ super(message);
|
|
+ }
|
|
+
|
|
+ public ProxyInternalException(String message, Throwable cause) {
|
|
+ super(message, cause);
|
|
+ }
|
|
+
|
|
+ public ProxyInternalException(Throwable cause) {
|
|
+ super(cause);
|
|
+ }
|
|
+
|
|
+ protected ProxyInternalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace);
|
|
+ }
|
|
+
|
|
+ public static void reportInternalException(Throwable cause) {
|
|
+ try {
|
|
+ ProxyServer.getInstance().getPluginManager().callEvent(new ProxyExceptionEvent(new ProxyInternalException(cause)));;
|
|
+ } catch (Throwable t) {
|
|
+ t.printStackTrace(); // Don't want to rethrow!
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginEnableDisableException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginEnableDisableException.java
|
|
new file mode 100644
|
|
index 00000000..54dc7da0
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginEnableDisableException.java
|
|
@@ -0,0 +1,20 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import net.md_5.bungee.api.plugin.Plugin;
|
|
+
|
|
+/**
|
|
+ * Thrown whenever there is an exception with any enabling or disabling of plugins.
|
|
+ */
|
|
+public class ProxyPluginEnableDisableException extends ProxyPluginException {
|
|
+ public ProxyPluginEnableDisableException(String message, Throwable cause, Plugin responsiblePlugin) {
|
|
+ super(message, cause, responsiblePlugin);
|
|
+ }
|
|
+
|
|
+ public ProxyPluginEnableDisableException(Throwable cause, Plugin responsiblePlugin) {
|
|
+ super(cause, responsiblePlugin);
|
|
+ }
|
|
+
|
|
+ protected ProxyPluginEnableDisableException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginException.java
|
|
new file mode 100644
|
|
index 00000000..b0de7a4b
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginException.java
|
|
@@ -0,0 +1,36 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import net.md_5.bungee.api.plugin.Plugin;
|
|
+
|
|
+import static com.google.common.base.Preconditions.checkNotNull;
|
|
+
|
|
+/**
|
|
+ * Wrapper exception for all cases to which a plugin can be immediately blamed for
|
|
+ */
|
|
+public class ProxyPluginException extends ProxyException {
|
|
+ public ProxyPluginException(String message, Throwable cause, Plugin responsiblePlugin) {
|
|
+ super(message, cause);
|
|
+ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
|
|
+ }
|
|
+
|
|
+ public ProxyPluginException(Throwable cause, Plugin responsiblePlugin) {
|
|
+ super(cause);
|
|
+ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
|
|
+ }
|
|
+
|
|
+ protected ProxyPluginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace);
|
|
+ this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
|
|
+ }
|
|
+
|
|
+ private final Plugin responsiblePlugin;
|
|
+
|
|
+ /**
|
|
+ * Gets the plugin which is directly responsible for the exception being thrown
|
|
+ *
|
|
+ * @return plugin which is responsible for the exception throw
|
|
+ */
|
|
+ public Plugin getResponsiblePlugin() {
|
|
+ return responsiblePlugin;
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginMessageException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginMessageException.java
|
|
new file mode 100644
|
|
index 00000000..9e24e09c
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyPluginMessageException.java
|
|
@@ -0,0 +1,64 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
+import net.md_5.bungee.api.plugin.Plugin;
|
|
+
|
|
+import static com.google.common.base.Preconditions.checkNotNull;
|
|
+
|
|
+/**
|
|
+ * Thrown when an incoming plugin message channel throws an exception
|
|
+ */
|
|
+public class ProxyPluginMessageException extends ProxyPluginException {
|
|
+
|
|
+ private final ProxiedPlayer player;
|
|
+ private final String channel;
|
|
+ private final byte[] data;
|
|
+
|
|
+ public ProxyPluginMessageException(String message, Throwable cause, Plugin responsiblePlugin, ProxiedPlayer player, String channel, byte[] data) {
|
|
+ super(message, cause, responsiblePlugin);
|
|
+ this.player = checkNotNull(player, "player");
|
|
+ this.channel = checkNotNull(channel, "channel");
|
|
+ this.data = checkNotNull(data, "data");
|
|
+ }
|
|
+
|
|
+ public ProxyPluginMessageException(Throwable cause, Plugin responsiblePlugin, ProxiedPlayer player, String channel, byte[] data) {
|
|
+ super(cause, responsiblePlugin);
|
|
+ this.player = checkNotNull(player, "player");
|
|
+ this.channel = checkNotNull(channel, "channel");
|
|
+ this.data = checkNotNull(data, "data");
|
|
+ }
|
|
+
|
|
+ protected ProxyPluginMessageException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, ProxiedPlayer player, String channel, byte[] data) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
|
|
+ this.player = checkNotNull(player, "player");
|
|
+ this.channel = checkNotNull(channel, "channel");
|
|
+ this.data = checkNotNull(data, "data");
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the channel to which the error occurred from recieving data from
|
|
+ *
|
|
+ * @return exception channel
|
|
+ */
|
|
+ public String getChannel() {
|
|
+ return channel;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the data to which the error occurred from
|
|
+ *
|
|
+ * @return exception data
|
|
+ */
|
|
+ public byte[] getData() {
|
|
+ return data;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the player which the plugin message causing the exception originated from
|
|
+ *
|
|
+ * @return exception player
|
|
+ */
|
|
+ public ProxiedPlayer getPlayer() {
|
|
+ return player;
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxySchedulerException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxySchedulerException.java
|
|
new file mode 100644
|
|
index 00000000..0d574ecc
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxySchedulerException.java
|
|
@@ -0,0 +1,37 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import net.md_5.bungee.api.scheduler.ScheduledTask;
|
|
+
|
|
+import static com.google.common.base.Preconditions.checkNotNull;
|
|
+
|
|
+/**
|
|
+ * Thrown when a plugin's scheduler fails with an exception
|
|
+ */
|
|
+public class ProxySchedulerException extends ProxyPluginException {
|
|
+
|
|
+ private final ScheduledTask task;
|
|
+
|
|
+ public ProxySchedulerException(String message, Throwable cause, ScheduledTask task) {
|
|
+ super(message, cause, task.getOwner());
|
|
+ this.task = checkNotNull(task, "task");
|
|
+ }
|
|
+
|
|
+ public ProxySchedulerException(Throwable cause, ScheduledTask task) {
|
|
+ super(cause, task.getOwner());
|
|
+ this.task = checkNotNull(task, "task");
|
|
+ }
|
|
+
|
|
+ protected ProxySchedulerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, ScheduledTask task) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace, task.getOwner());
|
|
+ this.task = checkNotNull(task, "task");
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets the task which threw the exception
|
|
+ *
|
|
+ * @return exception throwing task
|
|
+ */
|
|
+ public ScheduledTask getTask() {
|
|
+ return task;
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyTabCompleteException.java b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyTabCompleteException.java
|
|
new file mode 100644
|
|
index 00000000..5bf57ec1
|
|
--- /dev/null
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/exception/ProxyTabCompleteException.java
|
|
@@ -0,0 +1,22 @@
|
|
+package io.github.waterfallmc.waterfall.exception;
|
|
+
|
|
+import net.md_5.bungee.api.CommandSender;
|
|
+import net.md_5.bungee.api.plugin.Command;
|
|
+
|
|
+/**
|
|
+ * Called when a tab-complete request throws an exception
|
|
+ */
|
|
+public class ProxyTabCompleteException extends ProxyCommandException {
|
|
+
|
|
+ public ProxyTabCompleteException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
|
+ super(message, cause, command, commandSender, arguments);
|
|
+ }
|
|
+
|
|
+ public ProxyTabCompleteException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
|
+ super(cause, command, commandSender, arguments);
|
|
+ }
|
|
+
|
|
+ protected ProxyTabCompleteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) {
|
|
+ super(message, cause, enableSuppression, writableStackTrace, command, commandSender, arguments);
|
|
+ }
|
|
+}
|
|
diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
|
|
index 4180c995..90031156 100644
|
|
--- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
|
|
+++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
|
|
@@ -26,6 +26,11 @@ import java.util.Stack;
|
|
import java.util.jar.JarEntry;
|
|
import java.util.jar.JarFile;
|
|
import java.util.logging.Level;
|
|
+import io.github.waterfallmc.waterfall.event.ProxyExceptionEvent; // Waterfall
|
|
+import io.github.waterfallmc.waterfall.exception.ProxyCommandException; // Waterfall
|
|
+import io.github.waterfallmc.waterfall.exception.ProxyEventException; // Waterfall
|
|
+import io.github.waterfallmc.waterfall.exception.ProxyPluginEnableDisableException; // Waterfall
|
|
+import io.github.waterfallmc.waterfall.exception.ProxyTabCompleteException; // Waterfall
|
|
import lombok.RequiredArgsConstructor;
|
|
import net.md_5.bungee.api.ChatColor;
|
|
import net.md_5.bungee.api.CommandSender;
|
|
@@ -33,6 +38,7 @@ import net.md_5.bungee.api.ProxyServer;
|
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
import net.md_5.bungee.event.EventBus;
|
|
import net.md_5.bungee.event.EventHandler;
|
|
+import net.md_5.bungee.event.EventHandlerMethod; //Waterfall - Exception event
|
|
import org.yaml.snakeyaml.Yaml;
|
|
import org.yaml.snakeyaml.constructor.Constructor;
|
|
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
|
@@ -193,10 +199,9 @@ public final class PluginManager
|
|
}
|
|
|
|
String[] args = Arrays.copyOfRange( split, 1, split.length );
|
|
- try
|
|
- {
|
|
if ( tabResults == null )
|
|
{
|
|
+ try { // Waterfall - split command & tab complete exception handlers for exception event
|
|
if ( proxy.getConfig().isLogCommands() )
|
|
{
|
|
proxy.getLogger().log( Level.INFO, "{0} executed command: /{1}", new Object[]
|
|
@@ -205,18 +210,28 @@ public final class PluginManager
|
|
} );
|
|
}
|
|
command.execute( sender, args );
|
|
+ // Waterfall start - split command & tab complete exception handlers for exception event
|
|
+ } catch ( Exception ex ) {
|
|
+ sender.sendMessage( ChatColor.RED + "An internal error occurred whilst executing this command, please check the console log for details." );
|
|
+ ProxyServer.getInstance().getLogger().log( Level.WARNING, "Error in dispatching command", ex );
|
|
+ this.callEvent( new ProxyExceptionEvent( new ProxyCommandException( ex, command, sender, args ) ) ); //Waterfall - throw error event
|
|
+ }
|
|
+ // Waterfall end
|
|
} else if ( commandLine.contains( " " ) && command instanceof TabExecutor )
|
|
{
|
|
+ try { // Waterfall - split command & tab complete exception handlers for exception event
|
|
for ( String s : ( (TabExecutor) command ).onTabComplete( sender, args ) )
|
|
{
|
|
tabResults.add( s );
|
|
}
|
|
- }
|
|
- } catch ( Exception ex )
|
|
- {
|
|
+ // Waterfall start - split command & tab complete exception handlers for exception event
|
|
+ } catch ( Exception ex ) {
|
|
sender.sendMessage( ChatColor.RED + "An internal error occurred whilst executing this command, please check the console log for details." );
|
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Error in dispatching command", ex );
|
|
+ this.callEvent( new ProxyExceptionEvent( new ProxyTabCompleteException( ex, command, sender, args ) ) ); //Waterfall - throw error event
|
|
}
|
|
+ // Waterfall end
|
|
+ }
|
|
return true;
|
|
}
|
|
|
|
@@ -304,7 +319,11 @@ public final class PluginManager
|
|
} );
|
|
} catch ( Throwable t )
|
|
{
|
|
- ProxyServer.getInstance().getLogger().log( Level.WARNING, "Exception encountered when loading plugin: " + plugin.getDescription().getName(), t );
|
|
+ // Waterfall start - throw exception event
|
|
+ String msg = "Exception encountered when loading plugin: " + plugin.getDescription().getName();
|
|
+ ProxyServer.getInstance().getLogger().log( Level.WARNING, msg, t );
|
|
+ this.callEvent( new ProxyExceptionEvent( new ProxyPluginEnableDisableException( msg, t, plugin) ) );
|
|
+ // Waterfall end
|
|
}
|
|
}
|
|
}
|
|
@@ -444,7 +463,7 @@ public final class PluginManager
|
|
Preconditions.checkNotNull( event, "event" );
|
|
|
|
long start = System.nanoTime();
|
|
- eventBus.post( event );
|
|
+ eventBus.post( event, this::handleEventException ); //Waterfall - pass exception handler below
|
|
event.postCall();
|
|
|
|
long elapsed = System.nanoTime() - start;
|
|
@@ -458,6 +477,14 @@ public final class PluginManager
|
|
return event;
|
|
}
|
|
|
|
+ //Waterfall start - Exception handler passed to event bus to fire the exception event
|
|
+ private <T extends Event> void handleEventException(String msg, T event, EventHandlerMethod method, Throwable ex) {
|
|
+ if( !(event instanceof ProxyExceptionEvent) ) {
|
|
+ this.callEvent( new ProxyExceptionEvent( new ProxyEventException( msg, ex, (Listener) method.getListener(), event) ) );
|
|
+ }
|
|
+ }
|
|
+ //Waterfall end
|
|
+
|
|
/**
|
|
* Register a {@link Listener} for receiving called events. Methods in this
|
|
* Object which wish to receive events must be annotated with the
|
|
diff --git a/event/src/main/java/net/md_5/bungee/event/EventBus.java b/event/src/main/java/net/md_5/bungee/event/EventBus.java
|
|
index b3effc8a..adb9f636 100644
|
|
--- a/event/src/main/java/net/md_5/bungee/event/EventBus.java
|
|
+++ b/event/src/main/java/net/md_5/bungee/event/EventBus.java
|
|
@@ -34,7 +34,8 @@ public class EventBus
|
|
this.logger = ( logger == null ) ? Logger.getLogger( Logger.GLOBAL_LOGGER_NAME ) : logger;
|
|
}
|
|
|
|
- public void post(Object event)
|
|
+ // Waterfall - Add generic to signature so we don't have to cast in exception handler
|
|
+ public <T> void post(T event, EventExceptionHandler<T> exceptionHandler)
|
|
{
|
|
EventHandlerMethod[] handlers = byEventBaked.get( event.getClass() );
|
|
|
|
@@ -55,7 +56,9 @@ public class EventBus
|
|
throw new Error( "Method rejected target/argument: " + event, ex );
|
|
} catch ( InvocationTargetException ex )
|
|
{
|
|
- logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() );
|
|
+ String msg = MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() );
|
|
+ logger.log( Level.WARNING, msg, ex.getCause() );
|
|
+ if( exceptionHandler != null ) exceptionHandler.handleEventException( msg, event, method, ex ); //Waterfall - call passed exception handler
|
|
}
|
|
|
|
long elapsed = System.nanoTime() - start;
|
|
diff --git a/event/src/main/java/net/md_5/bungee/event/EventExceptionHandler.java b/event/src/main/java/net/md_5/bungee/event/EventExceptionHandler.java
|
|
new file mode 100644
|
|
index 00000000..088fe9b7
|
|
--- /dev/null
|
|
+++ b/event/src/main/java/net/md_5/bungee/event/EventExceptionHandler.java
|
|
@@ -0,0 +1,7 @@
|
|
+package net.md_5.bungee.event;
|
|
+
|
|
+public interface EventExceptionHandler<T> {
|
|
+
|
|
+ public void handleEventException(String msg, T event, EventHandlerMethod method, Throwable ex);
|
|
+
|
|
+}
|
|
diff --git a/event/src/test/java/net/md_5/bungee/event/EventBusTest.java b/event/src/test/java/net/md_5/bungee/event/EventBusTest.java
|
|
index 2c737675..72f14937 100644
|
|
--- a/event/src/test/java/net/md_5/bungee/event/EventBusTest.java
|
|
+++ b/event/src/test/java/net/md_5/bungee/event/EventBusTest.java
|
|
@@ -14,14 +14,14 @@ public class EventBusTest
|
|
public void testNestedEvents()
|
|
{
|
|
bus.register( this );
|
|
- bus.post( new FirstEvent() );
|
|
+ bus.post( new FirstEvent(), null ); // Waterfall - We dont need an exception handler here
|
|
Assert.assertEquals( 0, latch.getCount() );
|
|
}
|
|
|
|
@EventHandler
|
|
public void firstListener(FirstEvent event)
|
|
{
|
|
- bus.post( new SecondEvent() );
|
|
+ bus.post( new SecondEvent(), null ); // Waterfall - We dont need an exception handler here
|
|
Assert.assertEquals( 1, latch.getCount() );
|
|
latch.countDown();
|
|
}
|
|
@@ -39,4 +39,5 @@ public class EventBusTest
|
|
public static class SecondEvent
|
|
{
|
|
}
|
|
+
|
|
}
|
|
diff --git a/event/src/test/java/net/md_5/bungee/event/EventPriorityTest.java b/event/src/test/java/net/md_5/bungee/event/EventPriorityTest.java
|
|
index 351d3724..88f1346f 100644
|
|
--- a/event/src/test/java/net/md_5/bungee/event/EventPriorityTest.java
|
|
+++ b/event/src/test/java/net/md_5/bungee/event/EventPriorityTest.java
|
|
@@ -15,7 +15,7 @@ public class EventPriorityTest
|
|
{
|
|
bus.register( this );
|
|
bus.register( new EventPriorityListenerPartner() );
|
|
- bus.post( new PriorityTestEvent() );
|
|
+ bus.post( new PriorityTestEvent(), null ); // Waterfall - We dont need an exception handler here
|
|
Assert.assertEquals( 0, latch.getCount() );
|
|
}
|
|
|
|
diff --git a/event/src/test/java/net/md_5/bungee/event/UnregisteringListenerTest.java b/event/src/test/java/net/md_5/bungee/event/UnregisteringListenerTest.java
|
|
index fbfbd546..ae85a1d4 100644
|
|
--- a/event/src/test/java/net/md_5/bungee/event/UnregisteringListenerTest.java
|
|
+++ b/event/src/test/java/net/md_5/bungee/event/UnregisteringListenerTest.java
|
|
@@ -13,7 +13,7 @@ public class UnregisteringListenerTest
|
|
{
|
|
bus.register( this );
|
|
bus.unregister( this );
|
|
- bus.post( new TestEvent() );
|
|
+ bus.post( new TestEvent(), null ); // Waterfall - We dont need an exception handler here
|
|
}
|
|
|
|
@EventHandler
|
|
diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java
|
|
index c5f2a92d..c7b0ab25 100644
|
|
--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java
|
|
+++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java
|
|
@@ -11,6 +11,8 @@ import com.google.gson.Gson;
|
|
import com.google.gson.GsonBuilder;
|
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
import io.github.waterfallmc.waterfall.conf.WaterfallConfiguration;
|
|
+import io.github.waterfallmc.waterfall.event.ProxyExceptionEvent;
|
|
+import io.github.waterfallmc.waterfall.exception.ProxyPluginEnableDisableException;
|
|
import io.netty.bootstrap.ServerBootstrap;
|
|
import io.netty.channel.Channel;
|
|
import io.netty.channel.ChannelException;
|
|
@@ -476,7 +478,11 @@ public class BungeeCord extends ProxyServer
|
|
}
|
|
} catch ( Throwable t )
|
|
{
|
|
- getLogger().log( Level.SEVERE, "Exception disabling plugin " + plugin.getDescription().getName(), t );
|
|
+ // Waterfall start - throw exception event
|
|
+ String msg = "Exception disabling plugin " + plugin.getDescription().getName();
|
|
+ getLogger().log( Level.SEVERE, msg, t );
|
|
+ pluginManager.callEvent( new ProxyExceptionEvent( new ProxyPluginEnableDisableException( msg, t, plugin) ) );
|
|
+ // Waterfall end
|
|
}
|
|
getScheduler().cancel( plugin );
|
|
plugin.getExecutorService().shutdownNow();
|
|
diff --git a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java
|
|
index 38b75b51..02ec98fc 100644
|
|
--- a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java
|
|
+++ b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java
|
|
@@ -3,6 +3,9 @@ package net.md_5.bungee.scheduler;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.logging.Level;
|
|
+
|
|
+import io.github.waterfallmc.waterfall.event.ProxyExceptionEvent;
|
|
+import io.github.waterfallmc.waterfall.exception.ProxySchedulerException;
|
|
import lombok.Data;
|
|
import net.md_5.bungee.api.ProxyServer;
|
|
import net.md_5.bungee.api.plugin.Plugin;
|
|
@@ -63,7 +66,11 @@ public class BungeeTask implements Runnable, ScheduledTask
|
|
task.run();
|
|
} catch ( Throwable t )
|
|
{
|
|
- ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Task " + this + " encountered an exception", t );
|
|
+ //Waterfall start - throw exception event
|
|
+ String msg = String.format( "Task %s encountered an exception", this );
|
|
+ ProxyServer.getInstance().getLogger().log( Level.SEVERE, msg, t );
|
|
+ ProxyServer.getInstance().getPluginManager().callEvent( new ProxyExceptionEvent( new ProxySchedulerException( msg, t, this ) ) );
|
|
+ //Waterfall end
|
|
}
|
|
|
|
// If we have a period of 0 or less, only run once
|
|
--
|
|
2.33.0
|
|
|