    001/*
    002  Licensed to the Apache Software Foundation (ASF) under one or more
    003  contributor license agreements.  See the NOTICE file distributed with
    004  this work for additional information regarding copyright ownership.
    005  The ASF licenses this file to You under the Apache License, Version 2.0
    006  (the "License"); you may not use this file except in compliance with
    007  the License.  You may obtain a copy of the License at
    008
    009      http://www.apache.org/licenses/LICENSE-2.0
    010
    011  Unless required by applicable law or agreed to in writing, software
    012  distributed under the License is distributed on an "AS IS" BASIS,
    013  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014  See the License for the specific language governing permissions and
    015  limitations under the License.
    016 */
    017
    018package org.apache.commons.cli;
    019
    020/**
    021 * OptionBuilder allows the user to create Options using descriptive methods.
    022 * <p>
    023 * Details on the Builder pattern can be found at
    024 * <a href="https://c2.com/cgi-bin/wiki?BuilderPattern">https://c2.com/cgi-bin/wiki?BuilderPattern</a>.
    025 * <p>
    026 * This class is NOT thread safe. See <a href="https://issues.apache.org/jira/browse/CLI-209">CLI-209</a>
    027 *
    028 * @since 1.0
    029 * @deprecated since 1.3, use {@link Option#builder(String)} instead
    030 */
    031@Deprecated
    032public final class OptionBuilder {
    033
    034    /** Long option */
    035    private static String longOption;
    036
    037    /** Option description */
    038    private static String description;
    039
    040    /** Argument name */
    041    private static String argName;
    042
    043    /** Is required? */
    044    private static boolean required;
    045
    046    /** The number of arguments */
    047    private static int argCount = Option.UNINITIALIZED;
    048
    049    /** Option type */
    050    private static Class<?> type;
    051
    052    /** Option can have an optional argument value */
    053    private static boolean optionalArg;
    054
    055    /** Value separator for argument value */
    056    private static char valueSeparator;
    057
    058    /** Option builder instance */
    059    private static final OptionBuilder INSTANCE = new OptionBuilder();
    060
    061    static {
    062        // ensure the consistency of the initial values
    063        reset();
    064    }
    065
    066    /**
    067     * Creates an Option using the current settings
    068     *
    069     * @return the Option instance
    070     * @throws IllegalArgumentException if {@code longOpt} has not been set.
    071     */
    072    public static Option create() throws IllegalArgumentException {
    073        if (longOption == null) {
    074            reset();
    075            throw new IllegalArgumentException("must specify longopt");
    076        }
    077
    078        return create(null);
    079    }
    080
    081    /**
    082     * Creates an Option using the current settings and with the specified Option {@code char}.
    083     *
    084     * @param opt the character representation of the Option
    085     * @return the Option instance
    086     * @throws IllegalArgumentException if {@code opt} is not a valid character. See Option.
    087     */
    088    public static Option create(final char opt) throws IllegalArgumentException {
    089        return create(String.valueOf(opt));
    090    }
    091
    092    /**
    093     * Creates an Option using the current settings and with the specified Option {@code char}.
    094     *
    095     * @param opt the {@code String} representation of the Option
    096     * @return the Option instance
    097     * @throws IllegalArgumentException if {@code opt} is not a valid character. See Option.
    098     */
    099    public static Option create(final String opt) throws IllegalArgumentException {
    100        Option option;
    101        try {
    102            // create the option
    103            option = new Option(opt, description);
    104
    105            // set the option properties
    106            option.setLongOpt(longOption);
    107            option.setRequired(required);
    108            option.setOptionalArg(optionalArg);
    109            option.setArgs(argCount);
    110            option.setType(type);
    111            option.setConverter(TypeHandler.getDefault().getConverter(type));
    112            option.setValueSeparator(valueSeparator);
    113            option.setArgName(argName);
    114        } finally {
    115            // reset the OptionBuilder properties
    116            reset();
    117        }
    118
    119        // return the Option instance
    120        return option;
    121    }
    122
    123    /**
    124     * The next Option created will require an argument value.
    125     *
    126     * @return the OptionBuilder instance
    127     */
    128    public static OptionBuilder hasArg() {
    129        argCount = 1;
    130        return INSTANCE;
    131    }
    132
    133    /**
    134     * The next Option created will require an argument value if {@code hasArg} is true.
    135     *
    136     * @param hasArg if true then the Option has an argument value
    137     * @return the OptionBuilder instance
    138     */
    139    public static OptionBuilder hasArg(final boolean hasArg) {
    140        argCount = hasArg ? 1 : Option.UNINITIALIZED;
    141        return INSTANCE;
    142    }
    143
    144    /**
    145     * The next Option created can have unlimited argument values.
    146     *
    147     * @return the OptionBuilder instance
    148     */
    149    public static OptionBuilder hasArgs() {
    150        argCount = Option.UNLIMITED_VALUES;
    151        return INSTANCE;
    152    }
    153
    154    /**
    155     * The next Option created can have {@code num} argument values.
    156     *
    157     * @param num the number of args that the option can have
    158     * @return the OptionBuilder instance
    159     */
    160    public static OptionBuilder hasArgs(final int num) {
    161        argCount = num;
    162        return INSTANCE;
    163    }
    164
    165    /**
    166     * The next Option can have an optional argument.
    167     *
    168     * @return the OptionBuilder instance
    169     */
    170    public static OptionBuilder hasOptionalArg() {
    171        argCount = 1;
    172        optionalArg = true;
    173        return INSTANCE;
    174    }
    175
    176    /**
    177     * The next Option can have an unlimited number of optional arguments.
    178     *
    179     * @return the OptionBuilder instance
    180     */
    181    public static OptionBuilder hasOptionalArgs() {
    182        argCount = Option.UNLIMITED_VALUES;
    183        optionalArg = true;
    184        return INSTANCE;
    185    }
    186
    187    /**
    188     * The next Option can have the specified number of optional arguments.
    189     *
    190     * @param numArgs   the maximum number of optional arguments the next Option created can have.
    191     * @return the OptionBuilder instance
    192     */
    193    public static OptionBuilder hasOptionalArgs(final int numArgs) {
    194        argCount = numArgs;
    195        optionalArg = true;
    196        return INSTANCE;
    197    }
    198
    199    /**
    200     * The next Option created will be required.
    201     *
    202     * @return the OptionBuilder instance
    203     */
    204    public static OptionBuilder isRequired() {
    205        required = true;
    206        return INSTANCE;
    207    }
    208
    209    /**
    210     * The next Option created will be required if {@code required} is true.
    211     *
    212     * @param newRequired if true then the Option is required
    213     * @return the OptionBuilder instance
    214     */
    215    public static OptionBuilder isRequired(final boolean newRequired) {
    216        required = newRequired;
    217        return INSTANCE;
    218    }
    219
    220    /**
    221     * Resets the member variables to their default values.
    222     */
    223    private static void reset() {
    224        description = null;
    225        argName = null;
    226        longOption = null;
    227        type = String.class;
    228        required = false;
    229        argCount = Option.UNINITIALIZED;
    230        optionalArg = false;
    231        valueSeparator = (char) 0;
    232    }
    233
    234    /**
    235     * The next Option created will have the specified argument value name.
    236     *
    237     * @param name the name for the argument value
    238     * @return the OptionBuilder instance
    239     */
    240    public static OptionBuilder withArgName(final String name) {
    241        argName = name;
    242        return INSTANCE;
    243    }
    244
    245    /**
    246     * The next Option created will have the specified description
    247     *
    248     * @param newDescription a description of the Option's purpose
    249     * @return the OptionBuilder instance
    250     */
    251    public static OptionBuilder withDescription(final String newDescription) {
    252        description = newDescription;
    253        return INSTANCE;
    254    }
    255
    256    /**
    257     * The next Option created will have the following long option value.
    258     *
    259     * @param newLongopt the long option value
    260     * @return the OptionBuilder instance
    261     */
    262    public static OptionBuilder withLongOpt(final String newLongopt) {
    263        longOption = newLongopt;
    264        return INSTANCE;
    265    }
    266
    267    /**
    268     * The next Option created will have a value that will be an instance of {@code type}.
    269     *
    270     * @param newType the type of the Options argument value
    271     * @return the OptionBuilder instance
    272     * @since 1.3
    273     */
    274    public static OptionBuilder withType(final Class<?> newType) {
    275        type = newType;
    276        return INSTANCE;
    277    }
    278
    279    /**
    280     * The next Option created will have a value that will be an instance of {@code type}.
    281     * <p>
    282     * <b>Note:</b> this method is kept for binary compatibility and the input type is supposed to be a {@link Class}
    283     * object.
    284     *
    285     * @param newType the type of the Options argument value
    286     * @return the OptionBuilder instance
    287     * @deprecated since 1.3, use {@link #withType(Class)} instead
    288     */
    289    @Deprecated
    290    public static OptionBuilder withType(final Object newType) {
    291        return withType((Class<?>) newType);
    292    }
    293
    294    /**
    295     * The next Option created uses '{@code =}' as a means to separate argument values.
    296     *
    297     * <b>Example:</b>
    298     *
    299     * <pre>
    300     * Option opt = withValueSeparator().create('D');
    301     *
    302     * CommandLine line = parser.parse(args);
    303     * String propertyName = opt.getValue(0);
    304     * String propertyValue = opt.getValue(1);
    305     * </pre>
    306     *
    307     * @return the OptionBuilder instance
    308     */
    309    public static OptionBuilder withValueSeparator() {
    310        valueSeparator = Char.EQUAL;
    311        return INSTANCE;
    312    }
    313
    314    /**
    315     * The next Option created uses {@code sep} as a means to separate argument values.
    316     * <p>
    317     * <b>Example:</b>
    318     *
    319     * <pre>
    320     * Option opt = OptionBuilder.withValueSeparator('=').create('D');
    321     *
    322     * String args = "-Dkey=value";
    323     * CommandLine line = parser.parse(args);
    324     * String propertyName = opt.getValue(0); // will be "key"
    325     * String propertyValue = opt.getValue(1); // will be "value"
    326     * </pre>
    327     *
    328     * @param sep The value separator to be used for the argument values.
    329     *
    330     * @return the OptionBuilder instance
    331     */
    332    public static OptionBuilder withValueSeparator(final char sep) {
    333        valueSeparator = sep;
    334        return INSTANCE;
    335    }
    336
    337    /**
    338     * private constructor to prevent instances being created
    339     */
    340    private OptionBuilder() {
    341        // hide the constructor
    342    }
    343}