Added CommandExecutionException which wraps any exception thrown during the execution of command handlers. Should be handled using CommandManager#registerExceptionHandler, similar to NoSuchCommandException, ArgumentParseException, etc.

This commit is contained in:
jmp 2020-11-19 19:50:17 -08:00 committed by Alexander Söderberg
parent 2f0ded5be6
commit 7df6917fe4
14 changed files with 240 additions and 32 deletions

View file

@ -26,6 +26,7 @@ package cloud.commandframework.bukkit;
import cloud.commandframework.Command;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.exceptions.ArgumentParseException;
import cloud.commandframework.exceptions.CommandExecutionException;
import cloud.commandframework.exceptions.InvalidCommandSenderException;
import cloud.commandframework.exceptions.InvalidSyntaxException;
import cloud.commandframework.exceptions.NoPermissionException;
@ -38,9 +39,12 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
import java.util.concurrent.CompletionException;
import java.util.logging.Level;
final class BukkitCommand<C> extends org.bukkit.command.Command implements PluginIdentifiableCommand {
private static final String MESSAGE_INTERNAL_ERROR = ChatColor.RED
+ "An internal error occurred while attempting to perform this command.";
private static final String MESSAGE_NO_PERMS = ChatColor.RED
+ "I'm sorry, but you do not have permission to perform this command. "
+ "Please contact the server administrators if you believe that this is in error.";
@ -50,7 +54,6 @@ final class BukkitCommand<C> extends org.bukkit.command.Command implements Plugi
private final BukkitCommandManager<C> manager;
private final Command<C> cloudCommand;
@SuppressWarnings("unchecked")
BukkitCommand(
final @NonNull String label,
final @NonNull List<@NonNull String> aliases,
@ -133,9 +136,25 @@ final class BukkitCommand<C> extends org.bukkit.command.Command implements Plugi
+ ChatColor.GRAY + finalThrowable.getCause()
.getMessage())
);
} else if (throwable instanceof CommandExecutionException) {
this.manager.handleException(sender,
CommandExecutionException.class,
(CommandExecutionException) throwable, (c, e) -> {
commandSender.sendMessage(MESSAGE_INTERNAL_ERROR);
this.manager.getOwningPlugin().getLogger().log(
Level.SEVERE,
"Exception executing command handler",
finalThrowable.getCause()
);
}
);
} else {
commandSender.sendMessage(throwable.getMessage());
throwable.printStackTrace();
commandSender.sendMessage(MESSAGE_INTERNAL_ERROR);
this.manager.getOwningPlugin().getLogger().log(
Level.SEVERE,
"An unhandled exception was thrown during command execution",
throwable
);
}
}
});

View file

@ -26,6 +26,7 @@ package cloud.commandframework.bungee;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.StaticArgument;
import cloud.commandframework.exceptions.ArgumentParseException;
import cloud.commandframework.exceptions.CommandExecutionException;
import cloud.commandframework.exceptions.InvalidCommandSenderException;
import cloud.commandframework.exceptions.InvalidSyntaxException;
import cloud.commandframework.exceptions.NoPermissionException;
@ -38,9 +39,11 @@ import net.md_5.bungee.api.plugin.TabExecutor;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.concurrent.CompletionException;
import java.util.logging.Level;
public final class BungeeCommand<C> extends Command implements TabExecutor {
private static final String MESSAGE_INTERNAL_ERROR = "An internal error occurred while attempting to perform this command.";
private static final String MESSAGE_NO_PERMS =
"I'm sorry, but you do not have permission to perform this command. "
+ "Please contact the server administrators if you believe that this is in error.";
@ -138,18 +141,27 @@ public final class BungeeCommand<C> extends Command implements TabExecutor {
.getMessage())
.create())
);
} else {
commandSender.sendMessage(new ComponentBuilder(throwable.getMessage()).create());
this.manager.getOwningPlugin().getLogger().warning(
String.format(
"(Cloud) Unknown exception type '%s' with cause '%s'",
throwable.getClass().getCanonicalName(),
throwable.getCause() == null ? "none"
: throwable.getCause()
.getClass().getCanonicalName()
)
} else if (throwable instanceof CommandExecutionException) {
this.manager.handleException(sender,
CommandExecutionException.class,
(CommandExecutionException) throwable, (c, e) -> {
commandSender.sendMessage(new ComponentBuilder(MESSAGE_INTERNAL_ERROR)
.color(ChatColor.RED)
.create());
this.manager.getOwningPlugin().getLogger().log(
Level.SEVERE,
"Exception executing command handler",
finalThrowable.getCause()
);
}
);
} else {
commandSender.sendMessage(new ComponentBuilder(MESSAGE_INTERNAL_ERROR).color(ChatColor.RED).create());
this.manager.getOwningPlugin().getLogger().log(
Level.SEVERE,
"An unhandled exception was thrown during command execution",
throwable
);
throwable.printStackTrace();
}
}
});

View file

@ -26,6 +26,7 @@ package cloud.commandframework.cloudburst;
import cloud.commandframework.Command;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.exceptions.ArgumentParseException;
import cloud.commandframework.exceptions.CommandExecutionException;
import cloud.commandframework.exceptions.InvalidCommandSenderException;
import cloud.commandframework.exceptions.InvalidSyntaxException;
import cloud.commandframework.exceptions.NoPermissionException;
@ -41,6 +42,7 @@ import java.util.concurrent.CompletionException;
final class CloudburstCommand<C> extends PluginCommand<Plugin> {
private static final String MESSAGE_INTERNAL_ERROR = "An internal error occurred while attempting to perform this command.";
private static final String MESSAGE_NO_PERMS =
"I'm sorry, but you do not have permission to perform this command. "
+ "Please contact the server administrators if you believe that this is in error.";
@ -124,9 +126,23 @@ final class CloudburstCommand<C> extends PluginCommand<Plugin> {
"Invalid Command Argument: "
+ finalThrowable.getCause().getMessage())
);
} else if (throwable instanceof CommandExecutionException) {
this.manager.handleException(sender,
CommandExecutionException.class,
(CommandExecutionException) throwable, (c, e) -> {
commandSender.sendMessage(MESSAGE_INTERNAL_ERROR);
manager.getOwningPlugin().getLogger().error(
"Exception executing command handler",
finalThrowable.getCause()
);
}
);
} else {
commandSender.sendMessage(throwable.getMessage());
throwable.printStackTrace();
commandSender.sendMessage(MESSAGE_INTERNAL_ERROR);
manager.getOwningPlugin().getLogger().error(
"An unhandled exception was thrown during command execution",
throwable
);
}
}
});

View file

@ -25,6 +25,7 @@ package cloud.commandframework.minecraft.extras;
import cloud.commandframework.CommandManager;
import cloud.commandframework.exceptions.ArgumentParseException;
import cloud.commandframework.exceptions.CommandExecutionException;
import cloud.commandframework.exceptions.InvalidCommandSenderException;
import cloud.commandframework.exceptions.InvalidSyntaxException;
import cloud.commandframework.exceptions.NoPermissionException;
@ -89,6 +90,19 @@ public final class MinecraftExceptionHandler<C> {
.append(Component.text("Invalid command argument: ", NamedTextColor.RED))
.append(Component.text(e.getCause().getMessage(), NamedTextColor.GRAY))
.build();
/**
* Default component builder for {@link CommandExecutionException}
*
* @since 1.2.0
*/
public static final Function<Exception, Component> DEFAULT_COMMAND_EXECUTION_FUNCTION =
e -> {
e.getCause().printStackTrace();
return Component.text()
.append(Component.text("An internal error occurred while attempting to perform this command.",
NamedTextColor.RED))
.build();
};
private final Map<ExceptionType, BiFunction<C, Exception, Component>> componentBuilders = new HashMap<>();
private Function<Component, Component> decorator = Function.identity();
@ -130,7 +144,17 @@ public final class MinecraftExceptionHandler<C> {
}
/**
* Use all four of the default exception handlers
* Use the default {@link CommandExecutionException} handler
*
* @return {@code this}
* @since 1.2.0
*/
public @NonNull MinecraftExceptionHandler<C> withCommandExecutionHandler() {
return this.withHandler(ExceptionType.COMMAND_EXECUTION, DEFAULT_COMMAND_EXECUTION_FUNCTION);
}
/**
* Use all of the default exception handlers
*
* @return {@code this}
*/
@ -139,7 +163,8 @@ public final class MinecraftExceptionHandler<C> {
.withArgumentParsingHandler()
.withInvalidSenderHandler()
.withInvalidSyntaxHandler()
.withNoPermissionHandler();
.withNoPermissionHandler()
.withCommandExecutionHandler();
}
/**
@ -237,6 +262,15 @@ public final class MinecraftExceptionHandler<C> {
)
);
}
if (componentBuilders.containsKey(ExceptionType.COMMAND_EXECUTION)) {
manager.registerExceptionHandler(
CommandExecutionException.class,
(c, e) -> audienceMapper.apply(c).sendMessage(
Identity.nil(),
this.decorator.apply(this.componentBuilders.get(ExceptionType.COMMAND_EXECUTION).apply(c, e))
)
);
}
}
@ -259,7 +293,13 @@ public final class MinecraftExceptionHandler<C> {
/**
* An argument failed to parse ({@link ArgumentParseException})
*/
ARGUMENT_PARSING
ARGUMENT_PARSING,
/**
* A command handler had an exception ({@link CommandExecutionException})
*
* @since 1.2.0
*/
COMMAND_EXECUTION
}
}

View file

@ -24,6 +24,7 @@
package cloud.commandframework.velocity;
import cloud.commandframework.exceptions.ArgumentParseException;
import cloud.commandframework.exceptions.CommandExecutionException;
import cloud.commandframework.exceptions.InvalidCommandSenderException;
import cloud.commandframework.exceptions.InvalidSyntaxException;
import cloud.commandframework.exceptions.NoPermissionException;
@ -42,6 +43,7 @@ import java.util.function.BiConsumer;
final class VelocityExecutor<C> implements Command<CommandSource> {
private static final String MESSAGE_INTERNAL_ERROR = "An internal error occurred while attempting to perform this command.";
private static final String MESSAGE_NO_PERMS =
"I'm sorry, but you do not have permission to perform this command. "
+ "Please contact the server administrators if you believe that this is in error.";
@ -128,10 +130,9 @@ final class VelocityExecutor<C> implements Command<CommandSource> {
sender,
ArgumentParseException.class,
(ArgumentParseException) throwable,
(c, e) ->
source.sendMessage(
Identity.nil(),
Component.text()
(c, e) -> source.sendMessage(
Identity.nil(),
Component.text()
.append(Component.text(
"Invalid Command Argument: ",
NamedTextColor.RED
@ -140,12 +141,28 @@ final class VelocityExecutor<C> implements Command<CommandSource> {
finalThrowable.getCause().getMessage(),
NamedTextColor.GRAY
))
)
)
);
} else if (throwable instanceof CommandExecutionException) {
this.manager.handleException(
sender,
CommandExecutionException.class,
(CommandExecutionException) throwable,
(c, e) -> {
source.sendMessage(
Identity.nil(),
Component.text(
MESSAGE_INTERNAL_ERROR,
NamedTextColor.RED
)
);
finalThrowable.getCause().printStackTrace();
}
);
} else {
source.sendMessage(
Identity.nil(),
Component.text(throwable.getMessage(), NamedTextColor.RED)
Component.text(MESSAGE_INTERNAL_ERROR, NamedTextColor.RED)
);
throwable.printStackTrace();
}