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