use of dev.rosewood.rosegarden.manager.AbstractCommandManager in project RoseGarden by Rosewood-Development.
the class RoseCommand method validateExecuteMethod.
/**
* Validates that the command has a valid {@link RoseExecutable} layout.
* The following conditions must be met:
* <ul>
* <li>Must have a {@code public void} method annotated with {@link RoseExecutable}</li>
* <li>First parameter must be a {@link CommandContext}</li>
* <li>All parameters must have a registered {@link RoseCommandArgumentHandler} (excluding {@link CommandContext} and {@link RoseSubCommand})</li>
* <li>Primitive typed parameters must not be marked as {@link Optional}, use wrapped types instead</li>
* <li>If a parameter is marked as {@link Optional} then all subsequent parameters must also be marked as {@link Optional}</li>
* <li>If the last parameter is a {@link RoseSubCommand}, there must be at least one registered {@link RoseSubCommand}</li>
* <li>No parameters are allowed after the {@link RoseSubCommand}</li>
* </ul>
*
* @throws InvalidRoseCommandArgumentsException if any of the above conditions are not met
*/
private void validateExecuteMethod() {
try {
this.getExecuteMethod();
} catch (IllegalStateException e) {
throw new InvalidRoseCommandArgumentsException("No method marked as RoseExecutable detected");
}
Parameter[] rawParameters = this.getExecuteMethod().getParameters();
if (rawParameters.length == 0 || rawParameters[0].getType() != CommandContext.class)
throw new InvalidRoseCommandArgumentsException("First method parameter is not a CommandContext");
AbstractCommandManager commandManager = this.rosePlugin.getManager(AbstractCommandManager.class);
boolean first = true;
boolean optionalFound = false;
boolean subCommandFound = false;
for (Parameter parameter : rawParameters) {
if (first) {
first = false;
continue;
} else if (parameter.getType() == CommandContext.class) {
throw new InvalidRoseCommandArgumentsException("Only the first parameter may be a CommandContext");
}
if (subCommandFound)
throw new InvalidRoseCommandArgumentsException("Parameters after a RoseSubCommand are not allowed");
if (optionalFound && !parameter.isAnnotationPresent(Optional.class))
throw new InvalidRoseCommandArgumentsException("Parameter '" + parameter.getType().getSimpleName() + " " + parameter.getName() + "' must be marked as Optional because a previous parameter was already marked as Optional");
if (parameter.getType() != RoseSubCommand.class) {
try {
commandManager.resolveArgumentHandler(parameter.getType());
} catch (IllegalStateException e) {
throw new InvalidRoseCommandArgumentsException("Parameter '" + parameter.getType().getSimpleName() + " " + parameter.getName() + "' is missing a RoseCommandArgumentHandler");
}
} else {
subCommandFound = true;
}
if (parameter.isAnnotationPresent(Optional.class)) {
if (parameter.getType().isPrimitive())
throw new InvalidRoseCommandArgumentsException("Parameter '" + parameter.getType().getSimpleName() + " " + parameter.getName() + "' is primitive but is marked as Optional. Change to a " + RoseGardenUtils.getPrimitiveAsWrapper(parameter.getType()) + " instead");
optionalFound = true;
}
}
if (subCommandFound && this.subCommands.isEmpty())
throw new InvalidRoseCommandArgumentsException("No subcommands are registered but at least one is required");
}
Aggregations