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
020import java.io.Serializable;
021import java.util.ArrayList;
022import java.util.List;
023
024/**
025 * Describes a single command-line option.  It maintains
026 * information regarding the short-name of the option, the long-name,
027 * if any exists, a flag indicating if an argument is required for
028 * this option, and a self-documenting description of the option.
029 * <p>
030 * An Option is not created independently, but is created through
031 * an instance of {@link Options}. An Option is required to have
032 * at least a short or a long-name.
033 * <p>
034 * <b>Note:</b> once an {@link Option} has been added to an instance
035 * of {@link Options}, it's required flag may not be changed anymore.
036 *
037 * @see org.apache.commons.cli.Options
038 * @see org.apache.commons.cli.CommandLine
039 *
040 * @version $Id: Option.java 1677406 2015-05-03 14:27:31Z britter $
041 */
042public class Option implements Cloneable, Serializable
043{
044    /** constant that specifies the number of argument values has not been specified */
045    public static final int UNINITIALIZED = -1;
046
047    /** constant that specifies the number of argument values is infinite */
048    public static final int UNLIMITED_VALUES = -2;
049
050    /** The serial version UID. */
051    private static final long serialVersionUID = 1L;
052
053    /** the name of the option */
054    private final String opt;
055
056    /** the long representation of the option */
057    private String longOpt;
058
059    /** the name of the argument for this option */
060    private String argName;
061
062    /** description of the option */
063    private String description;
064
065    /** specifies whether this option is required to be present */
066    private boolean required;
067
068    /** specifies whether the argument value of this Option is optional */
069    private boolean optionalArg;
070
071    /** the number of argument values this option can have */
072    private int numberOfArgs = UNINITIALIZED;
073
074    /** the type of this Option */
075    private Class<?> type = String.class;
076
077    /** the list of argument values **/
078    private List<String> values = new ArrayList<String>();
079
080    /** the character that is the value separator */
081    private char valuesep;
082
083    /**
084     * Private constructor used by the nested Builder class.
085     * 
086     * @param builder builder used to create this option
087     */
088    private Option(final Builder builder)
089    {
090        this.argName = builder.argName;
091        this.description = builder.description;
092        this.longOpt = builder.longOpt;
093        this.numberOfArgs = builder.numberOfArgs;
094        this.opt = builder.opt;
095        this.optionalArg = builder.optionalArg;
096        this.required = builder.required;
097        this.type = builder.type;
098        this.valuesep = builder.valuesep;
099    }
100    
101    /**
102     * Creates an Option using the specified parameters.
103     * The option does not take an argument.
104     *
105     * @param opt short representation of the option
106     * @param description describes the function of the option
107     *
108     * @throws IllegalArgumentException if there are any non valid
109     * Option characters in <code>opt</code>.
110     */
111    public Option(String opt, String description) throws IllegalArgumentException
112    {
113        this(opt, null, false, description);
114    }
115
116    /**
117     * Creates an Option using the specified parameters.
118     *
119     * @param opt short representation of the option
120     * @param hasArg specifies whether the Option takes an argument or not
121     * @param description describes the function of the option
122     *
123     * @throws IllegalArgumentException if there are any non valid
124     * Option characters in <code>opt</code>.
125     */
126    public Option(String opt, boolean hasArg, String description) throws IllegalArgumentException
127    {
128        this(opt, null, hasArg, description);
129    }
130
131    /**
132     * Creates an Option using the specified parameters.
133     *
134     * @param opt short representation of the option
135     * @param longOpt the long representation of the option
136     * @param hasArg specifies whether the Option takes an argument or not
137     * @param description describes the function of the option
138     *
139     * @throws IllegalArgumentException if there are any non valid
140     * Option characters in <code>opt</code>.
141     */
142    public Option(String opt, String longOpt, boolean hasArg, String description)
143           throws IllegalArgumentException
144    {
145        // ensure that the option is valid
146        OptionValidator.validateOption(opt);
147
148        this.opt = opt;
149        this.longOpt = longOpt;
150
151        // if hasArg is set then the number of arguments is 1
152        if (hasArg)
153        {
154            this.numberOfArgs = 1;
155        }
156
157        this.description = description;
158    }
159
160    /**
161     * Returns the id of this Option.  This is only set when the
162     * Option shortOpt is a single character.  This is used for switch
163     * statements.
164     *
165     * @return the id of this Option
166     */
167    public int getId()
168    {
169        return getKey().charAt(0);
170    }
171
172    /**
173     * Returns the 'unique' Option identifier.
174     * 
175     * @return the 'unique' Option identifier
176     */
177    String getKey()
178    {
179        // if 'opt' is null, then it is a 'long' option
180        return (opt == null) ? longOpt : opt;
181    }
182
183    /** 
184     * Retrieve the name of this Option.
185     *
186     * It is this String which can be used with
187     * {@link CommandLine#hasOption(String opt)} and
188     * {@link CommandLine#getOptionValue(String opt)} to check
189     * for existence and argument.
190     *
191     * @return The name of this option
192     */
193    public String getOpt()
194    {
195        return opt;
196    }
197
198    /**
199     * Retrieve the type of this Option.
200     * 
201     * @return The type of this option
202     */
203    public Object getType()
204    {
205        return type;
206    }
207
208    /**
209     * Sets the type of this Option.
210     * <p>
211     * <b>Note:</b> this method is kept for binary compatibility and the
212     * input type is supposed to be a {@link Class} object. 
213     *
214     * @param type the type of this Option
215     * @deprecated since 1.3, use {@link #setType(Class)} instead
216     */
217    @Deprecated
218    public void setType(Object type)
219    {
220        setType((Class<?>) type);
221    }
222
223    /**
224     * Sets the type of this Option.
225     *
226     * @param type the type of this Option
227     * @since 1.3
228     */
229    public void setType(Class<?> type)
230    {
231        this.type = type;
232    }
233
234    /** 
235     * Retrieve the long name of this Option.
236     *
237     * @return Long name of this option, or null, if there is no long name
238     */
239    public String getLongOpt()
240    {
241        return longOpt;
242    }
243
244    /**
245     * Sets the long name of this Option.
246     *
247     * @param longOpt the long name of this Option
248     */
249    public void setLongOpt(String longOpt)
250    {
251        this.longOpt = longOpt;
252    }
253
254    /**
255     * Sets whether this Option can have an optional argument.
256     *
257     * @param optionalArg specifies whether the Option can have
258     * an optional argument.
259     */
260    public void setOptionalArg(boolean optionalArg)
261    {
262        this.optionalArg = optionalArg;
263    }
264
265    /**
266     * @return whether this Option can have an optional argument
267     */
268    public boolean hasOptionalArg()
269    {
270        return optionalArg;
271    }
272
273    /** 
274     * Query to see if this Option has a long name
275     *
276     * @return boolean flag indicating existence of a long name
277     */
278    public boolean hasLongOpt()
279    {
280        return longOpt != null;
281    }
282
283    /** 
284     * Query to see if this Option requires an argument
285     *
286     * @return boolean flag indicating if an argument is required
287     */
288    public boolean hasArg()
289    {
290        return numberOfArgs > 0 || numberOfArgs == UNLIMITED_VALUES;
291    }
292
293    /** 
294     * Retrieve the self-documenting description of this Option
295     *
296     * @return The string description of this option
297     */
298    public String getDescription()
299    {
300        return description;
301    }
302
303    /**
304     * Sets the self-documenting description of this Option
305     *
306     * @param description The description of this option
307     * @since 1.1
308     */
309    public void setDescription(String description)
310    {
311        this.description = description;
312    }
313
314    /** 
315     * Query to see if this Option is mandatory
316     *
317     * @return boolean flag indicating whether this Option is mandatory
318     */
319    public boolean isRequired()
320    {
321        return required;
322    }
323
324    /**
325     * Sets whether this Option is mandatory.
326     *
327     * @param required specifies whether this Option is mandatory
328     */
329    public void setRequired(boolean required)
330    {
331        this.required = required;
332    }
333
334    /**
335     * Sets the display name for the argument value.
336     *
337     * @param argName the display name for the argument value.
338     */
339    public void setArgName(String argName)
340    {
341        this.argName = argName;
342    }
343
344    /**
345     * Gets the display name for the argument value.
346     *
347     * @return the display name for the argument value.
348     */
349    public String getArgName()
350    {
351        return argName;
352    }
353
354    /**
355     * Returns whether the display name for the argument value has been set.
356     *
357     * @return if the display name for the argument value has been set.
358     */
359    public boolean hasArgName()
360    {
361        return argName != null && argName.length() > 0;
362    }
363
364    /** 
365     * Query to see if this Option can take many values.
366     *
367     * @return boolean flag indicating if multiple values are allowed
368     */
369    public boolean hasArgs()
370    {
371        return numberOfArgs > 1 || numberOfArgs == UNLIMITED_VALUES;
372    }
373
374    /** 
375     * Sets the number of argument values this Option can take.
376     *
377     * @param num the number of argument values
378     */
379    public void setArgs(int num)
380    {
381        this.numberOfArgs = num;
382    }
383
384    /**
385     * Sets the value separator.  For example if the argument value
386     * was a Java property, the value separator would be '='.
387     *
388     * @param sep The value separator.
389     */
390    public void setValueSeparator(char sep)
391    {
392        this.valuesep = sep;
393    }
394
395    /**
396     * Returns the value separator character.
397     *
398     * @return the value separator character.
399     */
400    public char getValueSeparator()
401    {
402        return valuesep;
403    }
404
405    /**
406     * Return whether this Option has specified a value separator.
407     * 
408     * @return whether this Option has specified a value separator.
409     * @since 1.1
410     */
411    public boolean hasValueSeparator()
412    {
413        return valuesep > 0;
414    }
415
416    /** 
417     * Returns the number of argument values this Option can take.
418     *
419     * @return num the number of argument values
420     */
421    public int getArgs()
422    {
423        return numberOfArgs;
424    }
425
426    /**
427     * Adds the specified value to this Option.
428     * 
429     * @param value is a/the value of this Option
430     */
431    void addValueForProcessing(String value)
432    {
433        if (numberOfArgs == UNINITIALIZED)
434        {
435            throw new RuntimeException("NO_ARGS_ALLOWED");
436        }
437        processValue(value);
438    }
439
440    /**
441     * Processes the value.  If this Option has a value separator
442     * the value will have to be parsed into individual tokens.  When
443     * n-1 tokens have been processed and there are more value separators
444     * in the value, parsing is ceased and the remaining characters are
445     * added as a single token.
446     *
447     * @param value The String to be processed.
448     *
449     * @since 1.0.1
450     */
451    private void processValue(String value)
452    {
453        // this Option has a separator character
454        if (hasValueSeparator())
455        {
456            // get the separator character
457            char sep = getValueSeparator();
458
459            // store the index for the value separator
460            int index = value.indexOf(sep);
461
462            // while there are more value separators
463            while (index != -1)
464            {
465                // next value to be added 
466                if (values.size() == numberOfArgs - 1)
467                {
468                    break;
469                }
470
471                // store
472                add(value.substring(0, index));
473
474                // parse
475                value = value.substring(index + 1);
476
477                // get new index
478                index = value.indexOf(sep);
479            }
480        }
481
482        // store the actual value or the last value that has been parsed
483        add(value);
484    }
485
486    /**
487     * Add the value to this Option.  If the number of arguments
488     * is greater than zero and there is enough space in the list then
489     * add the value.  Otherwise, throw a runtime exception.
490     *
491     * @param value The value to be added to this Option
492     *
493     * @since 1.0.1
494     */
495    private void add(String value)
496    {
497        if (!acceptsArg())
498        {
499            throw new RuntimeException("Cannot add value, list full.");
500        }
501
502        // store value
503        values.add(value);
504    }
505
506    /**
507     * Returns the specified value of this Option or 
508     * <code>null</code> if there is no value.
509     *
510     * @return the value/first value of this Option or 
511     * <code>null</code> if there is no value.
512     */
513    public String getValue()
514    {
515        return hasNoValues() ? null : values.get(0);
516    }
517
518    /**
519     * Returns the specified value of this Option or 
520     * <code>null</code> if there is no value.
521     *
522     * @param index The index of the value to be returned.
523     *
524     * @return the specified value of this Option or 
525     * <code>null</code> if there is no value.
526     *
527     * @throws IndexOutOfBoundsException if index is less than 1
528     * or greater than the number of the values for this Option.
529     */
530    public String getValue(int index) throws IndexOutOfBoundsException
531    {
532        return hasNoValues() ? null : values.get(index);
533    }
534
535    /**
536     * Returns the value/first value of this Option or the 
537     * <code>defaultValue</code> if there is no value.
538     *
539     * @param defaultValue The value to be returned if there
540     * is no value.
541     *
542     * @return the value/first value of this Option or the 
543     * <code>defaultValue</code> if there are no values.
544     */
545    public String getValue(String defaultValue)
546    {
547        String value = getValue();
548
549        return (value != null) ? value : defaultValue;
550    }
551
552    /**
553     * Return the values of this Option as a String array 
554     * or null if there are no values
555     *
556     * @return the values of this Option as a String array 
557     * or null if there are no values
558     */
559    public String[] getValues()
560    {
561        return hasNoValues() ? null : values.toArray(new String[values.size()]);
562    }
563
564    /**
565     * @return the values of this Option as a List
566     * or null if there are no values
567     */
568    public List<String> getValuesList()
569    {
570        return values;
571    }
572
573    /** 
574     * Dump state, suitable for debugging.
575     *
576     * @return Stringified form of this object
577     */
578    @Override
579    public String toString()
580    {
581        StringBuilder buf = new StringBuilder().append("[ option: ");
582
583        buf.append(opt);
584
585        if (longOpt != null)
586        {
587            buf.append(" ").append(longOpt);
588        }
589
590        buf.append(" ");
591
592        if (hasArgs())
593        {
594            buf.append("[ARG...]");
595        }
596        else if (hasArg())
597        {
598            buf.append(" [ARG]");
599        }
600
601        buf.append(" :: ").append(description);
602
603        if (type != null)
604        {
605            buf.append(" :: ").append(type);
606        }
607
608        buf.append(" ]");
609
610        return buf.toString();
611    }
612
613    /**
614     * Returns whether this Option has any values.
615     *
616     * @return whether this Option has any values.
617     */
618    private boolean hasNoValues()
619    {
620        return values.isEmpty();
621    }
622
623    @Override
624    public boolean equals(Object o)
625    {
626        if (this == o)
627        {
628            return true;
629        }
630        if (o == null || getClass() != o.getClass())
631        {
632            return false;
633        }
634
635        Option option = (Option) o;
636
637
638        if (opt != null ? !opt.equals(option.opt) : option.opt != null)
639        {
640            return false;
641        }
642        if (longOpt != null ? !longOpt.equals(option.longOpt) : option.longOpt != null)
643        {
644            return false;
645        }
646
647        return true;
648    }
649
650    @Override
651    public int hashCode()
652    {
653        int result;
654        result = opt != null ? opt.hashCode() : 0;
655        result = 31 * result + (longOpt != null ? longOpt.hashCode() : 0);
656        return result;
657    }
658
659    /**
660     * A rather odd clone method - due to incorrect code in 1.0 it is public 
661     * and in 1.1 rather than throwing a CloneNotSupportedException it throws 
662     * a RuntimeException so as to maintain backwards compat at the API level. 
663     *
664     * After calling this method, it is very likely you will want to call 
665     * clearValues(). 
666     *
667     * @return a clone of this Option instance
668     * @throws RuntimeException if a {@link CloneNotSupportedException} has been thrown
669     * by {@code super.clone()}
670     */
671    @Override
672    public Object clone()
673    {
674        try
675        {
676            Option option = (Option) super.clone();
677            option.values = new ArrayList<String>(values);
678            return option;
679        }
680        catch (CloneNotSupportedException cnse)
681        {
682            throw new RuntimeException("A CloneNotSupportedException was thrown: " + cnse.getMessage());
683        }
684    }
685
686    /**
687     * Clear the Option values. After a parse is complete, these are left with
688     * data in them and they need clearing if another parse is done.
689     *
690     * See: <a href="https://issues.apache.org/jira/browse/CLI-71">CLI-71</a>
691     */
692    void clearValues()
693    {
694        values.clear();
695    }
696
697    /**
698     * This method is not intended to be used. It was a piece of internal 
699     * API that was made public in 1.0. It currently throws an UnsupportedOperationException.
700     *
701     * @param value the value to add
702     * @return always throws an {@link UnsupportedOperationException}
703     * @throws UnsupportedOperationException always
704     * @deprecated
705     */
706    @Deprecated
707    public boolean addValue(String value)
708    {
709        throw new UnsupportedOperationException("The addValue method is not intended for client use. "
710                + "Subclasses should use the addValueForProcessing method instead. ");
711    }
712
713    /**
714     * Tells if the option can accept more arguments.
715     * 
716     * @return false if the maximum number of arguments is reached
717     * @since 1.3
718     */
719    boolean acceptsArg()
720    {
721        return (hasArg() || hasArgs() || hasOptionalArg()) && (numberOfArgs <= 0 || values.size() < numberOfArgs);
722    }
723
724    /**
725     * Tells if the option requires more arguments to be valid.
726     * 
727     * @return false if the option doesn't require more arguments
728     * @since 1.3
729     */
730    boolean requiresArg()
731    {
732        if (optionalArg)
733        {
734            return false;
735        }
736        if (numberOfArgs == UNLIMITED_VALUES)
737        {
738            return values.isEmpty();
739        }
740        return acceptsArg();
741    }
742    
743    /**
744     * Returns a {@link Builder} to create an {@link Option} using descriptive
745     * methods.  
746     * 
747     * @return a new {@link Builder} instance
748     * @since 1.3
749     */
750    public static Builder builder()
751    {
752        return builder(null);
753    }
754    
755    /**
756     * Returns a {@link Builder} to create an {@link Option} using descriptive
757     * methods.  
758     *
759     * @param opt short representation of the option
760     * @return a new {@link Builder} instance
761     * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}
762     * @since 1.3
763     */
764    public static Builder builder(final String opt)
765    {
766        return new Builder(opt);
767    }
768    
769    /**
770     * A nested builder class to create <code>Option</code> instances
771     * using descriptive methods.
772     * <p>
773     * Example usage:
774     * <pre>
775     * Option option = Option.builder("a")
776     *     .required(true)
777     *     .longOpt("arg-name")
778     *     .build();
779     * </pre>
780     * 
781     * @since 1.3
782     */
783    public static final class Builder 
784    {
785        /** the name of the option */
786        private final String opt;
787
788        /** description of the option */
789        private String description;
790
791        /** the long representation of the option */
792        private String longOpt;
793
794        /** the name of the argument for this option */
795        private String argName;
796
797        /** specifies whether this option is required to be present */
798        private boolean required;
799
800        /** specifies whether the argument value of this Option is optional */
801        private boolean optionalArg;
802
803        /** the number of argument values this option can have */
804        private int numberOfArgs = UNINITIALIZED;
805
806        /** the type of this Option */
807        private Class<?> type = String.class;
808
809        /** the character that is the value separator */
810        private char valuesep;
811
812        /**
813         * Constructs a new <code>Builder</code> with the minimum
814         * required parameters for an <code>Option</code> instance.
815         * 
816         * @param opt short representation of the option
817         * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}
818         */
819        private Builder(final String opt) throws IllegalArgumentException
820        {
821            OptionValidator.validateOption(opt);
822            this.opt = opt;
823        }
824        
825        /**
826         * Sets the display name for the argument value.
827         *
828         * @param argName the display name for the argument value.
829         * @return this builder, to allow method chaining
830         */
831        public Builder argName(final String argName)
832        {
833            this.argName = argName;
834            return this;
835        }
836
837        /**
838         * Sets the description for this option.
839         *
840         * @param description the description of the option.
841         * @return this builder, to allow method chaining
842         */
843        public Builder desc(final String description)
844        {
845            this.description = description;
846            return this;
847        }
848
849        /**
850         * Sets the long name of the Option.
851         *
852         * @param longOpt the long name of the Option
853         * @return this builder, to allow method chaining
854         */        
855        public Builder longOpt(final String longOpt)
856        {
857            this.longOpt = longOpt;
858            return this;
859        }
860        
861        /** 
862         * Sets the number of argument values the Option can take.
863         *
864         * @param numberOfArgs the number of argument values
865         * @return this builder, to allow method chaining
866         */        
867        public Builder numberOfArgs(final int numberOfArgs)
868        {
869            this.numberOfArgs = numberOfArgs;
870            return this;
871        }
872        
873        /**
874         * Sets whether the Option can have an optional argument.
875         *
876         * @param isOptional specifies whether the Option can have
877         * an optional argument.
878         * @return this builder, to allow method chaining
879         */
880        public Builder optionalArg(final boolean isOptional)
881        {
882            this.optionalArg = isOptional;
883            return this;
884        }
885        
886        /**
887         * Marks this Option as required.
888         *
889         * @return this builder, to allow method chaining
890         */
891        public Builder required()
892        {
893            return required(true);
894        }
895
896        /**
897         * Sets whether the Option is mandatory.
898         *
899         * @param required specifies whether the Option is mandatory
900         * @return this builder, to allow method chaining
901         */
902        public Builder required(final boolean required)
903        {
904            this.required = required;
905            return this;
906        }
907        
908        /**
909         * Sets the type of the Option.
910         *
911         * @param type the type of the Option
912         * @return this builder, to allow method chaining
913         */
914        public Builder type(final Class<?> type)
915        {
916            this.type = type;
917            return this;
918        }
919
920        /**
921         * The Option will use '=' as a means to separate argument value.
922         *
923         * @return this builder, to allow method chaining
924         */
925        public Builder valueSeparator()
926        {
927            return valueSeparator('=');
928        }
929
930        /**
931         * The Option will use <code>sep</code> as a means to
932         * separate argument values.
933         * <p>
934         * <b>Example:</b>
935         * <pre>
936         * Option opt = Option.builder("D").hasArgs()
937         *                                 .valueSeparator('=')
938         *                                 .build();
939         * Options options = new Options();
940         * options.addOption(opt);
941         * String[] args = {"-Dkey=value"};
942         * CommandLineParser parser = new DefaultParser();
943         * CommandLine line = parser.parse(options, args);
944         * String propertyName = line.getOptionValues("D")[0];  // will be "key"
945         * String propertyValue = line.getOptionValues("D")[1]; // will be "value"
946         * </pre>
947         *
948         * @param sep The value separator.
949         * @return this builder, to allow method chaining
950         */
951        public Builder valueSeparator(final char sep)
952        {
953            valuesep = sep;
954            return this;
955        }
956        
957        /**
958         * Indicates that the Option will require an argument.
959         * 
960         * @return this builder, to allow method chaining
961         */
962        public Builder hasArg()
963        {
964            return hasArg(true);
965        }
966
967        /**
968         * Indicates if the Option has an argument or not.
969         * 
970         * @param hasArg specifies whether the Option takes an argument or not
971         * @return this builder, to allow method chaining
972         */
973        public Builder hasArg(final boolean hasArg)
974        {
975            // set to UNINITIALIZED when no arg is specified to be compatible with OptionBuilder
976            numberOfArgs = hasArg ? 1 : Option.UNINITIALIZED;
977            return this;
978        }
979
980        /**
981         * Indicates that the Option can have unlimited argument values.
982         * 
983         * @return this builder, to allow method chaining
984         */
985        public Builder hasArgs()
986        {
987            numberOfArgs = Option.UNLIMITED_VALUES;
988            return this;
989        }
990
991        /**
992         * Constructs an Option with the values declared by this {@link Builder}.
993         * 
994         * @return the new {@link Option}
995         * @throws IllegalArgumentException if neither {@code opt} or {@code longOpt} has been set
996         */
997        public Option build()
998        {
999            if (opt == null && longOpt == null)
1000            {
1001                throw new IllegalArgumentException("Either opt or longOpt must be specified");
1002            }
1003            return new Option(this);
1004        }
1005    }
1006}