✨ 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:
parent
2f0ded5be6
commit
7df6917fe4
14 changed files with 240 additions and 32 deletions
|
|
@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Added a method to get the failure reason of SelectorParseExceptions
|
- Added a method to get the failure reason of SelectorParseExceptions
|
||||||
- Added some methods to FlagContext to work with flag values as optionals
|
- Added some methods to FlagContext to work with flag values as optionals
|
||||||
- Allow for use of named suggestion providers with `@Flag`s (cloud-annotations)
|
- Allow for use of named suggestion providers with `@Flag`s (cloud-annotations)
|
||||||
|
- Added `CommandExecutionException` which wraps any exception thrown during the execution of command handlers. Should be
|
||||||
|
handled using `CommandManager#registerExceptionHandler`, similar to `NoSuchCommandException`, `ArgumentParseException`, etc.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Allow for use of `@Completions` annotation with argument types other than String
|
- Allow for use of `@Completions` annotation with argument types other than String
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import cloud.commandframework.annotations.injection.ParameterInjectorRegistry;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.flags.FlagContext;
|
import cloud.commandframework.arguments.flags.FlagContext;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.execution.CommandExecutionHandler;
|
import cloud.commandframework.execution.CommandExecutionHandler;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
|
@ -115,8 +116,10 @@ class MethodCommandExecutionHandler<C> implements CommandExecutionHandler<C> {
|
||||||
/* Invoke the command method */
|
/* Invoke the command method */
|
||||||
try {
|
try {
|
||||||
this.methodHandle.invokeWithArguments(arguments);
|
this.methodHandle.invokeWithArguments(arguments);
|
||||||
} catch (final Throwable e) {
|
} catch (final Error e) {
|
||||||
e.printStackTrace();
|
throw e;
|
||||||
|
} catch (final Throwable throwable) {
|
||||||
|
throw new CommandExecutionException(throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||||
|
//
|
||||||
|
// 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 cloud.commandframework.exceptions;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when there is an exception during execution of a command handler
|
||||||
|
*
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class CommandExecutionException extends IllegalArgumentException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -4785446899438294661L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when there is an exception during execution of a command handler
|
||||||
|
*
|
||||||
|
* @param cause Exception thrown during the execution of a command handler
|
||||||
|
*/
|
||||||
|
public CommandExecutionException(final @NonNull Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -27,6 +27,7 @@ import cloud.commandframework.Command;
|
||||||
import cloud.commandframework.CommandManager;
|
import cloud.commandframework.CommandManager;
|
||||||
import cloud.commandframework.CommandTree;
|
import cloud.commandframework.CommandTree;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.services.State;
|
import cloud.commandframework.services.State;
|
||||||
import cloud.commandframework.types.tuples.Pair;
|
import cloud.commandframework.types.tuples.Pair;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
@ -76,10 +77,17 @@ public final class AsynchronousCommandExecutionCoordinator<C> extends CommandExe
|
||||||
final @NonNull CommandContext<C> commandContext,
|
final @NonNull CommandContext<C> commandContext,
|
||||||
final @NonNull Queue<@NonNull String> input
|
final @NonNull Queue<@NonNull String> input
|
||||||
) {
|
) {
|
||||||
|
final CompletableFuture<CommandResult<C>> resultFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
final Consumer<Command<C>> commandConsumer = command -> {
|
final Consumer<Command<C>> commandConsumer = command -> {
|
||||||
if (this.commandManager.postprocessContext(commandContext, command) == State.ACCEPTED) {
|
if (this.commandManager.postprocessContext(commandContext, command) == State.ACCEPTED) {
|
||||||
|
try {
|
||||||
command.getCommandExecutionHandler().execute(commandContext);
|
command.getCommandExecutionHandler().execute(commandContext);
|
||||||
|
} catch (final CommandExecutionException exception) {
|
||||||
|
resultFuture.completeExceptionally(exception);
|
||||||
|
} catch (final Exception exception) {
|
||||||
|
resultFuture.completeExceptionally(new CommandExecutionException(exception));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -97,8 +105,6 @@ public final class AsynchronousCommandExecutionCoordinator<C> extends CommandExe
|
||||||
}, this.executor);
|
}, this.executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
final CompletableFuture<CommandResult<C>> resultFuture = new CompletableFuture<>();
|
|
||||||
|
|
||||||
this.executor.execute(() -> {
|
this.executor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
final @NonNull Pair<@Nullable Command<C>, @Nullable Exception> pair =
|
final @NonNull Pair<@Nullable Command<C>, @Nullable Exception> pair =
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework.execution;
|
||||||
import cloud.commandframework.Command;
|
import cloud.commandframework.Command;
|
||||||
import cloud.commandframework.CommandTree;
|
import cloud.commandframework.CommandTree;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.services.State;
|
import cloud.commandframework.services.State;
|
||||||
import cloud.commandframework.types.tuples.Pair;
|
import cloud.commandframework.types.tuples.Pair;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
@ -103,7 +104,7 @@ public abstract class CommandExecutionCoordinator<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<CommandResult<C>> coordinateExecution(
|
public @NonNull CompletableFuture<CommandResult<C>> coordinateExecution(
|
||||||
final @NonNull CommandContext<C> commandContext,
|
final @NonNull CommandContext<C> commandContext,
|
||||||
final @NonNull Queue<@NonNull String> input
|
final @NonNull Queue<@NonNull String> input
|
||||||
) {
|
) {
|
||||||
|
|
@ -116,7 +117,13 @@ public abstract class CommandExecutionCoordinator<C> {
|
||||||
} else {
|
} else {
|
||||||
final Command<C> command = Objects.requireNonNull(pair.getFirst());
|
final Command<C> command = Objects.requireNonNull(pair.getFirst());
|
||||||
if (this.getCommandTree().getCommandManager().postprocessContext(commandContext, command) == State.ACCEPTED) {
|
if (this.getCommandTree().getCommandManager().postprocessContext(commandContext, command) == State.ACCEPTED) {
|
||||||
|
try {
|
||||||
command.getCommandExecutionHandler().execute(commandContext);
|
command.getCommandExecutionHandler().execute(commandContext);
|
||||||
|
} catch (final CommandExecutionException exception) {
|
||||||
|
completableFuture.completeExceptionally(exception);
|
||||||
|
} catch (final Exception exception) {
|
||||||
|
completableFuture.completeExceptionally(new CommandExecutionException(exception));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
completableFuture.complete(new CommandResult<>(commandContext));
|
completableFuture.complete(new CommandResult<>(commandContext));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework.javacord;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.StaticArgument;
|
import cloud.commandframework.arguments.StaticArgument;
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
import cloud.commandframework.exceptions.NoPermissionException;
|
||||||
|
|
@ -42,6 +43,7 @@ import java.util.concurrent.CompletionException;
|
||||||
|
|
||||||
public class JavacordCommand<C> implements MessageCreateListener {
|
public class JavacordCommand<C> implements MessageCreateListener {
|
||||||
|
|
||||||
|
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 the permission to do this :/";
|
private static final String MESSAGE_NO_PERMS = "I'm sorry, but you do not have the permission to do this :/";
|
||||||
|
|
||||||
private final JavacordCommandManager<C> manager;
|
private final JavacordCommandManager<C> manager;
|
||||||
|
|
@ -95,6 +97,7 @@ public class JavacordCommand<C> implements MessageCreateListener {
|
||||||
if (throwable == null) {
|
if (throwable == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final Throwable finalThrowable = throwable;
|
||||||
|
|
||||||
if (throwable instanceof CompletionException) {
|
if (throwable instanceof CompletionException) {
|
||||||
throwable = throwable.getCause();
|
throwable = throwable.getCause();
|
||||||
|
|
@ -153,6 +156,20 @@ public class JavacordCommand<C> implements MessageCreateListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (throwable instanceof CommandExecutionException) {
|
||||||
|
manager.handleException(
|
||||||
|
sender,
|
||||||
|
CommandExecutionException.class,
|
||||||
|
(CommandExecutionException) throwable,
|
||||||
|
(c, e) -> {
|
||||||
|
commandSender.sendErrorMessage(MESSAGE_INTERNAL_ERROR);
|
||||||
|
finalThrowable.getCause().printStackTrace();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
commandSender.sendErrorMessage(throwable.getMessage());
|
commandSender.sendErrorMessage(throwable.getMessage());
|
||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
package cloud.commandframework.jda;
|
package cloud.commandframework.jda;
|
||||||
|
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
import cloud.commandframework.exceptions.NoPermissionException;
|
||||||
|
|
@ -41,6 +42,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class JDACommandListener<C> extends ListenerAdapter {
|
public class JDACommandListener<C> extends ListenerAdapter {
|
||||||
|
|
||||||
|
private static final String MESSAGE_INTERNAL_ERROR = "An internal error occurred while attempting to perform this command.";
|
||||||
private static final String MESSAGE_INVALID_SYNTAX = "Invalid Command Syntax. Correct command syntax is: ";
|
private static final String MESSAGE_INVALID_SYNTAX = "Invalid Command Syntax. Correct command syntax is: ";
|
||||||
private static final String MESSAGE_NO_PERMS = "I'm sorry, but you do not have permission 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.";
|
+ "Please contact the server administrators if you believe that this is in error.";
|
||||||
|
|
@ -116,6 +118,16 @@ public class JDACommandListener<C> extends ListenerAdapter {
|
||||||
.getMessage()
|
.getMessage()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else if (throwable instanceof CommandExecutionException) {
|
||||||
|
this.commandManager.handleException(sender, CommandExecutionException.class,
|
||||||
|
(CommandExecutionException) throwable, (c, e) -> {
|
||||||
|
this.sendMessage(
|
||||||
|
event,
|
||||||
|
MESSAGE_INTERNAL_ERROR
|
||||||
|
);
|
||||||
|
throwable.getCause().printStackTrace();
|
||||||
|
}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.sendMessage(event, throwable.getMessage());
|
this.sendMessage(event, throwable.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
package cloud.commandframework.pircbotx;
|
package cloud.commandframework.pircbotx;
|
||||||
|
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
import cloud.commandframework.exceptions.NoPermissionException;
|
||||||
|
|
@ -34,6 +35,7 @@ import org.pircbotx.hooks.types.GenericMessageEvent;
|
||||||
|
|
||||||
final class CloudListenerAdapter<C> extends ListenerAdapter {
|
final class CloudListenerAdapter<C> extends ListenerAdapter {
|
||||||
|
|
||||||
|
private static final String MESSAGE_INTERNAL_ERROR = "An internal error occurred while attempting to perform this command.";
|
||||||
private static final String MESSAGE_INVALID_SYNTAX = "Invalid Command Syntax. Correct command syntax is: ";
|
private static final String MESSAGE_INVALID_SYNTAX = "Invalid Command Syntax. Correct command syntax is: ";
|
||||||
private static final String MESSAGE_NO_PERMS = "I'm sorry, but you do not have permission 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.";
|
+ "Please contact the server administrators if you believe that this is in error.";
|
||||||
|
|
@ -57,6 +59,7 @@ final class CloudListenerAdapter<C> extends ListenerAdapter {
|
||||||
if (throwable == null) {
|
if (throwable == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final Throwable finalThrowable = throwable;
|
||||||
|
|
||||||
if (throwable instanceof InvalidSyntaxException) {
|
if (throwable instanceof InvalidSyntaxException) {
|
||||||
this.manager.handleException(sender,
|
this.manager.handleException(sender,
|
||||||
|
|
@ -90,6 +93,13 @@ final class CloudListenerAdapter<C> extends ListenerAdapter {
|
||||||
"Invalid Command Argument: " + throwable.getCause().getMessage()
|
"Invalid Command Argument: " + throwable.getCause().getMessage()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else if (throwable instanceof CommandExecutionException) {
|
||||||
|
this.manager.handleException(sender, CommandExecutionException.class,
|
||||||
|
(CommandExecutionException) throwable, (c, e) -> {
|
||||||
|
event.respondWith(MESSAGE_INTERNAL_ERROR);
|
||||||
|
finalThrowable.getCause().printStackTrace();
|
||||||
|
}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
event.respondWith(throwable.getMessage());
|
event.respondWith(throwable.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework.bukkit;
|
||||||
import cloud.commandframework.Command;
|
import cloud.commandframework.Command;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
import cloud.commandframework.exceptions.NoPermissionException;
|
||||||
|
|
@ -38,9 +39,12 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
final class BukkitCommand<C> extends org.bukkit.command.Command implements PluginIdentifiableCommand {
|
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
|
private static final String MESSAGE_NO_PERMS = ChatColor.RED
|
||||||
+ "I'm sorry, but you do not have permission to perform this command. "
|
+ "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.";
|
+ "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 BukkitCommandManager<C> manager;
|
||||||
private final Command<C> cloudCommand;
|
private final Command<C> cloudCommand;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
BukkitCommand(
|
BukkitCommand(
|
||||||
final @NonNull String label,
|
final @NonNull String label,
|
||||||
final @NonNull List<@NonNull String> aliases,
|
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()
|
+ ChatColor.GRAY + finalThrowable.getCause()
|
||||||
.getMessage())
|
.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 {
|
} else {
|
||||||
commandSender.sendMessage(throwable.getMessage());
|
commandSender.sendMessage(MESSAGE_INTERNAL_ERROR);
|
||||||
throwable.printStackTrace();
|
this.manager.getOwningPlugin().getLogger().log(
|
||||||
|
Level.SEVERE,
|
||||||
|
"An unhandled exception was thrown during command execution",
|
||||||
|
throwable
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework.bungee;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.StaticArgument;
|
import cloud.commandframework.arguments.StaticArgument;
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
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 org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public final class BungeeCommand<C> extends Command implements TabExecutor {
|
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 =
|
private static final String MESSAGE_NO_PERMS =
|
||||||
"I'm sorry, but you do not have permission to perform this command. "
|
"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.";
|
+ "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())
|
.getMessage())
|
||||||
.create())
|
.create())
|
||||||
);
|
);
|
||||||
} else {
|
} else if (throwable instanceof CommandExecutionException) {
|
||||||
commandSender.sendMessage(new ComponentBuilder(throwable.getMessage()).create());
|
this.manager.handleException(sender,
|
||||||
this.manager.getOwningPlugin().getLogger().warning(
|
CommandExecutionException.class,
|
||||||
String.format(
|
(CommandExecutionException) throwable, (c, e) -> {
|
||||||
"(Cloud) Unknown exception type '%s' with cause '%s'",
|
commandSender.sendMessage(new ComponentBuilder(MESSAGE_INTERNAL_ERROR)
|
||||||
throwable.getClass().getCanonicalName(),
|
.color(ChatColor.RED)
|
||||||
throwable.getCause() == null ? "none"
|
.create());
|
||||||
: throwable.getCause()
|
this.manager.getOwningPlugin().getLogger().log(
|
||||||
.getClass().getCanonicalName()
|
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework.cloudburst;
|
||||||
import cloud.commandframework.Command;
|
import cloud.commandframework.Command;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
import cloud.commandframework.exceptions.NoPermissionException;
|
||||||
|
|
@ -41,6 +42,7 @@ import java.util.concurrent.CompletionException;
|
||||||
|
|
||||||
final class CloudburstCommand<C> extends PluginCommand<Plugin> {
|
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 =
|
private static final String MESSAGE_NO_PERMS =
|
||||||
"I'm sorry, but you do not have permission to perform this command. "
|
"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.";
|
+ "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: "
|
"Invalid Command Argument: "
|
||||||
+ finalThrowable.getCause().getMessage())
|
+ 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 {
|
} else {
|
||||||
commandSender.sendMessage(throwable.getMessage());
|
commandSender.sendMessage(MESSAGE_INTERNAL_ERROR);
|
||||||
throwable.printStackTrace();
|
manager.getOwningPlugin().getLogger().error(
|
||||||
|
"An unhandled exception was thrown during command execution",
|
||||||
|
throwable
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ package cloud.commandframework.minecraft.extras;
|
||||||
|
|
||||||
import cloud.commandframework.CommandManager;
|
import cloud.commandframework.CommandManager;
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
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("Invalid command argument: ", NamedTextColor.RED))
|
||||||
.append(Component.text(e.getCause().getMessage(), NamedTextColor.GRAY))
|
.append(Component.text(e.getCause().getMessage(), NamedTextColor.GRAY))
|
||||||
.build();
|
.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 final Map<ExceptionType, BiFunction<C, Exception, Component>> componentBuilders = new HashMap<>();
|
||||||
private Function<Component, Component> decorator = Function.identity();
|
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}
|
* @return {@code this}
|
||||||
*/
|
*/
|
||||||
|
|
@ -139,7 +163,8 @@ public final class MinecraftExceptionHandler<C> {
|
||||||
.withArgumentParsingHandler()
|
.withArgumentParsingHandler()
|
||||||
.withInvalidSenderHandler()
|
.withInvalidSenderHandler()
|
||||||
.withInvalidSyntaxHandler()
|
.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})
|
* 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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
package cloud.commandframework.velocity;
|
package cloud.commandframework.velocity;
|
||||||
|
|
||||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||||
|
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||||
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
import cloud.commandframework.exceptions.InvalidSyntaxException;
|
||||||
import cloud.commandframework.exceptions.NoPermissionException;
|
import cloud.commandframework.exceptions.NoPermissionException;
|
||||||
|
|
@ -42,6 +43,7 @@ import java.util.function.BiConsumer;
|
||||||
|
|
||||||
final class VelocityExecutor<C> implements Command<CommandSource> {
|
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 =
|
private static final String MESSAGE_NO_PERMS =
|
||||||
"I'm sorry, but you do not have permission to perform this command. "
|
"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.";
|
+ "Please contact the server administrators if you believe that this is in error.";
|
||||||
|
|
@ -128,8 +130,7 @@ final class VelocityExecutor<C> implements Command<CommandSource> {
|
||||||
sender,
|
sender,
|
||||||
ArgumentParseException.class,
|
ArgumentParseException.class,
|
||||||
(ArgumentParseException) throwable,
|
(ArgumentParseException) throwable,
|
||||||
(c, e) ->
|
(c, e) -> source.sendMessage(
|
||||||
source.sendMessage(
|
|
||||||
Identity.nil(),
|
Identity.nil(),
|
||||||
Component.text()
|
Component.text()
|
||||||
.append(Component.text(
|
.append(Component.text(
|
||||||
|
|
@ -142,10 +143,26 @@ final class VelocityExecutor<C> implements Command<CommandSource> {
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} 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 {
|
} else {
|
||||||
source.sendMessage(
|
source.sendMessage(
|
||||||
Identity.nil(),
|
Identity.nil(),
|
||||||
Component.text(throwable.getMessage(), NamedTextColor.RED)
|
Component.text(MESSAGE_INTERNAL_ERROR, NamedTextColor.RED)
|
||||||
);
|
);
|
||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ public final class ExamplePlugin extends JavaPlugin {
|
||||||
.withInvalidSenderHandler()
|
.withInvalidSenderHandler()
|
||||||
.withNoPermissionHandler()
|
.withNoPermissionHandler()
|
||||||
.withArgumentParsingHandler()
|
.withArgumentParsingHandler()
|
||||||
|
.withCommandExecutionHandler()
|
||||||
.withDecorator(
|
.withDecorator(
|
||||||
component -> Component.text()
|
component -> Component.text()
|
||||||
.append(Component.text("[", NamedTextColor.DARK_GRAY))
|
.append(Component.text("[", NamedTextColor.DARK_GRAY))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue