# Source code
source: package: co.aikar.commands, class: CommandParameter

    001/*
    002 * Copyright (c) 2016-2018 Daniel Ennis (Aikar) - MIT License
    003 *
    004 *  Permission is hereby granted, free of charge, to any person obtaining
    005 *  a copy of this software and associated documentation files (the
    006 *  "Software"), to deal in the Software without restriction, including
    007 *  without limitation the rights to use, copy, modify, merge, publish,
    008 *  distribute, sublicense, and/or sell copies of the Software, and to
    009 *  permit persons to whom the Software is furnished to do so, subject to
    010 *  the following conditions:
    011 *
    012 *  The above copyright notice and this permission notice shall be
    013 *  included in all copies or substantial portions of the Software.
    014 *
    015 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    016 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    017 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    018 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    019 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    020 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    021 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    022 */
    023
    024package co.aikar.commands;
    025
    026import co.aikar.commands.annotation.CommandPermission;
    027import co.aikar.commands.annotation.Conditions;
    028import co.aikar.commands.annotation.Default;
    029import co.aikar.commands.annotation.Description;
    030import co.aikar.commands.annotation.Flags;
    031import co.aikar.commands.annotation.Name;
    032import co.aikar.commands.annotation.Optional;
    033import co.aikar.commands.annotation.Single;
    034import co.aikar.commands.annotation.Syntax;
    035import co.aikar.commands.annotation.Values;
    036import co.aikar.commands.contexts.ContextResolver;
    037import co.aikar.commands.contexts.IssuerAwareContextResolver;
    038import co.aikar.commands.contexts.IssuerOnlyContextResolver;
    039import co.aikar.commands.contexts.OptionalContextResolver;
    040import co.aikar.locales.MessageKey;
    041
    042import java.lang.reflect.Parameter;
    043import java.util.Arrays;
    044import java.util.HashMap;
    045import java.util.HashSet;
    046import java.util.Map;
    047import java.util.Set;
    048
    049public class CommandParameter<CEC extends CommandExecutionContext<CEC, ? extends CommandIssuer>> {
    050    private final Parameter parameter;
    051    private final Class<?> type;
    052    private final String name;
    053    private final CommandManager manager;
    054    private final int paramIndex;
    055
    056    private ContextResolver<?, CEC> resolver;
    057    private boolean optional;
    058    private Set<String> permissions = new HashSet<>();
    059    private String permission;
    060    private String description;
    061    private String defaultValue;
    062    private String syntax;
    063    private String conditions;
    064    private boolean requiresInput;
    065    private boolean commandIssuer;
    066    private String[] values;
    067    private Map<String, String> flags;
    068    private boolean canConsumeInput;
    069    private boolean optionalResolver;
    070    boolean consumesRest;
    071    private boolean isLast;
    072    private boolean isOptionalInput;
    073    private CommandParameter<CEC> nextParam;
    074
    075    public CommandParameter(RegisteredCommand<CEC> command, Parameter param, int paramIndex, boolean isLast) {
    076        this.parameter = param;
    077        this.isLast = isLast;
    078        this.type = param.getType();
    079        this.manager = command.manager;
    080        this.paramIndex = paramIndex;
    081        Annotations annotations = manager.getAnnotations();
    082
    083        String annotationName = annotations.getAnnotationValue(param, Name.class, Annotations.REPLACEMENTS);
    084        this.name = annotationName != null ? annotationName : param.getName();
    085        this.defaultValue = annotations.getAnnotationValue(param, Default.class, Annotations.REPLACEMENTS | (type != String.class ? Annotations.NO_EMPTY : 0));
    086        this.description = annotations.getAnnotationValue(param, Description.class, Annotations.REPLACEMENTS | Annotations.DEFAULT_EMPTY);
    087        this.conditions = annotations.getAnnotationValue(param, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY);
    088
    089        //noinspection unchecked
    090        this.resolver = manager.getCommandContexts().getResolver(type);
    091        if (this.resolver == null) {
    092            ACFUtil.sneaky(new InvalidCommandContextException(
    093                    "Parameter " + type.getSimpleName() + " of " + command + " has no applicable context resolver"
    094            ));
    095        }
    096
    097        this.optional = annotations.hasAnnotation(param, Optional.class) || this.defaultValue != null || (isLast && type == String[].class);
    098        this.permission = annotations.getAnnotationValue(param, CommandPermission.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY);
    099        this.optionalResolver = isOptionalResolver(resolver);
    100        this.requiresInput = !this.optional && !this.optionalResolver;
    101        //noinspection unchecked
    102        this.commandIssuer = paramIndex == 0 && manager.isCommandIssuer(type);
    103        this.canConsumeInput = !this.commandIssuer && !(resolver instanceof IssuerOnlyContextResolver);
    104        this.consumesRest = isLast && ((type == String.class && !annotations.hasAnnotation(param, Single.class)) || (type == String[].class));
    105
    106        this.values = annotations.getAnnotationValues(param, Values.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY);
    107
    108        this.syntax = null;
    109        this.isOptionalInput = !requiresInput && canConsumeInput;
    110
    111        if (!commandIssuer) {
    112            this.syntax = annotations.getAnnotationValue(param, Syntax.class);
    113        }
    114
    115        this.flags = new HashMap<>();
    116        String flags = annotations.getAnnotationValue(param, Flags.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY);
    117        if (flags != null) {
    118            parseFlags(flags);
    119        }
    120        inheritContextFlags(command.scope);
    121        this.computePermissions();
    122    }
    123
    124    private void inheritContextFlags(BaseCommand scope) {
    125        if (!scope.contextFlags.isEmpty()) {
    126            Class<?> pCls = this.type;
    127            do {
    128                parseFlags(scope.contextFlags.get(pCls));
    129            } while ((pCls = pCls.getSuperclass()) != null);
    130        }
    131        if (scope.parentCommand != null) {
    132            inheritContextFlags(scope.parentCommand);
    133        }
    134    }
    135
    136    private void parseFlags(String flags) {
    137        if (flags != null) {
    138            for (String s : ACFPatterns.COMMA.split(manager.getCommandReplacements().replace(flags))) {
    139                String[] v = ACFPatterns.EQUALS.split(s, 2);
    140                if (!this.flags.containsKey(v[0])) {
    141                    this.flags.put(v[0], v.length > 1 ? v[1] : null);
    142                }
    143            }
    144        }
    145    }
    146
    147    private void computePermissions() {
    148        this.permissions.clear();
    149        if (this.permission != null && !this.permission.isEmpty()) {
    150            this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission)));
    151        }
    152    }
    153
    154    private boolean isOptionalResolver(ContextResolver<?, CEC> resolver) {
    155        return resolver instanceof IssuerAwareContextResolver
    156                || resolver instanceof IssuerOnlyContextResolver
    157                || resolver instanceof OptionalContextResolver;
    158    }
    159
    160
    161    public Parameter getParameter() {
    162        return parameter;
    163    }
    164
    165    public Class<?> getType() {
    166        return type;
    167    }
    168
    169    public String getName() {
    170        return name;
    171    }
    172
    173    public String getDisplayName(CommandIssuer issuer) {
    174        String translated = manager.getLocales().getOptionalMessage(issuer, MessageKey.of("acf-core.parameter." + name.toLowerCase()));
    175        return translated != null ? translated : name;
    176    }
    177
    178    public CommandManager getManager() {
    179        return manager;
    180    }
    181
    182    public int getParamIndex() {
    183        return paramIndex;
    184    }
    185
    186    public ContextResolver<?, CEC> getResolver() {
    187        return resolver;
    188    }
    189
    190    public void setResolver(ContextResolver<?, CEC> resolver) {
    191        this.resolver = resolver;
    192    }
    193
    194    public boolean isOptionalInput() {
    195        return isOptionalInput;
    196    }
    197
    198    public boolean isOptional() {
    199        return optional;
    200    }
    201
    202    public void setOptional(boolean optional) {
    203        this.optional = optional;
    204    }
    205
    206    public String getDescription() {
    207        return description;
    208    }
    209
    210    public void setDescription(String description) {
    211        this.description = description;
    212    }
    213
    214    public String getDefaultValue() {
    215        return defaultValue;
    216    }
    217
    218    public void setDefaultValue(String defaultValue) {
    219        this.defaultValue = defaultValue;
    220    }
    221
    222    public boolean isCommandIssuer() {
    223        return commandIssuer;
    224    }
    225
    226    public void setCommandIssuer(boolean commandIssuer) {
    227        this.commandIssuer = commandIssuer;
    228    }
    229
    230    public String[] getValues() {
    231        return values;
    232    }
    233
    234    public void setValues(String[] values) {
    235        this.values = values;
    236    }
    237
    238    public Map<String, String> getFlags() {
    239        return flags;
    240    }
    241
    242    public void setFlags(Map<String, String> flags) {
    243        this.flags = flags;
    244    }
    245
    246    public boolean canConsumeInput() {
    247        return canConsumeInput;
    248    }
    249
    250    public void setCanConsumeInput(boolean canConsumeInput) {
    251        this.canConsumeInput = canConsumeInput;
    252    }
    253
    254    public void setOptionalResolver(boolean optionalResolver) {
    255        this.optionalResolver = optionalResolver;
    256    }
    257
    258    public boolean isOptionalResolver() {
    259        return optionalResolver;
    260    }
    261
    262    public boolean requiresInput() {
    263        return requiresInput;
    264    }
    265
    266    public void setRequiresInput(boolean requiresInput) {
    267        this.requiresInput = requiresInput;
    268    }
    269
    270    public String getSyntax() {
    271        return getSyntax(null);
    272    }
    273
    274    public String getSyntax(CommandIssuer issuer) {
    275        if (commandIssuer) return null;
    276        if (syntax == null) {
    277            if (isOptionalInput) {
    278                return "[" + getDisplayName(issuer) + "]";
    279            } else if (requiresInput) {
    280                return "<" + getDisplayName(issuer) + ">";
    281            }
    282        }
    283        return syntax;
    284    }
    285
    286    public void setSyntax(String syntax) {
    287        this.syntax = syntax;
    288    }
    289
    290    public String getConditions() {
    291        return conditions;
    292    }
    293
    294    public void setConditions(String conditions) {
    295        this.conditions = conditions;
    296    }
    297
    298    public Set<String> getRequiredPermissions() {
    299        return permissions;
    300    }
    301
    302    public void setNextParam(CommandParameter<CEC> nextParam) {
    303        this.nextParam = nextParam;
    304    }
    305
    306    public CommandParameter<CEC> getNextParam() {
    307        return nextParam;
    308    }
    309
    310    public boolean canExecuteWithoutInput() {
    311        return (!canConsumeInput || isOptionalInput()) && (nextParam == null || nextParam.canExecuteWithoutInput());
    312    }
    313
    314    public boolean isLast() {
    315        return isLast;
    316    }
    317}