All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.aikar.commands.BaseCommand Maven / Gradle / Ivy

The newest version!
/*
 * 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 co.aikar.commands.CommandRouter.RouteSearch;
import co.aikar.commands.annotation.CatchAll;
import co.aikar.commands.annotation.CatchUnknown;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Conditions;
import co.aikar.commands.annotation.Default;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.HelpCommand;
import co.aikar.commands.annotation.PreCommand;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.UnknownHandler;
import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * A Base command is defined as a command group of related commands.
 * A BaseCommand does not imply nor enforce that they use the same root command.
 * 

* It is up to the end user how to organize their command. you could use 1 base command per * command in your application. *

* Optionally (and encouraged), you can use the base command to represent a root command, and * then each actionable command is a sub command */ public abstract class BaseCommand { /** * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown * argument to command states. */ static final String CATCHUNKNOWN = "__catchunknown"; /** * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the * entire base command. */ static final String DEFAULT = "__default"; /** * A map of all the registered commands for this base command, keyed to each potential subcommand to access it. */ final SetMultimap subCommands = HashMultimap.create(); final Set subScopes = new HashSet<>(); /** * A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each. */ final Map, String> contextFlags = new HashMap<>(); /** * What method was annoated with {@link PreCommand} to execute before commands. */ @Nullable private Method preCommandHandler; /** * What root command the user actually entered to access the currently executing command */ @SuppressWarnings("WeakerAccess") private String execLabel; /** * What subcommand the user actually entered to access the currently executing command */ @SuppressWarnings("WeakerAccess") private String execSubcommand; /** * What arguments the user actually entered after the root command to access the currently executing command */ @SuppressWarnings("WeakerAccess") private String[] origArgs; /** * The manager this is registered to */ CommandManager manager = null; /** * The command which owns this. This may be null if there are no owners. */ BaseCommand parentCommand; Map registeredCommands = new HashMap<>(); /** * The description of the command. This may be null if no description has been provided. * Used for help documentation */ @Nullable String description; /** * The name of the command. This may be null if no name has been provided. */ @Nullable String commandName; /** * The permission of the command. This may be null if no permission has been provided. */ @Nullable String permission; /** * The conditions of the command. This may be null if no conditions has been provided. */ @Nullable String conditions; /** * Identifies if the command has an explicit help command annotated with {@link HelpCommand} */ boolean hasHelpCommand; /** * The handler of all uncaught exceptions thrown by the user's command implementation. */ private ExceptionHandler exceptionHandler = null; /** * The last operative context data of this command. This may be null if this command hasn't been run yet. */ private final ThreadLocal lastCommandOperationContext = new ThreadLocal<>(); /** * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this */ @Nullable private String parentSubcommand; /** * The permissions of the command. */ private final Set permissions = new HashSet<>(); public BaseCommand() { } /** * Constructor based defining of commands will be removed in the next version bump. * * @param cmd * @deprecated Please switch to {@link CommandAlias} for defining all root commands. */ @Deprecated public BaseCommand(@Nullable String cmd) { this.commandName = cmd; } /** * Returns a reference to the last used CommandOperationContext. * This method is ThreadLocal, in that it can only be used on a thread that has executed a command * * @return */ public CommandOperationContext getLastCommandOperationContext() { return lastCommandOperationContext.get(); } /** * Gets the root command name that the user actually typed * * @return Name */ public String getExecCommandLabel() { return execLabel; } /** * Gets the actual sub command name the user typed * * @return Name */ public String getExecSubcommand() { return execSubcommand; } /** * Gets the actual args in string form the user typed * * @return Args */ public String[] getOrigArgs() { return origArgs; } /** * This should be called whenever the command gets registered. * It sets all required fields correctly and injects dependencies. * * @param manager The manager to register as this command's owner and handler. */ void onRegister(CommandManager manager) { onRegister(manager, this.commandName); } /** * This should be called whenever the command gets registered. * It sets all required fields correctly and injects dependencies. * * @param manager The manager to register as this command's owner and handler. * @param cmd The command name to use register with. */ private void onRegister(CommandManager manager, String cmd) { manager.injectDependencies(this); this.manager = manager; final Annotations annotations = manager.getAnnotations(); final Class self = this.getClass(); String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); if (cmd == null && cmdAliases != null) { cmd = cmdAliases[0]; } this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(Locale.ENGLISH); this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); this.description = annotations.getAnnotationValue(self, Description.class, Annotations.NO_EMPTY | Annotations.REPLACEMENTS); this.parentSubcommand = getParentSubcommand(self); this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); computePermissions(); // Must be before any subcommands so they can inherit permissions registerSubcommands(); registerSubclasses(cmd); if (cmdAliases != null) { Set cmdList = new HashSet<>(); Collections.addAll(cmdList, cmdAliases); cmdList.remove(cmd); for (String cmdAlias : cmdList) { register(cmdAlias, this); } } if (cmd != null) { register(cmd, this); } } /** * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. * * @param cmd The command name of this command. */ private void registerSubclasses(String cmd) { for (Class clazz : this.getClass().getDeclaredClasses()) { if (BaseCommand.class.isAssignableFrom(clazz)) { try { BaseCommand subScope = null; Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { declaredConstructor.setAccessible(true); Parameter[] parameters = declaredConstructor.getParameters(); if (parameters.length == 1) { subScope = (BaseCommand) declaredConstructor.newInstance(this); } else { manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining(", ")) + ")"); } } if (subScope != null) { subScope.parentCommand = this; this.subScopes.add(subScope); subScope.onRegister(manager, cmd); this.subCommands.putAll(subScope.subCommands); this.registeredCommands.putAll(subScope.registeredCommands); } else { this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); } } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { this.manager.log(LogLevel.ERROR, "Error registering subclass", e); } } } } /** * This registers all subcommands of the command. */ private void registerSubcommands() { final Annotations annotations = manager.getAnnotations(); boolean foundCatchUnknown = false; boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); Set methods = new LinkedHashSet<>(); Collections.addAll(methods, this.getClass().getDeclaredMethods()); Collections.addAll(methods, this.getClass().getMethods()); for (Method method : methods) { method.setAccessible(true); String sublist = null; String sub = getSubcommandValue(method); final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); if (annotations.hasAnnotation(method, Default.class)) { if (!isParentEmpty) { sub = parentSubcommand; } else { registerSubcommand(method, DEFAULT); } } if (sub != null) { sublist = sub; } else if (commandAliases != null) { sublist = commandAliases; } else if (helpCommand != null) { sublist = helpCommand; hasHelpCommand = true; } boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || annotations.hasAnnotation(method, CatchAll.class) || annotations.hasAnnotation(method, UnknownHandler.class); if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { if (!foundCatchUnknown) { if (hasCatchUnknown) { this.subCommands.get(CATCHUNKNOWN).clear(); foundCatchUnknown = true; } registerSubcommand(method, CATCHUNKNOWN); } else { ACFUtil.sneaky(new IllegalStateException("Multiple @CatchUnknown/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); } } else if (preCommand) { if (this.preCommandHandler == null) { this.preCommandHandler = method; } else { ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); } } if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { registerSubcommand(method, sublist); } } } /** * This registers all the permissions required to execute this command. */ private void computePermissions() { this.permissions.clear(); if (this.permission != null && !this.permission.isEmpty()) { this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); } if (this.parentCommand != null) { this.permissions.addAll(this.parentCommand.getRequiredPermissions()); } this.subCommands.values().forEach(RegisteredCommand::computePermissions); this.subScopes.forEach(BaseCommand::computePermissions); } /** * Gets the subcommand name of the method given. * * @param method The method to check. * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. */ private String getSubcommandValue(Method method) { final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); if (sub == null) { return null; } Class clazz = method.getDeclaringClass(); String parent = getParentSubcommand(clazz); return parent == null || parent.isEmpty() ? sub : parent + " " + sub; } private String getParentSubcommand(Class clazz) { List subList = new ArrayList<>(); while (clazz != null) { String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); if (sub != null) { subList.add(sub); } clazz = clazz.getEnclosingClass(); } Collections.reverse(subList); return ACFUtil.join(subList, " "); } /** * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. * * @param name Name of the parent to cmd. * @param cmd The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. */ private void register(String name, BaseCommand cmd) { String nameLower = name.toLowerCase(Locale.ENGLISH); RootCommand rootCommand = manager.obtainRootCommand(nameLower); rootCommand.addChild(cmd); this.registeredCommands.put(nameLower, rootCommand); } /** * Registers the given {@link Method} as a subcommand. * * @param method The method to register as a subcommand. * @param subCommand The subcommand's name(s). */ private void registerSubcommand(Method method, String subCommand) { subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase(Locale.ENGLISH)); final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); // Must run getSubcommandPossibility BEFORE we rewrite it just after this. Set cmdList = getSubCommandPossibilityList(subCommandParts); // Strip pipes off for auto complete addition for (int i = 0; i < subCommandParts.length; i++) { String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); if (split.length == 0 || split[0].isEmpty()) { throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); } subCommandParts[i] = split[0]; } String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); for (String subcmd : cmdList) { subCommands.put(subcmd, cmd); } cmd.addSubcommands(cmdList); if (aliasNames != null) { for (String name : aliasNames) { register(name, new ForwardingCommand(this, cmd, subCommandParts)); } } } /** * Takes a string like "foo|bar baz|qux" and generates a list of * - foo baz * - foo qux * - bar baz * - bar qux *

* For every possible sub command combination * * @param subCommandParts * @return List of all sub command possibilities */ private static Set getSubCommandPossibilityList(String[] subCommandParts) { int i = 0; Set current = null; while (true) { Set newList = new HashSet<>(); if (i < subCommandParts.length) { for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { if (current != null) { newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); } else { newList.add(s1); } } } if (i + 1 < subCommandParts.length) { current = newList; i = i + 1; continue; } return newList; } } void execute(CommandIssuer issuer, CommandRouter.CommandRouteResult command) { try { CommandOperationContext commandContext = preCommandOperation(issuer, command.commandLabel, command.args, false); execSubcommand = command.subcommand; executeCommand(commandContext, issuer, command.args, command.cmd); } finally { postCommandOperation(); } } /** * This is ran after any command operation has been performed. */ private void postCommandOperation() { CommandManager.commandOperationContext.get().pop(); execSubcommand = null; execLabel = null; origArgs = new String[]{}; } /** * This is ran before any command operation has been performed. * * @param issuer The user who executed the command. * @param commandLabel The label the user used to execute the command. This is not the command name, but their input. * When there is multiple aliases, this is which alias was used * @param args The arguments passed to the command when executing it. * @param isAsync Whether the command is executed off of the main thread. * @return The context which is being registered to the {@link CommandManager}'s {@link * CommandManager#commandOperationContext thread local stack}. */ private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { Stack contexts = CommandManager.commandOperationContext.get(); CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); contexts.push(context); lastCommandOperationContext.set(context); execSubcommand = null; execLabel = commandLabel; origArgs = args; return context; } /** * Gets the current command issuer. * * @return The current command issuer. */ public CommandIssuer getCurrentCommandIssuer() { return CommandManager.getCurrentCommandIssuer(); } /** * Gets the current command manager. * * @return The current command manager. */ public CommandManager getCurrentCommandManager() { return CommandManager.getCurrentCommandManager(); } private void executeCommand(CommandOperationContext commandOperationContext, CommandIssuer issuer, String[] args, RegisteredCommand cmd) { if (cmd.hasPermission(issuer)) { commandOperationContext.setRegisteredCommand(cmd); if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { return; } List sargs = Arrays.asList(args); cmd.invoke(issuer, sargs, commandOperationContext); } else { issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); } } /** * Please use command conditions for restricting execution * * @param issuer * @param cmd * @return * @deprecated See {@link CommandConditions} */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated public boolean canExecute(CommandIssuer issuer, RegisteredCommand cmd) { return true; } /** * Gets tab completed data from the given command from the user. * * @param issuer The user who executed the tabcomplete. * @param commandLabel The label which is being used by the user. * @param args The arguments the user has typed so far. * @return All possibilities in the tab complete. */ public List tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { return tabComplete(issuer, commandLabel, args, false); } /** * Gets the tab complete suggestions from a given command. This will automatically find anything * which is valid for the specified command through the command's implementation. * * @param issuer The issuer of the command. * @param commandLabel The command name as entered by the user instead of the ACF registered name. * @param args All arguments entered by the user. * @param isAsync Whether this is run off of the main thread. * @return The possibilities to tab complete in no particular order. */ @SuppressWarnings("WeakerAccess") public List tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) throws IllegalArgumentException { return tabComplete(issuer, manager.getRootCommand(commandLabel.toLowerCase(Locale.ENGLISH)), args, isAsync); } List tabComplete(CommandIssuer issuer, RootCommand rootCommand, String[] args, boolean isAsync) throws IllegalArgumentException { if (args.length == 0) { args = new String[]{""}; } String commandLabel = rootCommand.getCommandName(); try { CommandRouter router = manager.getRouter(); preCommandOperation(issuer, commandLabel, args, isAsync); final RouteSearch search = router.routeCommand(rootCommand, commandLabel, args, true); final List cmds = new ArrayList<>(); if (search != null) { CommandRouter.CommandRouteResult result = router.matchCommand(search, true); if (result != null) { cmds.addAll(completeCommand(issuer, result.cmd, result.args, commandLabel, isAsync)); } } return filterTabComplete(args[args.length - 1], cmds); } finally { postCommandOperation(); } } /** * Gets all subcommands which are possible to tabcomplete. * * @param issuer The command issuer. * @param args * @return */ List getCommandsForCompletion(CommandIssuer issuer, String[] args) { final Set cmds = new HashSet<>(); final int cmdIndex = Math.max(0, args.length - 1); String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(Locale.ENGLISH); for (Map.Entry entry : subCommands.entries()) { final String key = entry.getKey(); if (key.startsWith(argString) && !isSpecialSubcommand(key)) { final RegisteredCommand value = entry.getValue(); if (!value.hasPermission(issuer) || value.isPrivate) { continue; } String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); cmds.add(split[cmdIndex]); } } return new ArrayList<>(cmds); } static boolean isSpecialSubcommand(String key) { return CATCHUNKNOWN.equals(key) || DEFAULT.equals(key); } /** * Complete a command properly per issuer and input. * * @param issuer The user who executed this. * @param cmd The command to be completed. * @param args All arguments given by the user. * @param commandLabel The command name the user used. * @param isAsync Whether the command was executed async. * @return All results to complete the command. */ private List completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { if (!cmd.hasPermission(issuer) || args.length == 0 || cmd.parameters.length == 0) { return Collections.emptyList(); } if (!cmd.parameters[cmd.parameters.length - 1].consumesRest && args.length > cmd.consumeInputResolvers) { return Collections.emptyList(); } List cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); return filterTabComplete(args[args.length - 1], cmds); } /** * Gets the actual args in string form the user typed * This returns a list of all tab complete options which are possible with the given argument and commands. * * @param arg Argument which was pressed tab on. * @param cmds The possibilities to return. * @return All possible options. This may be empty. */ private static List filterTabComplete(String arg, List cmds) { return cmds.stream() .distinct() .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) .collect(Collectors.toList()); } /** * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. * * @param commandOperationContext The context to use. * @param cmd The command executed. * @param issuer The issuer who executed the command. * @param args The arguments the issuer provided. * @return Whether something went wrong. */ private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { Method pre = this.preCommandHandler; if (pre != null) { try { Class[] types = pre.getParameterTypes(); Object[] parameters = new Object[pre.getParameterCount()]; for (int i = 0; i < parameters.length; i++) { Class type = types[i]; Object issuerObject = issuer.getIssuer(); if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { parameters[i] = issuerObject; } else if (CommandIssuer.class.isAssignableFrom(type)) { parameters[i] = issuer; } else if (RegisteredCommand.class.isAssignableFrom(type)) { parameters[i] = cmd; } else if (String[].class.isAssignableFrom((type))) { parameters[i] = args; } else { parameters[i] = null; } } return (boolean) pre.invoke(this, parameters); } catch (IllegalAccessException | InvocationTargetException e) { this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); } } return false; } /** * @deprecated Unstable API */ @Deprecated @UnstableAPI public CommandHelp getCommandHelp() { return manager.generateCommandHelp(); } /** * @deprecated Unstable API */ @Deprecated @UnstableAPI public void showCommandHelp() { getCommandHelp().showHelp(); } public void help(Object issuer, String[] args) { help(manager.getCommandIssuer(issuer), args); } public void help(CommandIssuer issuer, String[] args) { issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); } public void doHelp(Object issuer, String... args) { doHelp(manager.getCommandIssuer(issuer), args); } public void doHelp(CommandIssuer issuer, String... args) { help(issuer, args); } public void showSyntax(CommandIssuer issuer, RegisteredCommand cmd) { issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, "{command}", manager.getCommandPrefix(issuer) + cmd.command, "{syntax}", cmd.getSyntaxText(issuer) ); } public boolean hasPermission(Object issuer) { return hasPermission(manager.getCommandIssuer(issuer)); } public boolean hasPermission(CommandIssuer issuer) { return this.manager.hasPermission(issuer, getRequiredPermissions()); } public Set getRequiredPermissions() { return this.permissions; } public boolean requiresPermission(String permission) { return getRequiredPermissions().contains(permission); } public String getName() { return commandName; } public ExceptionHandler getExceptionHandler() { return exceptionHandler; } public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; return this; } public RegisteredCommand getDefaultRegisteredCommand() { return ACFUtil.getFirstElement(this.subCommands.get(DEFAULT)); } public String setContextFlags(Class cls, String flags) { return this.contextFlags.put(cls, flags); } public String getContextFlags(Class cls) { return this.contextFlags.get(cls); } public List getRegisteredCommands() { List registeredCommands = new ArrayList<>(); registeredCommands.addAll(this.subCommands.values()); return registeredCommands; } protected SetMultimap getSubCommands() { return subCommands; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy