Search in sources :

Example 1 with AbstractCommandManager

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");
}
Also used : AbstractCommandManager(dev.rosewood.rosegarden.manager.AbstractCommandManager) Parameter(java.lang.reflect.Parameter)

Aggregations

AbstractCommandManager (dev.rosewood.rosegarden.manager.AbstractCommandManager)1 Parameter (java.lang.reflect.Parameter)1