    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
    035    /** Long option */
    036    private static String longOption;
    037
    038    /** Option description */
    039    private static String description;
    040
    041    /** Argument name */
    042    private static String argName;
    043
    044    /** Is required? */
    045    private static boolean required;
    046
    047    /** The number of arguments */
    048    private static int argCount = Option.UNINITIALIZED;
    049
    050    /** Option type */
    051    private static Class<?> type;
    052
    053    /** Option can have an optional argument value */
    054    private static boolean optionalArg;
    055
    056    /** Value separator for argument value */
    057    private static char valueSeparator;
    058
    059    /** Option builder instance */
    060    private static final OptionBuilder INSTANCE = new OptionBuilder();
    061
    062    static {
    063        // ensure the consistency of the initial values
    064        reset();
    065    }
    066
    067    /**
    068     * Creates an Option using the current settings
    069     *
    070     * @return the Option instance
    071     * @throws IllegalArgumentException if {@code longOpt} has not been set.
    072     */
    073    public static Option create() throws IllegalArgumentException {
    074        if (longOption == null) {
    075            OptionBuilder.reset();
    076            throw new IllegalArgumentException("must specify longopt");
    077        }
    078
    079        return create(null);
    080    }
    081
    082    /**
    083     * Creates an Option using the current settings and with the specified Option {@code char}.
    084     *
    085     * @param opt the character representation of the Option
    086     * @return the Option instance
    087     * @throws IllegalArgumentException if {@code opt} is not a valid character. See Option.
    088     */
    089    public static Option create(final char opt) throws IllegalArgumentException {
    090        return create(String.valueOf(opt));
    091    }
    092
    093    /**
    094     * Creates an Option using the current settings and with the specified Option {@code char}.
    095     *
    096     * @param opt the {@code String} representation of the Option
    097     * @return the Option instance
    098     * @throws IllegalArgumentException if {@code opt} is not a valid character. See Option.
    099     */
    100    public static Option create(final String opt) throws IllegalArgumentException {
    101        Option option;
    102        try {
    103            // create the option
    104            option = new Option(opt, description);
    105
    106            // set the option properties
    107            option.setLongOpt(longOption);
    108            option.setRequired(required);
    109            option.setOptionalArg(optionalArg);
    110            option.setArgs(argCount);
    111            option.setType(type);
    112            option.setConverter(TypeHandler.getDefault().getConverter(type));
    113            option.setValueSeparator(valueSeparator);
    114            option.setArgName(argName);
    115        } finally {
    116            // reset the OptionBuilder properties
    117            OptionBuilder.reset();
    118        }
    119
    120        // return the Option instance
    121        return option;
    122    }
    123
    124    /**
    125     * The next Option created will require an argument value.
    126     *
    127     * @return the OptionBuilder instance
    128     */
    129    public static OptionBuilder hasArg() {
    130        OptionBuilder.argCount = 1;
    131
    132        return INSTANCE;
    133    }
    134
    135    /**
    136     * The next Option created will require an argument value if {@code hasArg} is true.
    137     *
    138     * @param hasArg if true then the Option has an argument value
    139     * @return the OptionBuilder instance
    140     */
    141    public static OptionBuilder hasArg(final boolean hasArg) {
    142        OptionBuilder.argCount = hasArg ? 1 : Option.UNINITIALIZED;
    143
    144        return INSTANCE;
    145    }
    146
    147    /**
    148     * The next Option created can have unlimited argument values.
    149     *
    150     * @return the OptionBuilder instance
    151     */
    152    public static OptionBuilder hasArgs() {
    153        OptionBuilder.argCount = Option.UNLIMITED_VALUES;
    154
    155        return INSTANCE;
    156    }
    157
    158    /**
    159     * The next Option created can have {@code num} argument values.
    160     *
    161     * @param num the number of args that the option can have
    162     * @return the OptionBuilder instance
    163     */
    164    public static OptionBuilder hasArgs(final int num) {
    165        OptionBuilder.argCount = num;
    166
    167        return INSTANCE;
    168    }
    169
    170    /**
    171     * The next Option can have an optional argument.
    172     *
    173     * @return the OptionBuilder instance
    174     */
    175    public static OptionBuilder hasOptionalArg() {
    176        OptionBuilder.argCount = 1;
    177        OptionBuilder.optionalArg = true;
    178
    179        return INSTANCE;
    180    }
    181
    182    /**
    183     * The next Option can have an unlimited number of optional arguments.
    184     *
    185     * @return the OptionBuilder instance
    186     */
    187    public static OptionBuilder hasOptionalArgs() {
    188        OptionBuilder.argCount = Option.UNLIMITED_VALUES;
    189        OptionBuilder.optionalArg = true;
    190
    191        return INSTANCE;
    192    }
    193
    194    /**
    195     * The next Option can have the specified number of optional arguments.
    196     *
    197     * @param numArgs - the maximum number of optional arguments the next Option created can have.
    198     * @return the OptionBuilder instance
    199     */
    200    public static OptionBuilder hasOptionalArgs(final int numArgs) {
    201        OptionBuilder.argCount = numArgs;
    202        OptionBuilder.optionalArg = true;
    203
    204        return INSTANCE;
    205    }
    206
    207    /**
    208     * The next Option created will be required.
    209     *
    210     * @return the OptionBuilder instance
    211     */
    212    public static OptionBuilder isRequired() {
    213        OptionBuilder.required = true;
    214
    215        return INSTANCE;
    216    }
    217
    218    /**
    219     * The next Option created will be required if {@code required} is true.
    220     *
    221     * @param newRequired if true then the Option is required
    222     * @return the OptionBuilder instance
    223     */
    224    public static OptionBuilder isRequired(final boolean newRequired) {
    225        OptionBuilder.required = newRequired;
    226
    227        return INSTANCE;
    228    }
    229
    230    /**
    231     * Resets the member variables to their default values.
    232     */
    233    private static void reset() {
    234        description = null;
    235        argName = null;
    236        longOption = null;
    237        type = String.class;
    238        required = false;
    239        argCount = Option.UNINITIALIZED;
    240        optionalArg = false;
    241        valueSeparator = (char) 0;
    242    }
    243
    244    /**
    245     * The next Option created will have the specified argument value name.
    246     *
    247     * @param name the name for the argument value
    248     * @return the OptionBuilder instance
    249     */
    250    public static OptionBuilder withArgName(final String name) {
    251        OptionBuilder.argName = name;
    252
    253        return INSTANCE;
    254    }
    255
    256    /**
    257     * The next Option created will have the specified description
    258     *
    259     * @param newDescription a description of the Option's purpose
    260     * @return the OptionBuilder instance
    261     */
    262    public static OptionBuilder withDescription(final String newDescription) {
    263        OptionBuilder.description = newDescription;
    264
    265        return INSTANCE;
    266    }
    267
    268    /**
    269     * The next Option created will have the following long option value.
    270     *
    271     * @param newLongopt the long option value
    272     * @return the OptionBuilder instance
    273     */
    274    public static OptionBuilder withLongOpt(final String newLongopt) {
    275        OptionBuilder.longOption = newLongopt;
    276
    277        return INSTANCE;
    278    }
    279
    280    /**
    281     * The next Option created will have a value that will be an instance of {@code type}.
    282     *
    283     * @param newType the type of the Options argument value
    284     * @return the OptionBuilder instance
    285     * @since 1.3
    286     */
    287    public static OptionBuilder withType(final Class<?> newType) {
    288        OptionBuilder.type = newType;
    289
    290        return INSTANCE;
    291    }
    292
    293    /**
    294     * The next Option created will have a value that will be an instance of {@code type}.
    295     * <p>
    296     * <b>Note:</b> this method is kept for binary compatibility and the input type is supposed to be a {@link Class}
    297     * object.
    298     *
    299     * @param newType the type of the Options argument value
    300     * @return the OptionBuilder instance
    301     * @deprecated since 1.3, use {@link #withType(Class)} instead
    302     */
    303    @Deprecated
    304    public static OptionBuilder withType(final Object newType) {
    305        return withType((Class<?>) newType);
    306    }
    307
    308    /**
    309     * The next Option created uses '{@code =}' as a means to separate argument values.
    310     *
    311     * <b>Example:</b>
    312     *
    313     * <pre>
    314     * Option opt = OptionBuilder.withValueSeparator().create('D');
    315     *
    316     * CommandLine line = parser.parse(args);
    317     * String propertyName = opt.getValue(0);
    318     * String propertyValue = opt.getValue(1);
    319     * </pre>
    320     *
    321     * @return the OptionBuilder instance
    322     */
    323    public static OptionBuilder withValueSeparator() {
    324        OptionBuilder.valueSeparator = Char.EQUAL;
    325
    326        return INSTANCE;
    327    }
    328
    329    /**
    330     * The next Option created uses {@code sep} as a means to separate argument values.
    331     * <p>
    332     * <b>Example:</b>
    333     *
    334     * <pre>
    335     * Option opt = OptionBuilder.withValueSeparator('=').create('D');
    336     *
    337     * String args = "-Dkey=value";
    338     * CommandLine line = parser.parse(args);
    339     * String propertyName = opt.getValue(0); // will be "key"
    340     * String propertyValue = opt.getValue(1); // will be "value"
    341     * </pre>
    342     *
    343     * @param sep The value separator to be used for the argument values.
    344     *
    345     * @return the OptionBuilder instance
    346     */
    347    public static OptionBuilder withValueSeparator(final char sep) {
    348        OptionBuilder.valueSeparator = sep;
    349
    350        return INSTANCE;
    351    }
    352
    353    /**
    354     * private constructor to prevent instances being created
    355     */
    356    private OptionBuilder() {
    357        // hide the constructor
    358    }
    359}