diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java index 1d784093..6dc081cd 100644 --- a/core/src/main/java/co/aikar/commands/BaseCommand.java +++ b/core/src/main/java/co/aikar/commands/BaseCommand.java @@ -76,6 +76,8 @@ public abstract class BaseCommand { String permission; public String permissionMessage = "&cI'm sorry, but you do not have permission to perform this command."; + private ExceptionHandler exceptionHandler = null; + public BaseCommand() {} public BaseCommand(String cmd) { this.commandName = cmd; @@ -512,6 +514,15 @@ public abstract class BaseCommand { return commandName; } + public ExceptionHandler getExceptionHandler() { + return exceptionHandler; + } + + public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + return this; + } + private static class CommandSearch { RegisteredCommand cmd; int argIndex; String checkSub; CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) { diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java index b423d04f..29a09f97 100644 --- a/core/src/main/java/co/aikar/commands/CommandManager.java +++ b/core/src/main/java/co/aikar/commands/CommandManager.java @@ -34,6 +34,7 @@ abstract class CommandManager { protected Map rootCommands = new HashMap<>(); protected CommandReplacements replacements = new CommandReplacements(this); + protected ExceptionHandler defaultExceptionHandler = null; /** * Gets the command contexts manager @@ -92,4 +93,32 @@ abstract class CommandManager { public abstract void log(final LogLevel level, final String message); public abstract void log(final LogLevel level, final String message, final Throwable throwable); + + /** + * Sets the default {@link ExceptionHandler} that is called when an exception occurs while executing a command, if the command doesn't have it's own exception handler registered. + * + * @param exceptionHandler the handler that should handle uncaught exceptions + */ + public void setDefaultExceptionHandler(ExceptionHandler exceptionHandler){ + defaultExceptionHandler = exceptionHandler; + } + + /** + * Gets the current default exception handler, might be null. + * + * @return the default exception handler + */ + public ExceptionHandler getDefaultExceptionHandler() { + return defaultExceptionHandler; + } + + protected boolean handleUncaughtException(BaseCommand scope, RegisteredCommand registeredCommand, CommandIssuer sender, List args, Throwable t){ + boolean result = false; + if(scope.getExceptionHandler() != null){ + result = scope.getExceptionHandler().execute(scope, registeredCommand, sender, args, t); + }else if(defaultExceptionHandler != null){ + result = defaultExceptionHandler.execute(scope, registeredCommand, sender, args, t); + } + return result; + } } diff --git a/core/src/main/java/co/aikar/commands/ExceptionHandler.java b/core/src/main/java/co/aikar/commands/ExceptionHandler.java new file mode 100644 index 00000000..b87920ab --- /dev/null +++ b/core/src/main/java/co/aikar/commands/ExceptionHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package co.aikar.commands; + +import java.util.List; + +/** + * Functional interface to allow plugins to handle uncaught excetpions + */ +@FunctionalInterface +public interface ExceptionHandler { + + /** + * Called when an exception occurs while executing a command
+ * If an exception handler properly handles an exception, the user will not be noticied by the + * framework that something went unexceptected. + * + * @param command the command that was executed + * @param registeredCommand the registered command + * @param sender the issuer who send the command + * @param args the args he used + * @param t the throwable that caused this exception + * + * @return if the exception was handeled by the exception handler. + */ + boolean execute(BaseCommand command, RegisteredCommand registeredCommand, CommandIssuer sender, List args, Throwable t); +} diff --git a/core/src/main/java/co/aikar/commands/RegisteredCommand.java b/core/src/main/java/co/aikar/commands/RegisteredCommand.java index 21bba06e..e2a4ab13 100644 --- a/core/src/main/java/co/aikar/commands/RegisteredCommand.java +++ b/core/src/main/java/co/aikar/commands/RegisteredCommand.java @@ -153,7 +153,10 @@ public class RegisteredCommand ( Lists.newArrayList("foo", "bar", "baz") )); - commandManager.registerCommand(new SomeCommand()); + + commandManager.registerCommand(new SomeCommand().setExceptionHandler((command, registeredCommand, sender, args, t) -> { + sender.sendMessage("An error occured. This problem has been logged. Sorry for the inconvienence."); + return true; // mark as handeled, default message will not be send to sender + })); commandManager.registerCommand(new SomeCommand_ExtraSubs()); + + commandManager.setDefaultExceptionHandler((command, registeredCommand, sender, args, t) -> { + getLogger().warning("Error occured while executing command " + command.getName()); + return false; // mark as unhandeled, sender will see default message + }); } public static ACFExample getPlugin() {