From d3707353a4b8be0fa47a5fa155bb44520914a383 Mon Sep 17 00:00:00 2001 From: theminecoder 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 c11ce8d3..1ba5b249 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; @@ -34,6 +39,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.event.EventBus; import net.md_5.bungee.event.EventHandler; import org.yaml.snakeyaml.LoaderOptions; +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; @@ -194,10 +200,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[] @@ -206,18 +211,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; } @@ -305,7 +320,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 } } } @@ -445,7 +464,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; @@ -459,6 +478,14 @@ public final class PluginManager return event; } + //Waterfall start - Exception handler passed to event bus to fire the exception event + private 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 fb301a44..1187acd0 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 void post(T event, EventExceptionHandler 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 { + + 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 ef4e5edf..15fb4ad2 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; @@ -485,7 +487,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.37.3.windows.1