From d7477cb732cae6d7a3a8f18e7ae3242cd1ff20b2 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 3 Mar 2019 11:12:51 -0500 Subject: [PATCH] (DEPLOYED ACF) Updated JavaDocs --- .../co/aikar/commands/BaseCommand.html | 60 +- .../co/aikar/commands/BaseCommand.html | 1502 +++++++++-------- 2 files changed, 783 insertions(+), 779 deletions(-) diff --git a/docs/acf-core/co/aikar/commands/BaseCommand.html b/docs/acf-core/co/aikar/commands/BaseCommand.html index 34c19476..375acfad 100644 --- a/docs/acf-core/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/co/aikar/commands/BaseCommand.html @@ -112,7 +112,7 @@ var activeTableTab = "activeTableTab";

-
public abstract class BaseCommand
+
public abstract class BaseCommand
 extends Object
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. @@ -340,7 +340,7 @@ extends
  • BaseCommand

    -
    public BaseCommand()
    +
    public BaseCommand()
  • @@ -350,7 +350,7 @@ extends

    BaseCommand

    @Deprecated
    -public BaseCommand(@Nullable
    +public BaseCommand(@Nullable
                                    @Nullable String cmd)
    Deprecated. Please switch to CommandAlias for defining all root commands.
    Constructor based defining of commands will be removed in the next version bump.
    @@ -374,7 +374,7 @@ public 
  • getLastCommandOperationContext

    -
    public CommandOperationContext getLastCommandOperationContext()
    +
    public CommandOperationContext getLastCommandOperationContext()
    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
    @@ -388,7 +388,7 @@ public 
  • getExecCommandLabel

    -
    public String getExecCommandLabel()
    +
    public String getExecCommandLabel()
    Gets the root command name that the user actually typed
    Returns:
    @@ -402,7 +402,7 @@ public 
  • getExecSubcommand

    -
    public String getExecSubcommand()
    +
    public String getExecSubcommand()
    Gets the actual sub command name the user typed
    Returns:
    @@ -416,7 +416,7 @@ public 
  • getOrigArgs

    -
    public String[] getOrigArgs()
    +
    public String[] getOrigArgs()
    Gets the actual args in string form the user typed
    Returns:
    @@ -430,7 +430,7 @@ public 
  • getCurrentCommandIssuer

    -
    public CommandIssuer getCurrentCommandIssuer()
    +
    public CommandIssuer getCurrentCommandIssuer()
    Gets the current command issuer.
    Returns:
    @@ -444,7 +444,7 @@ public 
  • getCurrentCommandManager

    -
    public CommandManager getCurrentCommandManager()
    +
    public CommandManager getCurrentCommandManager()
    Gets the current command manager.
    Returns:
    @@ -459,7 +459,7 @@ public 

    canExecute

    @Deprecated
    -public boolean canExecute(CommandIssuer issuer,
    +public boolean canExecute(CommandIssuer issuer,
                                           RegisteredCommand<?> cmd)
    Deprecated. See CommandConditions
    Please use command conditions for restricting execution
    @@ -477,7 +477,7 @@ public boolean 
  • tabComplete

    -
    public List<StringtabComplete(CommandIssuer issuer,
    +
    public List<StringtabComplete(CommandIssuer issuer,
                                     String commandLabel,
                                     String[] args)
    Gets tab completed data from the given command from the user.
    @@ -497,7 +497,7 @@ public boolean 
  • tabComplete

    -
    public List<StringtabComplete(CommandIssuer issuer,
    +
    public List<StringtabComplete(CommandIssuer issuer,
                                     String commandLabel,
                                     String[] args,
                                     boolean isAsync)
    @@ -524,7 +524,7 @@ public boolean 
     

    getCommandHelp

    @Deprecated
    -public CommandHelp getCommandHelp()
    +public CommandHelp getCommandHelp()
    Deprecated. Unstable API
  • @@ -535,7 +535,7 @@ public 

    showCommandHelp

    @Deprecated
    -public void showCommandHelp()
    +public void showCommandHelp()
    Deprecated. Unstable API
  • @@ -545,7 +545,7 @@ public void 
  • help

    -
    public void help(Object issuer,
    +
    public void help(Object issuer,
                      String[] args)
  • @@ -555,7 +555,7 @@ public void 
  • help

    -
    public void help(CommandIssuer issuer,
    +
    public void help(CommandIssuer issuer,
                      String[] args)
  • @@ -565,7 +565,7 @@ public void 
  • doHelp

    -
    public void doHelp(Object issuer,
    +
    public void doHelp(Object issuer,
                        String... args)
  • @@ -575,7 +575,7 @@ public void 
  • doHelp

    -
    public void doHelp(CommandIssuer issuer,
    +
    public void doHelp(CommandIssuer issuer,
                        String... args)
  • @@ -585,7 +585,7 @@ public void 
  • showSyntax

    -
    public void showSyntax(CommandIssuer issuer,
    +
    public void showSyntax(CommandIssuer issuer,
                            RegisteredCommand<?> cmd)
  • @@ -595,7 +595,7 @@ public void 
  • hasPermission

    -
    public boolean hasPermission(Object issuer)
    +
    public boolean hasPermission(Object issuer)
  • @@ -604,7 +604,7 @@ public void 
  • hasPermission

    -
    public boolean hasPermission(CommandIssuer issuer)
    +
    public boolean hasPermission(CommandIssuer issuer)
  • @@ -613,7 +613,7 @@ public void 
  • getRequiredPermissions

    -
    public Set<StringgetRequiredPermissions()
    +
    public Set<StringgetRequiredPermissions()
  • @@ -622,7 +622,7 @@ public void 
  • requiresPermission

    -
    public boolean requiresPermission(String permission)
    +
    public boolean requiresPermission(String permission)
  • @@ -631,7 +631,7 @@ public void 
  • getName

    -
    public String getName()
    +
    public String getName()
  • @@ -640,7 +640,7 @@ public void 
  • getExceptionHandler

    -
    public ExceptionHandler getExceptionHandler()
    +
    public ExceptionHandler getExceptionHandler()
  • @@ -649,7 +649,7 @@ public void 
  • setExceptionHandler

    -
    public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler)
    +
    public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler)
  • @@ -658,7 +658,7 @@ public void 
  • getDefaultRegisteredCommand

    -
    public RegisteredCommand getDefaultRegisteredCommand()
    +
    public RegisteredCommand getDefaultRegisteredCommand()
  • @@ -667,7 +667,7 @@ public void 
  • setContextFlags

    -
    public String setContextFlags(Class<?> cls,
    +
    public String setContextFlags(Class<?> cls,
                                   String flags)
  • @@ -677,7 +677,7 @@ public void 
  • getContextFlags

    -
    public String getContextFlags(Class<?> cls)
    +
    public String getContextFlags(Class<?> cls)
  • @@ -686,7 +686,7 @@ public void 
  • getRegisteredCommands

    -
    public List<RegisteredCommandgetRegisteredCommands()
    +
    public List<RegisteredCommandgetRegisteredCommands()
  • diff --git a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html index 8790759b..2471cbd8 100644 --- a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html @@ -56,784 +56,788 @@ 048import java.util.Collections; 049import java.util.HashMap; 050import java.util.HashSet; -051import java.util.List; -052import java.util.Map; -053import java.util.Objects; -054import java.util.Set; -055import java.util.Stack; -056import java.util.stream.Collectors; -057import java.util.stream.Stream; -058 -059/** -060 * A Base command is defined as a command group of related commands. -061 * A BaseCommand does not imply nor enforce that they use the same root command. -062 * <p> -063 * It is up to the end user how to organize their command. you could use 1 base command per -064 * command in your application. -065 * <p> -066 * Optionally (and encouraged), you can use the base command to represent a root command, and -067 * then each actionable command is a sub command -068 */ -069 -070public abstract class BaseCommand { -071 -072 /** -073 * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown -074 * argument to command states. -075 */ -076 static final String CATCHUNKNOWN = "__catchunknown"; -077 /** -078 * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the -079 * entire base command. -080 */ -081 static final String DEFAULT = "__default"; -082 -083 /** -084 * A map of all the registered commands for this base command, keyed to each potential subcommand to access it. -085 */ -086 final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create(); -087 -088 /** -089 * A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each. -090 */ -091 final Map<Class<?>, String> contextFlags = new HashMap<>(); -092 -093 /** -094 * What method was annoated with {@link PreCommand} to execute before commands. -095 */ -096 @Nullable -097 private Method preCommandHandler; -098 -099 /** -100 * What root command the user actually entered to access the currently executing command -101 */ -102 @SuppressWarnings("WeakerAccess") -103 private String execLabel; -104 /** -105 * What subcommand the user actually entered to access the currently executing command -106 */ -107 @SuppressWarnings("WeakerAccess") -108 private String execSubcommand; -109 /** -110 * What arguments the user actually entered after the root command to access the currently executing command -111 */ -112 @SuppressWarnings("WeakerAccess") -113 private String[] origArgs; -114 -115 /** -116 * The manager this is registered to -117 */ -118 CommandManager<?, ?, ?, ?, ?, ?> manager = null; -119 -120 /** -121 * The command which owns this. This may be null if there are no owners. -122 */ -123 BaseCommand parentCommand; -124 Map<String, RootCommand> registeredCommands = new HashMap<>(); -125 /** -126 * The description of the command. This may be null if no description has been provided. -127 * Used for help documentation -128 */ -129 @Nullable String description; -130 /** -131 * The name of the command. This may be null if no name has been provided. -132 */ -133 @Nullable String commandName; -134 /** -135 * The permission of the command. This may be null if no permission has been provided. -136 */ -137 @Nullable String permission; -138 /** -139 * The conditions of the command. This may be null if no conditions has been provided. -140 */ -141 @Nullable String conditions; -142 /** -143 * Identifies if the command has an explicit help command annotated with {@link HelpCommand} -144 */ -145 boolean hasHelpCommand; -146 -147 /** -148 * The handler of all uncaught exceptions thrown by the user's command implementation. -149 */ -150 private ExceptionHandler exceptionHandler = null; -151 /** -152 * The last operative context data of this command. This may be null if this command hasn't been run yet. -153 */ -154 private final ThreadLocal<CommandOperationContext> lastCommandOperationContext = new ThreadLocal<>(); -155 /** -156 * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this -157 */ -158 @Nullable -159 private String parentSubcommand; -160 -161 /** -162 * The permissions of the command. -163 */ -164 private final Set<String> permissions = new HashSet<>(); -165 -166 public BaseCommand() { -167 } -168 -169 /** -170 * Constructor based defining of commands will be removed in the next version bump. -171 * -172 * @param cmd -173 * @deprecated Please switch to {@link CommandAlias} for defining all root commands. -174 */ -175 @Deprecated -176 public BaseCommand(@Nullable String cmd) { -177 this.commandName = cmd; -178 } -179 -180 /** -181 * Returns a reference to the last used CommandOperationContext. -182 * This method is ThreadLocal, in that it can only be used on a thread that has executed a command -183 * -184 * @return -185 */ -186 public CommandOperationContext getLastCommandOperationContext() { -187 return lastCommandOperationContext.get(); -188 } -189 -190 /** -191 * Gets the root command name that the user actually typed -192 * -193 * @return Name -194 */ -195 public String getExecCommandLabel() { -196 return execLabel; -197 } -198 -199 /** -200 * Gets the actual sub command name the user typed -201 * -202 * @return Name -203 */ -204 public String getExecSubcommand() { -205 return execSubcommand; -206 } -207 -208 /** -209 * Gets the actual args in string form the user typed -210 * -211 * @return Args -212 */ -213 public String[] getOrigArgs() { -214 return origArgs; -215 } -216 -217 /** -218 * This should be called whenever the command gets registered. -219 * It sets all required fields correctly and injects dependencies. -220 * -221 * @param manager The manager to register as this command's owner and handler. -222 */ -223 void onRegister(CommandManager manager) { -224 onRegister(manager, this.commandName); -225 } -226 -227 /** -228 * This should be called whenever the command gets registered. -229 * It sets all required fields correctly and injects dependencies. -230 * -231 * @param manager The manager to register as this command's owner and handler. -232 * @param cmd The command name to use register with. -233 */ -234 private void onRegister(CommandManager manager, String cmd) { -235 manager.injectDependencies(this); -236 this.manager = manager; -237 -238 final Annotations annotations = manager.getAnnotations(); -239 final Class<? extends BaseCommand> self = this.getClass(); -240 -241 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); -242 -243 if (cmd == null && cmdAliases != null) { -244 cmd = cmdAliases[0]; -245 } -246 -247 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); -248 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); -249 this.description = this.commandName + " commands"; -250 this.parentSubcommand = getParentSubcommand(self); -251 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -252 -253 registerSubcommands(); -254 computePermissions(); -255 registerSubclasses(cmd); -256 -257 if (cmdAliases != null) { -258 Set<String> cmdList = new HashSet<>(); -259 Collections.addAll(cmdList, cmdAliases); -260 cmdList.remove(cmd); -261 for (String cmdAlias : cmdList) { -262 register(cmdAlias, this); -263 } -264 } -265 -266 if (cmd != null) { -267 register(cmd, this); -268 } -269 } -270 -271 /** -272 * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. -273 * -274 * @param cmd The command name of this command. -275 */ -276 private void registerSubclasses(String cmd) { -277 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { -278 if (BaseCommand.class.isAssignableFrom(clazz)) { -279 try { -280 BaseCommand subCommand = null; -281 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); -282 for (Constructor<?> declaredConstructor : declaredConstructors) { -283 -284 declaredConstructor.setAccessible(true); -285 Parameter[] parameters = declaredConstructor.getParameters(); -286 if (parameters.length == 1) { -287 subCommand = (BaseCommand) declaredConstructor.newInstance(this); -288 } else { -289 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); -290 } -291 } -292 if (subCommand != null) { -293 subCommand.parentCommand = this; -294 subCommand.onRegister(manager, cmd); -295 this.subCommands.putAll(subCommand.subCommands); -296 this.registeredCommands.putAll(subCommand.registeredCommands); -297 } else { -298 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); -299 } -300 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { -301 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); -302 } -303 } -304 } -305 } -306 -307 /** -308 * This registers all subcommands of the command. -309 */ -310 private void registerSubcommands() { -311 final Annotations annotations = manager.getAnnotations(); -312 boolean foundCatchUnknown = false; -313 boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); -314 -315 for (Method method : this.getClass().getMethods()) { -316 method.setAccessible(true); -317 String sublist = null; -318 String sub = getSubcommandValue(method); -319 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); -320 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); -321 -322 if (annotations.hasAnnotation(method, Default.class)) { -323 if (!isParentEmpty) { -324 sub = parentSubcommand; -325 } else { -326 registerSubcommand(method, DEFAULT); -327 } -328 } -329 -330 if (sub != null) { -331 sublist = sub; -332 } else if (commandAliases != null) { -333 sublist = commandAliases; -334 } else if (helpCommand != null) { -335 sublist = helpCommand; -336 hasHelpCommand = true; -337 } -338 -339 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); -340 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || -341 annotations.hasAnnotation(method, CatchAll.class) || -342 annotations.hasAnnotation(method, UnknownHandler.class); -343 -344 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { -345 if (!foundCatchUnknown) { -346 if (hasCatchUnknown) { -347 this.subCommands.get(CATCHUNKNOWN).clear(); -348 foundCatchUnknown = true; -349 } -350 registerSubcommand(method, CATCHUNKNOWN); -351 } else { -352 ACFUtil.sneaky(new IllegalStateException("Multiple @CatchUnknown/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -353 } -354 } else if (preCommand) { -355 if (this.preCommandHandler == null) { -356 this.preCommandHandler = method; -357 } else { -358 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -359 } -360 } -361 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { -362 registerSubcommand(method, sublist); -363 } -364 } -365 } -366 -367 /** -368 * This registers all the permissions required to execute this command. -369 */ -370 private void computePermissions() { -371 this.permissions.clear(); -372 if (this.permission != null && !this.permission.isEmpty()) { -373 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); -374 } -375 if (this.parentCommand != null) { -376 this.permissions.addAll(this.parentCommand.getRequiredPermissions()); -377 } -378 } -379 -380 /** -381 * Gets the subcommand name of the method given. -382 * -383 * @param method The method to check. -384 * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. -385 */ -386 private String getSubcommandValue(Method method) { -387 final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); -388 if (sub == null) { -389 return null; -390 } -391 Class<?> clazz = method.getDeclaringClass(); -392 String parent = getParentSubcommand(clazz); -393 return parent == null || parent.isEmpty() ? sub : parent + " " + sub; -394 } -395 -396 private String getParentSubcommand(Class<?> clazz) { -397 List<String> subList = new ArrayList<>(); -398 while (clazz != null) { -399 String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); -400 if (sub != null) { -401 subList.add(sub); -402 } -403 clazz = clazz.getEnclosingClass(); -404 } -405 Collections.reverse(subList); -406 return ACFUtil.join(subList, " "); -407 } -408 -409 /** -410 * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. -411 * -412 * @param name Name of the parent to cmd. -413 * @param cmd The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. -414 */ -415 private void register(String name, BaseCommand cmd) { -416 String nameLower = name.toLowerCase(); -417 RootCommand rootCommand = manager.obtainRootCommand(nameLower); -418 rootCommand.addChild(cmd); -419 -420 this.registeredCommands.put(nameLower, rootCommand); -421 } -422 -423 /** -424 * Registers the given {@link Method} as a subcommand. -425 * -426 * @param method The method to register as a subcommand. -427 * @param subCommand The subcommand's name(s). -428 */ -429 private void registerSubcommand(Method method, String subCommand) { -430 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); -431 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); -432 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. -433 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); -434 -435 // Strip pipes off for auto complete addition -436 for (int i = 0; i < subCommandParts.length; i++) { -437 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); -438 if (split.length == 0 || split[0].isEmpty()) { -439 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); -440 } -441 subCommandParts[i] = split[0]; -442 } -443 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); -444 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); -445 -446 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; -447 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); -448 -449 for (String subcmd : cmdList) { -450 subCommands.put(subcmd, cmd); -451 } -452 cmd.addSubcommands(cmdList); -453 -454 if (aliasNames != null) { -455 for (String name : aliasNames) { -456 register(name, new ForwardingCommand(this, cmd, subCommandParts)); -457 } -458 } -459 } -460 -461 /** -462 * Takes a string like "foo|bar baz|qux" and generates a list of -463 * - foo baz -464 * - foo qux -465 * - bar baz -466 * - bar qux -467 * <p> -468 * For every possible sub command combination -469 * -470 * @param subCommandParts -471 * @return List of all sub command possibilities -472 */ -473 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { -474 int i = 0; -475 Set<String> current = null; -476 while (true) { -477 Set<String> newList = new HashSet<>(); -478 -479 if (i < subCommandParts.length) { -480 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { -481 if (current != null) { -482 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); -483 } else { -484 newList.add(s1); -485 } -486 } -487 } -488 -489 if (i + 1 < subCommandParts.length) { -490 current = newList; -491 i = i + 1; -492 continue; -493 } -494 -495 return newList; -496 } -497 } +051import java.util.LinkedHashSet; +052import java.util.List; +053import java.util.Map; +054import java.util.Objects; +055import java.util.Set; +056import java.util.Stack; +057import java.util.stream.Collectors; +058import java.util.stream.Stream; +059 +060/** +061 * A Base command is defined as a command group of related commands. +062 * A BaseCommand does not imply nor enforce that they use the same root command. +063 * <p> +064 * It is up to the end user how to organize their command. you could use 1 base command per +065 * command in your application. +066 * <p> +067 * Optionally (and encouraged), you can use the base command to represent a root command, and +068 * then each actionable command is a sub command +069 */ +070 +071public abstract class BaseCommand { +072 +073 /** +074 * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown +075 * argument to command states. +076 */ +077 static final String CATCHUNKNOWN = "__catchunknown"; +078 /** +079 * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the +080 * entire base command. +081 */ +082 static final String DEFAULT = "__default"; +083 +084 /** +085 * A map of all the registered commands for this base command, keyed to each potential subcommand to access it. +086 */ +087 final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create(); +088 +089 /** +090 * A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each. +091 */ +092 final Map<Class<?>, String> contextFlags = new HashMap<>(); +093 +094 /** +095 * What method was annoated with {@link PreCommand} to execute before commands. +096 */ +097 @Nullable +098 private Method preCommandHandler; +099 +100 /** +101 * What root command the user actually entered to access the currently executing command +102 */ +103 @SuppressWarnings("WeakerAccess") +104 private String execLabel; +105 /** +106 * What subcommand the user actually entered to access the currently executing command +107 */ +108 @SuppressWarnings("WeakerAccess") +109 private String execSubcommand; +110 /** +111 * What arguments the user actually entered after the root command to access the currently executing command +112 */ +113 @SuppressWarnings("WeakerAccess") +114 private String[] origArgs; +115 +116 /** +117 * The manager this is registered to +118 */ +119 CommandManager<?, ?, ?, ?, ?, ?> manager = null; +120 +121 /** +122 * The command which owns this. This may be null if there are no owners. +123 */ +124 BaseCommand parentCommand; +125 Map<String, RootCommand> registeredCommands = new HashMap<>(); +126 /** +127 * The description of the command. This may be null if no description has been provided. +128 * Used for help documentation +129 */ +130 @Nullable String description; +131 /** +132 * The name of the command. This may be null if no name has been provided. +133 */ +134 @Nullable String commandName; +135 /** +136 * The permission of the command. This may be null if no permission has been provided. +137 */ +138 @Nullable String permission; +139 /** +140 * The conditions of the command. This may be null if no conditions has been provided. +141 */ +142 @Nullable String conditions; +143 /** +144 * Identifies if the command has an explicit help command annotated with {@link HelpCommand} +145 */ +146 boolean hasHelpCommand; +147 +148 /** +149 * The handler of all uncaught exceptions thrown by the user's command implementation. +150 */ +151 private ExceptionHandler exceptionHandler = null; +152 /** +153 * The last operative context data of this command. This may be null if this command hasn't been run yet. +154 */ +155 private final ThreadLocal<CommandOperationContext> lastCommandOperationContext = new ThreadLocal<>(); +156 /** +157 * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this +158 */ +159 @Nullable +160 private String parentSubcommand; +161 +162 /** +163 * The permissions of the command. +164 */ +165 private final Set<String> permissions = new HashSet<>(); +166 +167 public BaseCommand() { +168 } +169 +170 /** +171 * Constructor based defining of commands will be removed in the next version bump. +172 * +173 * @param cmd +174 * @deprecated Please switch to {@link CommandAlias} for defining all root commands. +175 */ +176 @Deprecated +177 public BaseCommand(@Nullable String cmd) { +178 this.commandName = cmd; +179 } +180 +181 /** +182 * Returns a reference to the last used CommandOperationContext. +183 * This method is ThreadLocal, in that it can only be used on a thread that has executed a command +184 * +185 * @return +186 */ +187 public CommandOperationContext getLastCommandOperationContext() { +188 return lastCommandOperationContext.get(); +189 } +190 +191 /** +192 * Gets the root command name that the user actually typed +193 * +194 * @return Name +195 */ +196 public String getExecCommandLabel() { +197 return execLabel; +198 } +199 +200 /** +201 * Gets the actual sub command name the user typed +202 * +203 * @return Name +204 */ +205 public String getExecSubcommand() { +206 return execSubcommand; +207 } +208 +209 /** +210 * Gets the actual args in string form the user typed +211 * +212 * @return Args +213 */ +214 public String[] getOrigArgs() { +215 return origArgs; +216 } +217 +218 /** +219 * This should be called whenever the command gets registered. +220 * It sets all required fields correctly and injects dependencies. +221 * +222 * @param manager The manager to register as this command's owner and handler. +223 */ +224 void onRegister(CommandManager manager) { +225 onRegister(manager, this.commandName); +226 } +227 +228 /** +229 * This should be called whenever the command gets registered. +230 * It sets all required fields correctly and injects dependencies. +231 * +232 * @param manager The manager to register as this command's owner and handler. +233 * @param cmd The command name to use register with. +234 */ +235 private void onRegister(CommandManager manager, String cmd) { +236 manager.injectDependencies(this); +237 this.manager = manager; +238 +239 final Annotations annotations = manager.getAnnotations(); +240 final Class<? extends BaseCommand> self = this.getClass(); +241 +242 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); +243 +244 if (cmd == null && cmdAliases != null) { +245 cmd = cmdAliases[0]; +246 } +247 +248 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); +249 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); +250 this.description = this.commandName + " commands"; +251 this.parentSubcommand = getParentSubcommand(self); +252 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +253 +254 registerSubcommands(); +255 computePermissions(); +256 registerSubclasses(cmd); +257 +258 if (cmdAliases != null) { +259 Set<String> cmdList = new HashSet<>(); +260 Collections.addAll(cmdList, cmdAliases); +261 cmdList.remove(cmd); +262 for (String cmdAlias : cmdList) { +263 register(cmdAlias, this); +264 } +265 } +266 +267 if (cmd != null) { +268 register(cmd, this); +269 } +270 } +271 +272 /** +273 * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. +274 * +275 * @param cmd The command name of this command. +276 */ +277 private void registerSubclasses(String cmd) { +278 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { +279 if (BaseCommand.class.isAssignableFrom(clazz)) { +280 try { +281 BaseCommand subCommand = null; +282 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); +283 for (Constructor<?> declaredConstructor : declaredConstructors) { +284 +285 declaredConstructor.setAccessible(true); +286 Parameter[] parameters = declaredConstructor.getParameters(); +287 if (parameters.length == 1) { +288 subCommand = (BaseCommand) declaredConstructor.newInstance(this); +289 } else { +290 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); +291 } +292 } +293 if (subCommand != null) { +294 subCommand.parentCommand = this; +295 subCommand.onRegister(manager, cmd); +296 this.subCommands.putAll(subCommand.subCommands); +297 this.registeredCommands.putAll(subCommand.registeredCommands); +298 } else { +299 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); +300 } +301 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { +302 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); +303 } +304 } +305 } +306 } +307 +308 /** +309 * This registers all subcommands of the command. +310 */ +311 private void registerSubcommands() { +312 final Annotations annotations = manager.getAnnotations(); +313 boolean foundCatchUnknown = false; +314 boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); +315 Set<Method> methods = new LinkedHashSet<>(); +316 Collections.addAll(methods, this.getClass().getDeclaredMethods()); +317 Collections.addAll(methods, this.getClass().getMethods()); +318 +319 for (Method method : methods) { +320 method.setAccessible(true); +321 String sublist = null; +322 String sub = getSubcommandValue(method); +323 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); +324 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); +325 +326 if (annotations.hasAnnotation(method, Default.class)) { +327 if (!isParentEmpty) { +328 sub = parentSubcommand; +329 } else { +330 registerSubcommand(method, DEFAULT); +331 } +332 } +333 +334 if (sub != null) { +335 sublist = sub; +336 } else if (commandAliases != null) { +337 sublist = commandAliases; +338 } else if (helpCommand != null) { +339 sublist = helpCommand; +340 hasHelpCommand = true; +341 } +342 +343 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); +344 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || +345 annotations.hasAnnotation(method, CatchAll.class) || +346 annotations.hasAnnotation(method, UnknownHandler.class); +347 +348 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { +349 if (!foundCatchUnknown) { +350 if (hasCatchUnknown) { +351 this.subCommands.get(CATCHUNKNOWN).clear(); +352 foundCatchUnknown = true; +353 } +354 registerSubcommand(method, CATCHUNKNOWN); +355 } else { +356 ACFUtil.sneaky(new IllegalStateException("Multiple @CatchUnknown/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +357 } +358 } else if (preCommand) { +359 if (this.preCommandHandler == null) { +360 this.preCommandHandler = method; +361 } else { +362 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +363 } +364 } +365 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { +366 registerSubcommand(method, sublist); +367 } +368 } +369 } +370 +371 /** +372 * This registers all the permissions required to execute this command. +373 */ +374 private void computePermissions() { +375 this.permissions.clear(); +376 if (this.permission != null && !this.permission.isEmpty()) { +377 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); +378 } +379 if (this.parentCommand != null) { +380 this.permissions.addAll(this.parentCommand.getRequiredPermissions()); +381 } +382 } +383 +384 /** +385 * Gets the subcommand name of the method given. +386 * +387 * @param method The method to check. +388 * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. +389 */ +390 private String getSubcommandValue(Method method) { +391 final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); +392 if (sub == null) { +393 return null; +394 } +395 Class<?> clazz = method.getDeclaringClass(); +396 String parent = getParentSubcommand(clazz); +397 return parent == null || parent.isEmpty() ? sub : parent + " " + sub; +398 } +399 +400 private String getParentSubcommand(Class<?> clazz) { +401 List<String> subList = new ArrayList<>(); +402 while (clazz != null) { +403 String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); +404 if (sub != null) { +405 subList.add(sub); +406 } +407 clazz = clazz.getEnclosingClass(); +408 } +409 Collections.reverse(subList); +410 return ACFUtil.join(subList, " "); +411 } +412 +413 /** +414 * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. +415 * +416 * @param name Name of the parent to cmd. +417 * @param cmd The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. +418 */ +419 private void register(String name, BaseCommand cmd) { +420 String nameLower = name.toLowerCase(); +421 RootCommand rootCommand = manager.obtainRootCommand(nameLower); +422 rootCommand.addChild(cmd); +423 +424 this.registeredCommands.put(nameLower, rootCommand); +425 } +426 +427 /** +428 * Registers the given {@link Method} as a subcommand. +429 * +430 * @param method The method to register as a subcommand. +431 * @param subCommand The subcommand's name(s). +432 */ +433 private void registerSubcommand(Method method, String subCommand) { +434 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); +435 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); +436 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. +437 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); +438 +439 // Strip pipes off for auto complete addition +440 for (int i = 0; i < subCommandParts.length; i++) { +441 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); +442 if (split.length == 0 || split[0].isEmpty()) { +443 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); +444 } +445 subCommandParts[i] = split[0]; +446 } +447 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); +448 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); +449 +450 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; +451 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); +452 +453 for (String subcmd : cmdList) { +454 subCommands.put(subcmd, cmd); +455 } +456 cmd.addSubcommands(cmdList); +457 +458 if (aliasNames != null) { +459 for (String name : aliasNames) { +460 register(name, new ForwardingCommand(this, cmd, subCommandParts)); +461 } +462 } +463 } +464 +465 /** +466 * Takes a string like "foo|bar baz|qux" and generates a list of +467 * - foo baz +468 * - foo qux +469 * - bar baz +470 * - bar qux +471 * <p> +472 * For every possible sub command combination +473 * +474 * @param subCommandParts +475 * @return List of all sub command possibilities +476 */ +477 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { +478 int i = 0; +479 Set<String> current = null; +480 while (true) { +481 Set<String> newList = new HashSet<>(); +482 +483 if (i < subCommandParts.length) { +484 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { +485 if (current != null) { +486 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); +487 } else { +488 newList.add(s1); +489 } +490 } +491 } +492 +493 if (i + 1 < subCommandParts.length) { +494 current = newList; +495 i = i + 1; +496 continue; +497 } 498 -499 void execute(CommandIssuer issuer, CommandRouter.CommandRouteResult command) { -500 try { -501 CommandOperationContext commandContext = preCommandOperation(issuer, command.commandLabel, command.args, false); -502 execSubcommand = command.subcommand; -503 executeCommand(commandContext, issuer, command.args, command.cmd); -504 } finally { -505 postCommandOperation(); -506 } -507 } -508 -509 /** -510 * This is ran after any command operation has been performed. -511 */ -512 private void postCommandOperation() { -513 CommandManager.commandOperationContext.get().pop(); -514 execSubcommand = null; -515 execLabel = null; -516 origArgs = new String[]{}; -517 } -518 -519 /** -520 * This is ran before any command operation has been performed. -521 * -522 * @param issuer The user who executed the command. -523 * @param commandLabel The label the user used to execute the command. This is not the command name, but their input. -524 * When there is multiple aliases, this is which alias was used -525 * @param args The arguments passed to the command when executing it. -526 * @param isAsync Whether the command is executed off of the main thread. -527 * @return The context which is being registered to the {@link CommandManager}'s {@link -528 * CommandManager#commandOperationContext thread local stack}. -529 */ -530 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { -531 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); -532 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); -533 contexts.push(context); -534 lastCommandOperationContext.set(context); -535 execSubcommand = null; -536 execLabel = commandLabel; -537 origArgs = args; -538 return context; -539 } -540 -541 /** -542 * Gets the current command issuer. -543 * -544 * @return The current command issuer. -545 */ -546 public CommandIssuer getCurrentCommandIssuer() { -547 return CommandManager.getCurrentCommandIssuer(); -548 } -549 -550 /** -551 * Gets the current command manager. -552 * -553 * @return The current command manager. -554 */ -555 public CommandManager getCurrentCommandManager() { -556 return CommandManager.getCurrentCommandManager(); -557 } -558 -559 private void executeCommand(CommandOperationContext commandOperationContext, -560 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { -561 if (cmd.hasPermission(issuer)) { -562 commandOperationContext.setRegisteredCommand(cmd); -563 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { -564 return; -565 } -566 List<String> sargs = Arrays.asList(args); -567 cmd.invoke(issuer, sargs, commandOperationContext); -568 } else { -569 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); -570 } -571 } -572 -573 /** -574 * Please use command conditions for restricting execution -575 * -576 * @param issuer -577 * @param cmd -578 * @return -579 * @deprecated See {@link CommandConditions} -580 */ -581 @SuppressWarnings("DeprecatedIsStillUsed") -582 @Deprecated -583 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { -584 return true; -585 } -586 -587 /** -588 * Gets tab completed data from the given command from the user. -589 * -590 * @param issuer The user who executed the tabcomplete. -591 * @param commandLabel The label which is being used by the user. -592 * @param args The arguments the user has typed so far. -593 * @return All possibilities in the tab complete. -594 */ -595 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { -596 return tabComplete(issuer, commandLabel, args, false); -597 } -598 -599 /** -600 * Gets the tab complete suggestions from a given command. This will automatically find anything -601 * which is valid for the specified command through the command's implementation. -602 * -603 * @param issuer The issuer of the command. -604 * @param commandLabel The command name as entered by the user instead of the ACF registered name. -605 * @param args All arguments entered by the user. -606 * @param isAsync Whether this is run off of the main thread. -607 * @return The possibilities to tab complete in no particular order. -608 */ -609 @SuppressWarnings("WeakerAccess") -610 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) -611 throws IllegalArgumentException { -612 return tabComplete(issuer, manager.getRootCommand(commandLabel.toLowerCase()), args, isAsync); -613 } -614 -615 List<String> tabComplete(CommandIssuer issuer, RootCommand rootCommand, String[] args, boolean isAsync) -616 throws IllegalArgumentException { -617 if (args.length == 0) { -618 args = new String[]{""}; -619 } -620 String commandLabel = rootCommand.getCommandName(); -621 try { -622 CommandRouter router = manager.getRouter(); -623 -624 preCommandOperation(issuer, commandLabel, args, isAsync); -625 -626 final RouteSearch search = router.routeCommand(rootCommand, commandLabel, args, true); +499 return newList; +500 } +501 } +502 +503 void execute(CommandIssuer issuer, CommandRouter.CommandRouteResult command) { +504 try { +505 CommandOperationContext commandContext = preCommandOperation(issuer, command.commandLabel, command.args, false); +506 execSubcommand = command.subcommand; +507 executeCommand(commandContext, issuer, command.args, command.cmd); +508 } finally { +509 postCommandOperation(); +510 } +511 } +512 +513 /** +514 * This is ran after any command operation has been performed. +515 */ +516 private void postCommandOperation() { +517 CommandManager.commandOperationContext.get().pop(); +518 execSubcommand = null; +519 execLabel = null; +520 origArgs = new String[]{}; +521 } +522 +523 /** +524 * This is ran before any command operation has been performed. +525 * +526 * @param issuer The user who executed the command. +527 * @param commandLabel The label the user used to execute the command. This is not the command name, but their input. +528 * When there is multiple aliases, this is which alias was used +529 * @param args The arguments passed to the command when executing it. +530 * @param isAsync Whether the command is executed off of the main thread. +531 * @return The context which is being registered to the {@link CommandManager}'s {@link +532 * CommandManager#commandOperationContext thread local stack}. +533 */ +534 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { +535 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); +536 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); +537 contexts.push(context); +538 lastCommandOperationContext.set(context); +539 execSubcommand = null; +540 execLabel = commandLabel; +541 origArgs = args; +542 return context; +543 } +544 +545 /** +546 * Gets the current command issuer. +547 * +548 * @return The current command issuer. +549 */ +550 public CommandIssuer getCurrentCommandIssuer() { +551 return CommandManager.getCurrentCommandIssuer(); +552 } +553 +554 /** +555 * Gets the current command manager. +556 * +557 * @return The current command manager. +558 */ +559 public CommandManager getCurrentCommandManager() { +560 return CommandManager.getCurrentCommandManager(); +561 } +562 +563 private void executeCommand(CommandOperationContext commandOperationContext, +564 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { +565 if (cmd.hasPermission(issuer)) { +566 commandOperationContext.setRegisteredCommand(cmd); +567 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { +568 return; +569 } +570 List<String> sargs = Arrays.asList(args); +571 cmd.invoke(issuer, sargs, commandOperationContext); +572 } else { +573 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); +574 } +575 } +576 +577 /** +578 * Please use command conditions for restricting execution +579 * +580 * @param issuer +581 * @param cmd +582 * @return +583 * @deprecated See {@link CommandConditions} +584 */ +585 @SuppressWarnings("DeprecatedIsStillUsed") +586 @Deprecated +587 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { +588 return true; +589 } +590 +591 /** +592 * Gets tab completed data from the given command from the user. +593 * +594 * @param issuer The user who executed the tabcomplete. +595 * @param commandLabel The label which is being used by the user. +596 * @param args The arguments the user has typed so far. +597 * @return All possibilities in the tab complete. +598 */ +599 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { +600 return tabComplete(issuer, commandLabel, args, false); +601 } +602 +603 /** +604 * Gets the tab complete suggestions from a given command. This will automatically find anything +605 * which is valid for the specified command through the command's implementation. +606 * +607 * @param issuer The issuer of the command. +608 * @param commandLabel The command name as entered by the user instead of the ACF registered name. +609 * @param args All arguments entered by the user. +610 * @param isAsync Whether this is run off of the main thread. +611 * @return The possibilities to tab complete in no particular order. +612 */ +613 @SuppressWarnings("WeakerAccess") +614 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) +615 throws IllegalArgumentException { +616 return tabComplete(issuer, manager.getRootCommand(commandLabel.toLowerCase()), args, isAsync); +617 } +618 +619 List<String> tabComplete(CommandIssuer issuer, RootCommand rootCommand, String[] args, boolean isAsync) +620 throws IllegalArgumentException { +621 if (args.length == 0) { +622 args = new String[]{""}; +623 } +624 String commandLabel = rootCommand.getCommandName(); +625 try { +626 CommandRouter router = manager.getRouter(); 627 -628 final List<String> cmds = new ArrayList<>(); -629 if (search != null) { -630 CommandRouter.CommandRouteResult result = router.matchCommand(search, true); -631 if (result != null) { -632 cmds.addAll(completeCommand(issuer, result.cmd, result.args, commandLabel, isAsync)); -633 } -634 } -635 -636 return filterTabComplete(args[args.length - 1], cmds); -637 } finally { -638 postCommandOperation(); -639 } -640 } -641 -642 /** -643 * Gets all subcommands which are possible to tabcomplete. -644 * -645 * @param issuer The command issuer. -646 * @param args -647 * @return -648 */ -649 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { -650 final Set<String> cmds = new HashSet<>(); -651 final int cmdIndex = Math.max(0, args.length - 1); -652 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); -653 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { -654 final String key = entry.getKey(); -655 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { -656 final RegisteredCommand value = entry.getValue(); -657 if (!value.hasPermission(issuer) || value.isPrivate) { -658 continue; -659 } -660 -661 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); -662 cmds.add(split[cmdIndex]); -663 } -664 } -665 return new ArrayList<>(cmds); -666 } -667 -668 /** -669 * Complete a command properly per issuer and input. -670 * -671 * @param issuer The user who executed this. -672 * @param cmd The command to be completed. -673 * @param args All arguments given by the user. -674 * @param commandLabel The command name the user used. -675 * @param isAsync Whether the command was executed async. -676 * @return All results to complete the command. -677 */ -678 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { -679 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { -680 return Collections.emptyList(); -681 } -682 -683 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); -684 return filterTabComplete(args[args.length - 1], cmds); -685 } +628 preCommandOperation(issuer, commandLabel, args, isAsync); +629 +630 final RouteSearch search = router.routeCommand(rootCommand, commandLabel, args, true); +631 +632 final List<String> cmds = new ArrayList<>(); +633 if (search != null) { +634 CommandRouter.CommandRouteResult result = router.matchCommand(search, true); +635 if (result != null) { +636 cmds.addAll(completeCommand(issuer, result.cmd, result.args, commandLabel, isAsync)); +637 } +638 } +639 +640 return filterTabComplete(args[args.length - 1], cmds); +641 } finally { +642 postCommandOperation(); +643 } +644 } +645 +646 /** +647 * Gets all subcommands which are possible to tabcomplete. +648 * +649 * @param issuer The command issuer. +650 * @param args +651 * @return +652 */ +653 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { +654 final Set<String> cmds = new HashSet<>(); +655 final int cmdIndex = Math.max(0, args.length - 1); +656 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); +657 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { +658 final String key = entry.getKey(); +659 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { +660 final RegisteredCommand value = entry.getValue(); +661 if (!value.hasPermission(issuer) || value.isPrivate) { +662 continue; +663 } +664 +665 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); +666 cmds.add(split[cmdIndex]); +667 } +668 } +669 return new ArrayList<>(cmds); +670 } +671 +672 /** +673 * Complete a command properly per issuer and input. +674 * +675 * @param issuer The user who executed this. +676 * @param cmd The command to be completed. +677 * @param args All arguments given by the user. +678 * @param commandLabel The command name the user used. +679 * @param isAsync Whether the command was executed async. +680 * @return All results to complete the command. +681 */ +682 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { +683 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { +684 return Collections.emptyList(); +685 } 686 -687 /** -688 * Gets the actual args in string form the user typed -689 * This returns a list of all tab complete options which are possible with the given argument and commands. -690 * -691 * @param arg Argument which was pressed tab on. -692 * @param cmds The possibilities to return. -693 * @return All possible options. This may be empty. -694 */ -695 private static List<String> filterTabComplete(String arg, List<String> cmds) { -696 return cmds.stream() -697 .distinct() -698 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) -699 .collect(Collectors.toList()); -700 } -701 -702 /** -703 * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. -704 * -705 * @param commandOperationContext The context to use. -706 * @param cmd The command executed. -707 * @param issuer The issuer who executed the command. -708 * @param args The arguments the issuer provided. -709 * @return Whether something went wrong. -710 */ -711 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { -712 Method pre = this.preCommandHandler; -713 if (pre != null) { -714 try { -715 Class<?>[] types = pre.getParameterTypes(); -716 Object[] parameters = new Object[pre.getParameterCount()]; -717 for (int i = 0; i < parameters.length; i++) { -718 Class<?> type = types[i]; -719 Object issuerObject = issuer.getIssuer(); -720 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { -721 parameters[i] = issuerObject; -722 } else if (CommandIssuer.class.isAssignableFrom(type)) { -723 parameters[i] = issuer; -724 } else if (RegisteredCommand.class.isAssignableFrom(type)) { -725 parameters[i] = cmd; -726 } else if (String[].class.isAssignableFrom((type))) { -727 parameters[i] = args; -728 } else { -729 parameters[i] = null; -730 } -731 } -732 -733 return (boolean) pre.invoke(this, parameters); -734 } catch (IllegalAccessException | InvocationTargetException e) { -735 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); -736 } -737 } -738 return false; -739 } -740 -741 /** -742 * @deprecated Unstable API -743 */ -744 @Deprecated -745 @UnstableAPI -746 public CommandHelp getCommandHelp() { -747 return manager.generateCommandHelp(); -748 } -749 -750 /** -751 * @deprecated Unstable API -752 */ -753 @Deprecated -754 @UnstableAPI -755 public void showCommandHelp() { -756 getCommandHelp().showHelp(); -757 } -758 -759 public void help(Object issuer, String[] args) { -760 help(manager.getCommandIssuer(issuer), args); +687 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); +688 return filterTabComplete(args[args.length - 1], cmds); +689 } +690 +691 /** +692 * Gets the actual args in string form the user typed +693 * This returns a list of all tab complete options which are possible with the given argument and commands. +694 * +695 * @param arg Argument which was pressed tab on. +696 * @param cmds The possibilities to return. +697 * @return All possible options. This may be empty. +698 */ +699 private static List<String> filterTabComplete(String arg, List<String> cmds) { +700 return cmds.stream() +701 .distinct() +702 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) +703 .collect(Collectors.toList()); +704 } +705 +706 /** +707 * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. +708 * +709 * @param commandOperationContext The context to use. +710 * @param cmd The command executed. +711 * @param issuer The issuer who executed the command. +712 * @param args The arguments the issuer provided. +713 * @return Whether something went wrong. +714 */ +715 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { +716 Method pre = this.preCommandHandler; +717 if (pre != null) { +718 try { +719 Class<?>[] types = pre.getParameterTypes(); +720 Object[] parameters = new Object[pre.getParameterCount()]; +721 for (int i = 0; i < parameters.length; i++) { +722 Class<?> type = types[i]; +723 Object issuerObject = issuer.getIssuer(); +724 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { +725 parameters[i] = issuerObject; +726 } else if (CommandIssuer.class.isAssignableFrom(type)) { +727 parameters[i] = issuer; +728 } else if (RegisteredCommand.class.isAssignableFrom(type)) { +729 parameters[i] = cmd; +730 } else if (String[].class.isAssignableFrom((type))) { +731 parameters[i] = args; +732 } else { +733 parameters[i] = null; +734 } +735 } +736 +737 return (boolean) pre.invoke(this, parameters); +738 } catch (IllegalAccessException | InvocationTargetException e) { +739 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); +740 } +741 } +742 return false; +743 } +744 +745 /** +746 * @deprecated Unstable API +747 */ +748 @Deprecated +749 @UnstableAPI +750 public CommandHelp getCommandHelp() { +751 return manager.generateCommandHelp(); +752 } +753 +754 /** +755 * @deprecated Unstable API +756 */ +757 @Deprecated +758 @UnstableAPI +759 public void showCommandHelp() { +760 getCommandHelp().showHelp(); 761 } 762 -763 public void help(CommandIssuer issuer, String[] args) { -764 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); +763 public void help(Object issuer, String[] args) { +764 help(manager.getCommandIssuer(issuer), args); 765 } 766 -767 public void doHelp(Object issuer, String... args) { -768 doHelp(manager.getCommandIssuer(issuer), args); +767 public void help(CommandIssuer issuer, String[] args) { +768 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); 769 } 770 -771 public void doHelp(CommandIssuer issuer, String... args) { -772 help(issuer, args); +771 public void doHelp(Object issuer, String... args) { +772 doHelp(manager.getCommandIssuer(issuer), args); 773 } 774 -775 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { -776 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, -777 "{command}", manager.getCommandPrefix(issuer) + cmd.command, -778 "{syntax}", cmd.syntaxText -779 ); -780 } -781 -782 public boolean hasPermission(Object issuer) { -783 return hasPermission(manager.getCommandIssuer(issuer)); +775 public void doHelp(CommandIssuer issuer, String... args) { +776 help(issuer, args); +777 } +778 +779 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { +780 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, +781 "{command}", manager.getCommandPrefix(issuer) + cmd.command, +782 "{syntax}", cmd.syntaxText +783 ); 784 } 785 -786 public boolean hasPermission(CommandIssuer issuer) { -787 return getRequiredPermissions().isEmpty() || getRequiredPermissions().stream().allMatch(permission -> manager.hasPermission(issuer, permission)); +786 public boolean hasPermission(Object issuer) { +787 return hasPermission(manager.getCommandIssuer(issuer)); 788 } 789 -790 public Set<String> getRequiredPermissions() { -791 return this.permissions; +790 public boolean hasPermission(CommandIssuer issuer) { +791 return getRequiredPermissions().isEmpty() || getRequiredPermissions().stream().allMatch(permission -> manager.hasPermission(issuer, permission)); 792 } 793 -794 public boolean requiresPermission(String permission) { -795 return getRequiredPermissions().contains(permission); +794 public Set<String> getRequiredPermissions() { +795 return this.permissions; 796 } 797 -798 public String getName() { -799 return commandName; +798 public boolean requiresPermission(String permission) { +799 return getRequiredPermissions().contains(permission); 800 } 801 -802 public ExceptionHandler getExceptionHandler() { -803 return exceptionHandler; +802 public String getName() { +803 return commandName; 804 } 805 -806 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { -807 this.exceptionHandler = exceptionHandler; -808 return this; -809 } -810 -811 public RegisteredCommand getDefaultRegisteredCommand() { -812 return ACFUtil.getFirstElement(this.subCommands.get(DEFAULT)); +806 public ExceptionHandler getExceptionHandler() { +807 return exceptionHandler; +808 } +809 +810 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { +811 this.exceptionHandler = exceptionHandler; +812 return this; 813 } 814 -815 public String setContextFlags(Class<?> cls, String flags) { -816 return this.contextFlags.put(cls, flags); +815 public RegisteredCommand getDefaultRegisteredCommand() { +816 return ACFUtil.getFirstElement(this.subCommands.get(DEFAULT)); 817 } 818 -819 public String getContextFlags(Class<?> cls) { -820 return this.contextFlags.get(cls); +819 public String setContextFlags(Class<?> cls, String flags) { +820 return this.contextFlags.put(cls, flags); 821 } 822 -823 public List<RegisteredCommand> getRegisteredCommands() { -824 List<RegisteredCommand> registeredCommands = new ArrayList<>(); -825 registeredCommands.addAll(this.subCommands.values()); -826 return registeredCommands; -827 } -828} +823 public String getContextFlags(Class<?> cls) { +824 return this.contextFlags.get(cls); +825 } +826 +827 public List<RegisteredCommand> getRegisteredCommands() { +828 List<RegisteredCommand> registeredCommands = new ArrayList<>(); +829 registeredCommands.addAll(this.subCommands.values()); +830 return registeredCommands; +831 } +832}