1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.cli;
19
20 import java.io.Serializable;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 /**
25 * Describes a single command-line option. It maintains
26 * information regarding the short-name of the option, the long-name,
27 * if any exists, a flag indicating if an argument is required for
28 * this option, and a self-documenting description of the option.
29 * <p>
30 * An Option is not created independently, but is created through
31 * an instance of {@link Options}. An Option is required to have
32 * at least a short or a long-name.
33 * <p>
34 * <b>Note:</b> once an {@link Option} has been added to an instance
35 * of {@link Options}, it's required flag may not be changed anymore.
36 *
37 * @see org.apache.commons.cli.Options
38 * @see org.apache.commons.cli.CommandLine
39 *
40 * @version $Id: Option.java 1447094 2013-02-17 22:32:21Z tn $
41 */
42 public class Option implements Cloneable, Serializable
43 {
44 /** constant that specifies the number of argument values has not been specified */
45 public static final int UNINITIALIZED = -1;
46
47 /** constant that specifies the number of argument values is infinite */
48 public static final int UNLIMITED_VALUES = -2;
49
50 /** The serial version UID. */
51 private static final long serialVersionUID = 1L;
52
53 /** the name of the option */
54 private String opt;
55
56 /** the long representation of the option */
57 private String longOpt;
58
59 /** the name of the argument for this option */
60 private String argName;
61
62 /** description of the option */
63 private String description;
64
65 /** specifies whether this option is required to be present */
66 private boolean required;
67
68 /** specifies whether the argument value of this Option is optional */
69 private boolean optionalArg;
70
71 /** the number of argument values this option can have */
72 private int numberOfArgs = UNINITIALIZED;
73
74 /** the type of this Option */
75 private Class<?> type = String.class;
76
77 /** the list of argument values **/
78 private List<String> values = new ArrayList<String>();
79
80 /** the character that is the value separator */
81 private char valuesep;
82
83 /**
84 * Private constructor used by the nested Builder class.
85 *
86 * @param builder builder used to create this option
87 */
88 private Option(final Builder builder)
89 {
90 this.argName = builder.argName;
91 this.description = builder.description;
92 this.longOpt = builder.longOpt;
93 this.numberOfArgs = builder.numberOfArgs;
94 this.opt = builder.opt;
95 this.optionalArg = builder.optionalArg;
96 this.required = builder.required;
97 this.type = builder.type;
98 this.valuesep = builder.valuesep;
99 }
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 if (opt == null)
181 {
182 return longOpt;
183 }
184
185 return opt;
186 }
187
188 /**
189 * Retrieve the name of this Option.
190 *
191 * It is this String which can be used with
192 * {@link CommandLine#hasOption(String opt)} and
193 * {@link CommandLine#getOptionValue(String opt)} to check
194 * for existence and argument.
195 *
196 * @return The name of this option
197 */
198 public String getOpt()
199 {
200 return opt;
201 }
202
203 /**
204 * Retrieve the type of this Option.
205 *
206 * @return The type of this option
207 */
208 public Object getType()
209 {
210 return type;
211 }
212
213 /**
214 * Sets the type of this Option.
215 * <p>
216 * <b>Note:</b> this method is kept for binary compatibility and the
217 * input type is supposed to be a {@link Class} object.
218 *
219 * @param type the type of this Option
220 * @deprecated since 1.3, use {@link #setType(Class)} instead
221 */
222 @Deprecated
223 public void setType(Object type)
224 {
225 setType((Class<?>) type);
226 }
227
228 /**
229 * Sets the type of this Option.
230 *
231 * @param type the type of this Option
232 * @since 1.3
233 */
234 public void setType(Class<?> type)
235 {
236 this.type = type;
237 }
238
239 /**
240 * Retrieve the long name of this Option.
241 *
242 * @return Long name of this option, or null, if there is no long name
243 */
244 public String getLongOpt()
245 {
246 return longOpt;
247 }
248
249 /**
250 * Sets the long name of this Option.
251 *
252 * @param longOpt the long name of this Option
253 */
254 public void setLongOpt(String longOpt)
255 {
256 this.longOpt = longOpt;
257 }
258
259 /**
260 * Sets whether this Option can have an optional argument.
261 *
262 * @param optionalArg specifies whether the Option can have
263 * an optional argument.
264 */
265 public void setOptionalArg(boolean optionalArg)
266 {
267 this.optionalArg = optionalArg;
268 }
269
270 /**
271 * @return whether this Option can have an optional argument
272 */
273 public boolean hasOptionalArg()
274 {
275 return optionalArg;
276 }
277
278 /**
279 * Query to see if this Option has a long name
280 *
281 * @return boolean flag indicating existence of a long name
282 */
283 public boolean hasLongOpt()
284 {
285 return longOpt != null;
286 }
287
288 /**
289 * Query to see if this Option requires an argument
290 *
291 * @return boolean flag indicating if an argument is required
292 */
293 public boolean hasArg()
294 {
295 return numberOfArgs > 0 || numberOfArgs == UNLIMITED_VALUES;
296 }
297
298 /**
299 * Retrieve the self-documenting description of this Option
300 *
301 * @return The string description of this option
302 */
303 public String getDescription()
304 {
305 return description;
306 }
307
308 /**
309 * Sets the self-documenting description of this Option
310 *
311 * @param description The description of this option
312 * @since 1.1
313 */
314 public void setDescription(String description)
315 {
316 this.description = description;
317 }
318
319 /**
320 * Query to see if this Option is mandatory
321 *
322 * @return boolean flag indicating whether this Option is mandatory
323 */
324 public boolean isRequired()
325 {
326 return required;
327 }
328
329 /**
330 * Sets whether this Option is mandatory.
331 *
332 * @param required specifies whether this Option is mandatory
333 */
334 public void setRequired(boolean required)
335 {
336 this.required = required;
337 }
338
339 /**
340 * Sets the display name for the argument value.
341 *
342 * @param argName the display name for the argument value.
343 */
344 public void setArgName(String argName)
345 {
346 this.argName = argName;
347 }
348
349 /**
350 * Gets the display name for the argument value.
351 *
352 * @return the display name for the argument value.
353 */
354 public String getArgName()
355 {
356 return argName;
357 }
358
359 /**
360 * Returns whether the display name for the argument value has been set.
361 *
362 * @return if the display name for the argument value has been set.
363 */
364 public boolean hasArgName()
365 {
366 return argName != null && argName.length() > 0;
367 }
368
369 /**
370 * Query to see if this Option can take many values.
371 *
372 * @return boolean flag indicating if multiple values are allowed
373 */
374 public boolean hasArgs()
375 {
376 return numberOfArgs > 1 || numberOfArgs == UNLIMITED_VALUES;
377 }
378
379 /**
380 * Sets the number of argument values this Option can take.
381 *
382 * @param num the number of argument values
383 */
384 public void setArgs(int num)
385 {
386 this.numberOfArgs = num;
387 }
388
389 /**
390 * Sets the value separator. For example if the argument value
391 * was a Java property, the value separator would be '='.
392 *
393 * @param sep The value separator.
394 */
395 public void setValueSeparator(char sep)
396 {
397 this.valuesep = sep;
398 }
399
400 /**
401 * Returns the value separator character.
402 *
403 * @return the value separator character.
404 */
405 public char getValueSeparator()
406 {
407 return valuesep;
408 }
409
410 /**
411 * Return whether this Option has specified a value separator.
412 *
413 * @return whether this Option has specified a value separator.
414 * @since 1.1
415 */
416 public boolean hasValueSeparator()
417 {
418 return valuesep > 0;
419 }
420
421 /**
422 * Returns the number of argument values this Option can take.
423 *
424 * @return num the number of argument values
425 */
426 public int getArgs()
427 {
428 return numberOfArgs;
429 }
430
431 /**
432 * Adds the specified value to this Option.
433 *
434 * @param value is a/the value of this Option
435 */
436 void addValueForProcessing(String value)
437 {
438 switch (numberOfArgs)
439 {
440 case UNINITIALIZED:
441 throw new RuntimeException("NO_ARGS_ALLOWED");
442
443 default:
444 processValue(value);
445 }
446 }
447
448 /**
449 * Processes the value. If this Option has a value separator
450 * the value will have to be parsed into individual tokens. When
451 * n-1 tokens have been processed and there are more value separators
452 * in the value, parsing is ceased and the remaining characters are
453 * added as a single token.
454 *
455 * @param value The String to be processed.
456 *
457 * @since 1.0.1
458 */
459 private void processValue(String value)
460 {
461 // this Option has a separator character
462 if (hasValueSeparator())
463 {
464 // get the separator character
465 char sep = getValueSeparator();
466
467 // store the index for the value separator
468 int index = value.indexOf(sep);
469
470 // while there are more value separators
471 while (index != -1)
472 {
473 // next value to be added
474 if (values.size() == (numberOfArgs - 1))
475 {
476 break;
477 }
478
479 // store
480 add(value.substring(0, index));
481
482 // parse
483 value = value.substring(index + 1);
484
485 // get new index
486 index = value.indexOf(sep);
487 }
488 }
489
490 // store the actual value or the last value that has been parsed
491 add(value);
492 }
493
494 /**
495 * Add the value to this Option. If the number of arguments
496 * is greater than zero and there is enough space in the list then
497 * add the value. Otherwise, throw a runtime exception.
498 *
499 * @param value The value to be added to this Option
500 *
501 * @since 1.0.1
502 */
503 private void add(String value)
504 {
505 if (!acceptsArg())
506 {
507 throw new RuntimeException("Cannot add value, list full.");
508 }
509
510 // store value
511 values.add(value);
512 }
513
514 /**
515 * Returns the specified value of this Option or
516 * <code>null</code> if there is no value.
517 *
518 * @return the value/first value of this Option or
519 * <code>null</code> if there is no value.
520 */
521 public String getValue()
522 {
523 return hasNoValues() ? null : values.get(0);
524 }
525
526 /**
527 * Returns the specified value of this Option or
528 * <code>null</code> if there is no value.
529 *
530 * @param index The index of the value to be returned.
531 *
532 * @return the specified value of this Option or
533 * <code>null</code> if there is no value.
534 *
535 * @throws IndexOutOfBoundsException if index is less than 1
536 * or greater than the number of the values for this Option.
537 */
538 public String getValue(int index) throws IndexOutOfBoundsException
539 {
540 return hasNoValues() ? null : values.get(index);
541 }
542
543 /**
544 * Returns the value/first value of this Option or the
545 * <code>defaultValue</code> if there is no value.
546 *
547 * @param defaultValue The value to be returned if ther
548 * is no value.
549 *
550 * @return the value/first value of this Option or the
551 * <code>defaultValue</code> if there are no values.
552 */
553 public String getValue(String defaultValue)
554 {
555 String value = getValue();
556
557 return (value != null) ? value : defaultValue;
558 }
559
560 /**
561 * Return the values of this Option as a String array
562 * or null if there are no values
563 *
564 * @return the values of this Option as a String array
565 * or null if there are no values
566 */
567 public String[] getValues()
568 {
569 return hasNoValues() ? null : values.toArray(new String[values.size()]);
570 }
571
572 /**
573 * @return the values of this Option as a List
574 * or null if there are no values
575 */
576 public List<String> getValuesList()
577 {
578 return values;
579 }
580
581 /**
582 * Dump state, suitable for debugging.
583 *
584 * @return Stringified form of this object
585 */
586 @Override
587 public String toString()
588 {
589 StringBuilder buf = new StringBuilder().append("[ option: ");
590
591 buf.append(opt);
592
593 if (longOpt != null)
594 {
595 buf.append(" ").append(longOpt);
596 }
597
598 buf.append(" ");
599
600 if (hasArgs())
601 {
602 buf.append("[ARG...]");
603 }
604 else if (hasArg())
605 {
606 buf.append(" [ARG]");
607 }
608
609 buf.append(" :: ").append(description);
610
611 if (type != null)
612 {
613 buf.append(" :: ").append(type);
614 }
615
616 buf.append(" ]");
617
618 return buf.toString();
619 }
620
621 /**
622 * Returns whether this Option has any values.
623 *
624 * @return whether this Option has any values.
625 */
626 private boolean hasNoValues()
627 {
628 return values.isEmpty();
629 }
630
631 @Override
632 public boolean equals(Object o)
633 {
634 if (this == o)
635 {
636 return true;
637 }
638 if (o == null || getClass() != o.getClass())
639 {
640 return false;
641 }
642
643 Option option = (Option) o;
644
645
646 if (opt != null ? !opt.equals(option.opt) : option.opt != null)
647 {
648 return false;
649 }
650 if (longOpt != null ? !longOpt.equals(option.longOpt) : option.longOpt != null)
651 {
652 return false;
653 }
654
655 return true;
656 }
657
658 @Override
659 public int hashCode()
660 {
661 int result;
662 result = opt != null ? opt.hashCode() : 0;
663 result = 31 * result + (longOpt != null ? longOpt.hashCode() : 0);
664 return result;
665 }
666
667 /**
668 * A rather odd clone method - due to incorrect code in 1.0 it is public
669 * and in 1.1 rather than throwing a CloneNotSupportedException it throws
670 * a RuntimeException so as to maintain backwards compat at the API level.
671 *
672 * After calling this method, it is very likely you will want to call
673 * clearValues().
674 *
675 * @return a clone of this Option instance
676 * @throws RuntimeException if a {@link CloneNotSupportedException} has been thrown
677 * by {@link super#clone()}
678 */
679 @Override
680 public Object clone()
681 {
682 try
683 {
684 Option option = (Option) super.clone();
685 option.values = new ArrayList<String>(values);
686 return option;
687 }
688 catch (CloneNotSupportedException cnse)
689 {
690 throw new RuntimeException("A CloneNotSupportedException was thrown: " + cnse.getMessage());
691 }
692 }
693
694 /**
695 * Clear the Option values. After a parse is complete, these are left with
696 * data in them and they need clearing if another parse is done.
697 *
698 * See: <a href="https://issues.apache.org/jira/browse/CLI-71">CLI-71</a>
699 */
700 void clearValues()
701 {
702 values.clear();
703 }
704
705 /**
706 * This method is not intended to be used. It was a piece of internal
707 * API that was made public in 1.0. It currently throws an UnsupportedOperationException.
708 *
709 * @param value the value to add
710 * @return always throws an {@link UnsupportedOperationException}
711 * @throws UnsupportedOperationException always
712 * @deprecated
713 */
714 @Deprecated
715 public boolean addValue(String value)
716 {
717 throw new UnsupportedOperationException("The addValue method is not intended for client use. "
718 + "Subclasses should use the addValueForProcessing method instead. ");
719 }
720
721 /**
722 * Tells if the option can accept more arguments.
723 *
724 * @return false if the maximum number of arguments is reached
725 * @since 1.3
726 */
727 boolean acceptsArg()
728 {
729 return (hasArg() || hasArgs() || hasOptionalArg()) && (numberOfArgs <= 0 || values.size() < numberOfArgs);
730 }
731
732 /**
733 * Tells if the option requires more arguments to be valid.
734 *
735 * @return false if the option doesn't require more arguments
736 * @since 1.3
737 */
738 boolean requiresArg()
739 {
740 if (optionalArg)
741 {
742 return false;
743 }
744 if (numberOfArgs == UNLIMITED_VALUES)
745 {
746 return values.size() < 1;
747 }
748 else
749 {
750 return acceptsArg();
751 }
752 }
753
754 /**
755 * Returns a {@link Builder} to create an {@link Option} using descriptive
756 * methods.
757 *
758 * @return a new {@link Builder} instance
759 * @since 1.3
760 */
761 public static Builder builder()
762 {
763 return builder(null);
764 }
765
766 /**
767 * Returns a {@link Builder} to create an {@link Option} using descriptive
768 * methods.
769 *
770 * @param opt short representation of the option
771 * @return a new {@link Builder} instance
772 * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}
773 * @since 1.3
774 */
775 public static Builder builder(final String opt)
776 {
777 return new Builder(opt);
778 }
779
780 /**
781 * A nested builder class to create <code>Option</code> instances
782 * using descriptive methods.
783 * <p>
784 * Example usage:
785 * <pre>
786 * Option option = Option.builder("a")
787 * .required(true)
788 * .longOpt("arg-name")
789 * .build();
790 * </pre>
791 *
792 * @since 1.3
793 */
794 public static final class Builder
795 {
796 /** the name of the option */
797 private final String opt;
798
799 /** description of the option */
800 private String description;
801
802 /** the long representation of the option */
803 private String longOpt;
804
805 /** the name of the argument for this option */
806 private String argName;
807
808 /** specifies whether this option is required to be present */
809 private boolean required;
810
811 /** specifies whether the argument value of this Option is optional */
812 private boolean optionalArg;
813
814 /** the number of argument values this option can have */
815 private int numberOfArgs = UNINITIALIZED;
816
817 /** the type of this Option */
818 private Class<?> type = String.class;
819
820 /** the character that is the value separator */
821 private char valuesep;
822
823 /**
824 * Constructs a new <code>Builder</code> with the minimum
825 * required parameters for an <code>Option</code> instance.
826 *
827 * @param opt short representation of the option
828 * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}
829 */
830 private Builder(final String opt) throws IllegalArgumentException
831 {
832 OptionValidator.validateOption(opt);
833 this.opt = opt;
834 }
835
836 /**
837 * Sets the display name for the argument value.
838 *
839 * @param argName the display name for the argument value.
840 * @return this builder, to allow method chaining
841 */
842 public Builder argName(final String argName)
843 {
844 this.argName = argName;
845 return this;
846 }
847
848 /**
849 * Sets the description for this option.
850 *
851 * @param description the description of the option.
852 * @return this builder, to allow method chaining
853 */
854 public Builder desc(final String description)
855 {
856 this.description = description;
857 return this;
858 }
859
860 /**
861 * Sets the long name of the Option.
862 *
863 * @param longOpt the long name of the Option
864 * @return this builder, to allow method chaining
865 */
866 public Builder longOpt(final String longOpt)
867 {
868 this.longOpt = longOpt;
869 return this;
870 }
871
872 /**
873 * Sets the number of argument values the Option can take.
874 *
875 * @param numberOfArgs the number of argument values
876 * @return this builder, to allow method chaining
877 */
878 public Builder numberOfArgs(final int numberOfArgs)
879 {
880 this.numberOfArgs = numberOfArgs;
881 return this;
882 }
883
884 /**
885 * Sets whether the Option can have an optional argument.
886 *
887 * @param isOptional specifies whether the Option can have
888 * an optional argument.
889 * @return this builder, to allow method chaining
890 */
891 public Builder optionalArg(final boolean isOptional)
892 {
893 this.optionalArg = isOptional;
894 return this;
895 }
896
897 /**
898 * Marks this Option as required.
899 *
900 * @return this builder, to allow method chaining
901 */
902 public Builder required()
903 {
904 return required(true);
905 }
906
907 /**
908 * Sets whether the Option is mandatory.
909 *
910 * @param required specifies whether the Option is mandatory
911 * @return this builder, to allow method chaining
912 */
913 public Builder required(final boolean required)
914 {
915 this.required = required;
916 return this;
917 }
918
919 /**
920 * Sets the type of the Option.
921 *
922 * @param type the type of the Option
923 * @return this builder, to allow method chaining
924 */
925 public Builder type(final Class<?> type)
926 {
927 this.type = type;
928 return this;
929 }
930
931 /**
932 * The Option will use '=' as a means to separate argument value.
933 *
934 * @return this builder, to allow method chaining
935 */
936 public Builder valueSeparator()
937 {
938 return valueSeparator('=');
939 }
940
941 /**
942 * The Option will use <code>sep</code> as a means to
943 * separate argument values.
944 * <p>
945 * <b>Example:</b>
946 * <pre>
947 * Option opt = Option.builder("D").valueSeparator('=')
948 * .build();
949 *
950 * String args = "-Dkey=value";
951 * CommandLine line = parser.parse(args);
952 * String propertyName = opt.getValue(0); // will be "key"
953 * String propertyValue = opt.getValue(1); // will be "value"
954 * </pre>
955 *
956 * @param sep The value separator.
957 * @return this builder, to allow method chaining
958 */
959 public Builder valueSeparator(final char sep)
960 {
961 valuesep = sep;
962 return this;
963 }
964
965 /**
966 * Indicates that the Option will require an argument.
967 *
968 * @return this builder, to allow method chaining
969 */
970 public Builder hasArg()
971 {
972 return hasArg(true);
973 }
974
975 /**
976 * Indicates if the Option has an argument or not.
977 *
978 * @param hasArg specifies whether the Option takes an argument or not
979 * @return this builder, to allow method chaining
980 */
981 public Builder hasArg(final boolean hasArg)
982 {
983 // set to UNINITIALIZED when no arg is specified to be compatible with OptionBuilder
984 numberOfArgs = hasArg ? 1 : Option.UNINITIALIZED;
985 return this;
986 }
987
988 /**
989 * Indicates that the Option can have unlimited argument values.
990 *
991 * @return this builder, to allow method chaining
992 */
993 public Builder hasArgs()
994 {
995 numberOfArgs = Option.UNLIMITED_VALUES;
996 return this;
997 }
998
999 /**
1000 * Constructs an Option with the values declared by this {@link Builder}.
1001 *
1002 * @return the new {@link Option}
1003 * @throws IllegalArgumentException if neither {@code opt} or {@code longOpt} has been set
1004 */
1005 public Option build()
1006 {
1007 if (opt == null && longOpt == null)
1008 {
1009 throw new IllegalArgumentException("Either opt or longOpt must be specified");
1010 }
1011 return new Option(this);
1012 }
1013 }
1014 }