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}