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="http://c2.com/cgi-bin/wiki?BuilderPattern">http://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            OptionBuilder.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 java.lang.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.setValueSeparator(valueSeparator);
112            option.setArgName(argName);
113        } finally {
114            // reset the OptionBuilder properties
115            OptionBuilder.reset();
116        }
117
118        // return the Option instance
119        return option;
120    }
121
122    /**
123     * The next Option created will require an argument value.
124     *
125     * @return the OptionBuilder instance
126     */
127    public static OptionBuilder hasArg() {
128        OptionBuilder.argCount = 1;
129
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        OptionBuilder.argCount = hasArg ? 1 : Option.UNINITIALIZED;
141
142        return INSTANCE;
143    }
144
145    /**
146     * The next Option created can have unlimited argument values.
147     *
148     * @return the OptionBuilder instance
149     */
150    public static OptionBuilder hasArgs() {
151        OptionBuilder.argCount = Option.UNLIMITED_VALUES;
152
153        return INSTANCE;
154    }
155
156    /**
157     * The next Option created can have {@code num} argument values.
158     *
159     * @param num the number of args that the option can have
160     * @return the OptionBuilder instance
161     */
162    public static OptionBuilder hasArgs(final int num) {
163        OptionBuilder.argCount = num;
164
165        return INSTANCE;
166    }
167
168    /**
169     * The next Option can have an optional argument.
170     *
171     * @return the OptionBuilder instance
172     */
173    public static OptionBuilder hasOptionalArg() {
174        OptionBuilder.argCount = 1;
175        OptionBuilder.optionalArg = true;
176
177        return INSTANCE;
178    }
179
180    /**
181     * The next Option can have an unlimited number of optional arguments.
182     *
183     * @return the OptionBuilder instance
184     */
185    public static OptionBuilder hasOptionalArgs() {
186        OptionBuilder.argCount = Option.UNLIMITED_VALUES;
187        OptionBuilder.optionalArg = true;
188
189        return INSTANCE;
190    }
191
192    /**
193     * The next Option can have the specified number of optional arguments.
194     *
195     * @param numArgs - the maximum number of optional arguments the next Option created can have.
196     * @return the OptionBuilder instance
197     */
198    public static OptionBuilder hasOptionalArgs(final int numArgs) {
199        OptionBuilder.argCount = numArgs;
200        OptionBuilder.optionalArg = true;
201
202        return INSTANCE;
203    }
204
205    /**
206     * The next Option created will be required.
207     *
208     * @return the OptionBuilder instance
209     */
210    public static OptionBuilder isRequired() {
211        OptionBuilder.required = true;
212
213        return INSTANCE;
214    }
215
216    /**
217     * The next Option created will be required if {@code required} is true.
218     *
219     * @param newRequired if true then the Option is required
220     * @return the OptionBuilder instance
221     */
222    public static OptionBuilder isRequired(final boolean newRequired) {
223        OptionBuilder.required = newRequired;
224
225        return INSTANCE;
226    }
227
228    /**
229     * Resets the member variables to their default values.
230     */
231    private static void reset() {
232        description = null;
233        argName = null;
234        longOption = null;
235        type = String.class;
236        required = false;
237        argCount = Option.UNINITIALIZED;
238        optionalArg = false;
239        valueSeparator = (char) 0;
240    }
241
242    /**
243     * The next Option created will have the specified argument value name.
244     *
245     * @param name the name for the argument value
246     * @return the OptionBuilder instance
247     */
248    public static OptionBuilder withArgName(final String name) {
249        OptionBuilder.argName = name;
250
251        return INSTANCE;
252    }
253
254    /**
255     * The next Option created will have the specified description
256     *
257     * @param newDescription a description of the Option's purpose
258     * @return the OptionBuilder instance
259     */
260    public static OptionBuilder withDescription(final String newDescription) {
261        OptionBuilder.description = newDescription;
262
263        return INSTANCE;
264    }
265
266    /**
267     * The next Option created will have the following long option value.
268     *
269     * @param newLongopt the long option value
270     * @return the OptionBuilder instance
271     */
272    public static OptionBuilder withLongOpt(final String newLongopt) {
273        OptionBuilder.longOption = newLongopt;
274
275        return INSTANCE;
276    }
277
278    /**
279     * The next Option created will have a value that will be an instance of {@code type}.
280     *
281     * @param newType the type of the Options argument value
282     * @return the OptionBuilder instance
283     * @since 1.3
284     */
285    public static OptionBuilder withType(final Class<?> newType) {
286        OptionBuilder.type = newType;
287
288        return INSTANCE;
289    }
290
291    /**
292     * The next Option created will have a value that will be an instance of {@code type}.
293     * <p>
294     * <b>Note:</b> this method is kept for binary compatibility and the input type is supposed to be a {@link Class}
295     * object.
296     *
297     * @param newType the type of the Options argument value
298     * @return the OptionBuilder instance
299     * @deprecated since 1.3, use {@link #withType(Class)} instead
300     */
301    @Deprecated
302    public static OptionBuilder withType(final Object newType) {
303        return withType((Class<?>) newType);
304    }
305
306    /**
307     * The next Option created uses '{@code =}' as a means to separate argument values.
308     *
309     * <b>Example:</b>
310     *
311     * <pre>
312     * Option opt = OptionBuilder.withValueSeparator().create('D');
313     *
314     * CommandLine line = parser.parse(args);
315     * String propertyName = opt.getValue(0);
316     * String propertyValue = opt.getValue(1);
317     * </pre>
318     *
319     * @return the OptionBuilder instance
320     */
321    public static OptionBuilder withValueSeparator() {
322        OptionBuilder.valueSeparator = '=';
323
324        return INSTANCE;
325    }
326
327    /**
328     * The next Option created uses {@code sep} as a means to separate argument values.
329     * <p>
330     * <b>Example:</b>
331     *
332     * <pre>
333     * Option opt = OptionBuilder.withValueSeparator('=').create('D');
334     *
335     * String args = "-Dkey=value";
336     * CommandLine line = parser.parse(args);
337     * String propertyName = opt.getValue(0); // will be "key"
338     * String propertyValue = opt.getValue(1); // will be "value"
339     * </pre>
340     *
341     * @param sep The value separator to be used for the argument values.
342     *
343     * @return the OptionBuilder instance
344     */
345    public static OptionBuilder withValueSeparator(final char sep) {
346        OptionBuilder.valueSeparator = sep;
347
348        return INSTANCE;
349    }
350
351    /**
352     * private constructor to prevent instances being created
353     */
354    private OptionBuilder() {
355        // hide the constructor
356    }
357}