View Javadoc
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.Iterator;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Objects;
26  import java.util.Properties;
27  import java.util.function.Consumer;
28  import java.util.function.Supplier;
29  
30  /**
31   * Represents list of arguments parsed against a {@link Options} descriptor.
32   * <p>
33   * It allows querying of a boolean {@link #hasOption(String opt)}, in addition to retrieving the
34   * {@link #getOptionValue(String opt)} for options requiring arguments.
35   * </p>
36   * <p>
37   * Additionally, any left-over or unrecognized arguments, are available for further processing.
38   * </p>
39   */
40  public class CommandLine implements Serializable {
41  
42      /**
43       * A nested builder class to create {@code CommandLine} instance using descriptive methods.
44       *
45       * @since 1.4
46       */
47      public static final class Builder {
48  
49          /**
50           * Prints an Option to {@link System#out}.
51           */
52          static final Consumer<Option> DEPRECATED_HANDLER = o -> System.out.println(o.toDeprecatedString());
53  
54          /** The unrecognized options/arguments */
55          private final List<String> args = new LinkedList<>();
56  
57          /** The processed options */
58          private final List<Option> options = new ArrayList<>();
59  
60          /**
61           * Deprecated Option handler.
62           */
63          private Consumer<Option> deprecatedHandler = DEPRECATED_HANDLER;
64  
65          /**
66           * Adds left-over unrecognized option/argument.
67           *
68           * @param arg the unrecognized option/argument.
69           *
70           * @return this Builder instance for method chaining.
71           */
72          public Builder addArg(final String arg) {
73              if (arg != null) {
74                  args.add(arg);
75              }
76              return this;
77          }
78  
79          /**
80           * Adds an option to the command line. The values of the option are stored.
81           *
82           * @param opt the processed option.
83           *
84           * @return this Builder instance for method chaining.
85           */
86          public Builder addOption(final Option opt) {
87              if (opt != null) {
88                  options.add(opt);
89              }
90              return this;
91          }
92  
93          /**
94           * Creates the new instance.
95           *
96           * @return the new instance.
97           */
98          public CommandLine build() {
99              return new CommandLine(args, options, deprecatedHandler);
100         }
101 
102         /**
103          * Sets the deprecated option handler.
104          *
105          * @param deprecatedHandler the deprecated option handler.
106          * @return {@code this} instance.
107          * @since 1.7.0
108          */
109         public Builder setDeprecatedHandler(final Consumer<Option> deprecatedHandler) {
110             this.deprecatedHandler = deprecatedHandler;
111             return this;
112         }
113     }
114 
115     /** The serial version UID. */
116     private static final long serialVersionUID = 1L;
117 
118     /**
119      * Creates a new builder.
120      *
121      * @return a new builder.
122      * @since 1.7.0
123      */
124     public static Builder builder() {
125         return new Builder();
126     }
127 
128     /** The unrecognized options/arguments */
129     private final List<String> args;
130 
131     /** The processed options */
132     private final List<Option> options;
133 
134     /**
135      * The deprecated option handler.
136      * <p>
137      * If you want to serialize this field, use a serialization proxy.
138      * </p>
139      */
140     private final transient Consumer<Option> deprecatedHandler;
141 
142     /**
143      * Creates a command line.
144      */
145     protected CommandLine() {
146         this(new LinkedList<>(), new ArrayList<>(), Builder.DEPRECATED_HANDLER);
147     }
148 
149     /**
150      * Creates a command line.
151      */
152     private CommandLine(final List<String> args, final List<Option> options, final Consumer<Option> deprecatedHandler) {
153         this.args = Objects.requireNonNull(args, "args");
154         this.options = Objects.requireNonNull(options, "options");
155         this.deprecatedHandler = deprecatedHandler;
156     }
157 
158     /**
159      * Adds left-over unrecognized option/argument.
160      *
161      * @param arg the unrecognized option/argument.
162      */
163     protected void addArg(final String arg) {
164         if (arg != null) {
165             args.add(arg);
166         }
167     }
168 
169     /**
170      * Adds an option to the command line. The values of the option are stored.
171      *
172      * @param opt the processed option.
173      */
174     protected void addOption(final Option opt) {
175         if (opt != null) {
176             options.add(opt);
177         }
178     }
179 
180     private <T> T get(final Supplier<T> supplier) {
181         return supplier == null ? null : supplier.get();
182     }
183 
184     /**
185      * Gets any left-over non-recognized options and arguments
186      *
187      * @return remaining items passed in but not parsed as a {@code List}.
188      */
189     public List<String> getArgList() {
190         return args;
191     }
192 
193     /**
194      * Gets any left-over non-recognized options and arguments
195      *
196      * @return remaining items passed in but not parsed as an array.
197      */
198     public String[] getArgs() {
199         return args.toArray(Util.EMPTY_STRING_ARRAY);
200     }
201 
202     /**
203      * Gets the {@code Object} type of this {@code Option}.
204      *
205      * @deprecated due to System.err message. Instead use getParsedOptionValue(char)
206      * @param opt the name of the option.
207      * @return the type of opt.
208      */
209     @Deprecated
210     public Object getOptionObject(final char opt) {
211         return getOptionObject(String.valueOf(opt));
212     }
213 
214     /**
215      * Gets the {@code Object} type of this {@code Option}.
216      *
217      * @param opt the name of the option.
218      * @return the type of this {@code Option}.
219      * @deprecated due to System.err message. Instead use getParsedOptionValue(String)
220      */
221     @Deprecated
222     public Object getOptionObject(final String opt) {
223         try {
224             return getParsedOptionValue(opt);
225         } catch (final ParseException pe) {
226             System.err.println("Exception found converting " + opt + " to desired type: " + pe.getMessage());
227             return null;
228         }
229     }
230 
231     /**
232      * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
233      * <code>-Dparam1=value1
234      * -Dparam2=value2</code>. All odd numbered values are property keys
235      * and even numbered values are property values.  If there are an odd number of values
236      * the last value is assumed to be a boolean flag and the value is "true".
237      *
238      * @param option name of the option.
239      * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
240      * @since 1.5.0
241      */
242     public Properties getOptionProperties(final Option option) {
243         final Properties props = new Properties();
244         for (final Option processedOption : options) {
245             if (processedOption.equals(option)) {
246                 processPropertiesFromValues(props, processedOption.getValuesList());
247             }
248         }
249         return props;
250     }
251 
252     /**
253      * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
254      * <code>-Dparam1=value1
255      * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
256      * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
257      *
258      * @param opt name of the option.
259      * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
260      * @since 1.2
261      */
262     public Properties getOptionProperties(final String opt) {
263         final Properties props = new Properties();
264         for (final Option option : options) {
265             if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) {
266                 processPropertiesFromValues(props, option.getValuesList());
267             }
268         }
269         return props;
270     }
271 
272     /**
273      * Gets an array of the processed {@link Option}s.
274      *
275      * @return an array of the processed {@link Option}s.
276      */
277     public Option[] getOptions() {
278         return options.toArray(Option.EMPTY_ARRAY);
279     }
280 
281     /**
282      * Gets the first argument, if any, of this option.
283      *
284      * @param opt the character name of the option.
285      * @return Value of the argument if option is set, and has an argument, otherwise null.
286      */
287     public String getOptionValue(final char opt) {
288         return getOptionValue(String.valueOf(opt));
289     }
290 
291     /**
292      * Gets the argument, if any, of an option.
293      *
294      * @param opt character name of the option
295      * @param defaultValue is the default value to be returned if the option is not specified.
296      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
297      */
298     public String getOptionValue(final char opt, final String defaultValue) {
299         return getOptionValue(String.valueOf(opt), () -> defaultValue);
300     }
301 
302     /**
303      * Gets the argument, if any, of an option.
304      *
305      * @param opt character name of the option
306      * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
307      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
308      * @since 1.7.0
309      */
310     public String getOptionValue(final char opt, final Supplier<String> defaultValue) {
311         return getOptionValue(String.valueOf(opt), defaultValue);
312     }
313 
314     /**
315      * Gets the first argument, if any, of this option.
316      *
317      * @param option the name of the option.
318      * @return Value of the argument if option is set, and has an argument, otherwise null.
319      * @since 1.5.0
320      */
321     public String getOptionValue(final Option option) {
322         final String[] values = getOptionValues(option);
323         return values == null ? null : values[0];
324     }
325 
326     /**
327      * Gets the first argument, if any, of an option.
328      *
329      * @param option name of the option.
330      * @param defaultValue is the default value to be returned if the option is not specified.
331      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
332      * @since 1.5.0
333      */
334     public String getOptionValue(final Option option, final String defaultValue) {
335         return getOptionValue(option, () -> defaultValue);
336     }
337 
338     /**
339      * Gets the first argument, if any, of an option.
340      *
341      * @param option name of the option.
342      * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
343      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
344      * @since 1.7.0
345      */
346     public String getOptionValue(final Option option, final Supplier<String> defaultValue) {
347         final String answer = getOptionValue(option);
348         return answer != null ? answer : get(defaultValue);
349     }
350 
351     /**
352      * Gets the first argument, if any, of this option.
353      *
354      * @param opt the name of the option.
355      * @return Value of the argument if option is set, and has an argument, otherwise null.
356      */
357     public String getOptionValue(final String opt) {
358         return getOptionValue(resolveOption(opt));
359     }
360 
361     /**
362      * Gets the first argument, if any, of an option.
363      *
364      * @param opt name of the option.
365      * @param defaultValue is the default value to be returned if the option is not specified.
366      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
367      */
368     public String getOptionValue(final String opt, final String defaultValue) {
369         return getOptionValue(resolveOption(opt), () -> defaultValue);
370     }
371 
372     /**
373      * Gets the first argument, if any, of an option.
374      *
375      * @param opt name of the option.
376      * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
377      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
378      * @since 1.7.0
379      */
380     public String getOptionValue(final String opt, final Supplier<String> defaultValue) {
381         return getOptionValue(resolveOption(opt), defaultValue);
382     }
383 
384 
385     /**
386      * Gets the array of values, if any, of an option.
387      *
388      * @param opt character name of the option.
389      * @return Values of the argument if option is set, and has an argument, otherwise null.
390      */
391     public String[] getOptionValues(final char opt) {
392         return getOptionValues(String.valueOf(opt));
393     }
394 
395     /**
396      * Gets the array of values, if any, of an option.
397      *
398      * @param option string name of the option.
399      * @return Values of the argument if option is set, and has an argument, otherwise null.
400      * @since 1.5.0
401      */
402     public String[] getOptionValues(final Option option) {
403         if (option == null) {
404             return null;
405         }
406         if (option.isDeprecated()) {
407             handleDeprecated(option);
408         }
409         final List<String> values = new ArrayList<>();
410         for (final Option processedOption : options) {
411             if (processedOption.equals(option)) {
412                 values.addAll(processedOption.getValuesList());
413             }
414         }
415         return values.isEmpty() ? null : values.toArray(Util.EMPTY_STRING_ARRAY);
416     }
417 
418     /**
419      * Gets the array of values, if any, of an option.
420      *
421      * @param opt string name of the option.
422      * @return Values of the argument if option is set, and has an argument, otherwise null.
423      */
424     public String[] getOptionValues(final String opt) {
425         return getOptionValues(resolveOption(opt));
426     }
427 
428     /**
429      * Gets a version of this {@code Option} converted to a particular type.
430      *
431      * @param opt the name of the option.
432      * @param <T> The return type for the method.
433      * @return the value parsed into a particular object.
434      * @throws ParseException if there are problems turning the option value into the desired type
435      * @see PatternOptionBuilder
436      * @since 1.5.0
437      */
438     public <T> T getParsedOptionValue(final char opt) throws ParseException {
439         return getParsedOptionValue(String.valueOf(opt));
440     }
441 
442     /**
443      * Gets a version of this {@code Option} converted to a particular type.
444      *
445      * @param opt the name of the option.
446      * @param defaultValue the default value to return if opt is not set.
447      * @param <T> The return type for the method.
448      * @return the value parsed into a particular object.
449      * @throws ParseException if there are problems turning the option value into the desired type
450      * @see PatternOptionBuilder
451      * @since 1.7.0
452      */
453     public <T> T getParsedOptionValue(final char opt, final Supplier<T> defaultValue) throws ParseException {
454         return getParsedOptionValue(String.valueOf(opt), defaultValue);
455     }
456 
457     /**
458      * Gets a version of this {@code Option} converted to a particular type.
459      *
460      * @param opt the name of the option.
461      * @param defaultValue the default value to return if opt is not set.
462      * @param <T> The return type for the method.
463      * @return the value parsed into a particular object.
464      * @throws ParseException if there are problems turning the option value into the desired type
465      * @see PatternOptionBuilder
466      * @since 1.7.0
467      */
468     public <T> T getParsedOptionValue(final char opt, final T defaultValue) throws ParseException {
469         return getParsedOptionValue(String.valueOf(opt), defaultValue);
470     }
471 
472     /**
473      * Gets a version of this {@code Option} converted to a particular type.
474      *
475      * @param option the name of the option.
476      * @param <T> The return type for the method.
477      * @return the value parsed into a particular object.
478      * @throws ParseException if there are problems turning the option value into the desired type
479      * @see PatternOptionBuilder
480      * @since 1.5.0
481      */
482     public <T> T getParsedOptionValue(final Option option) throws ParseException {
483         return getParsedOptionValue(option, () -> null);
484     }
485 
486     /**
487      * Gets a version of this {@code Option} converted to a particular type.
488      *
489      * @param option the name of the option.
490      * @param defaultValue the default value to return if opt is not set.
491      * @param <T> The return type for the method.
492      * @return the value parsed into a particular object.
493      * @throws ParseException if there are problems turning the option value into the desired type
494      * @see PatternOptionBuilder
495      * @since 1.7.0
496      */
497     @SuppressWarnings("unchecked")
498     public <T> T getParsedOptionValue(final Option option, final Supplier<T> defaultValue) throws ParseException {
499         if (option == null) {
500             return get(defaultValue);
501         }
502         final String res = getOptionValue(option);
503         try {
504             if (res == null) {
505                 return get(defaultValue);
506             }
507             return (T) option.getConverter().apply(res);
508         } catch (final Throwable e) {
509             throw ParseException.wrap(e);
510         }
511     }
512 
513     /**
514      * Gets a version of this {@code Option} converted to a particular type.
515      *
516      * @param option the name of the option.
517      * @param defaultValue the default value to return if opt is not set.
518      * @param <T> The return type for the method.
519      * @return the value parsed into a particular object.
520      * @throws ParseException if there are problems turning the option value into the desired type
521      * @see PatternOptionBuilder
522      * @since 1.7.0
523      */
524     public <T> T getParsedOptionValue(final Option option, final T defaultValue) throws ParseException {
525         return getParsedOptionValue(option, () -> defaultValue);
526     }
527 
528     /**
529      * Gets a version of this {@code Option} converted to a particular type.
530      *
531      * @param opt the name of the option.
532      * @param <T> The return type for the method.
533      * @return the value parsed into a particular object.
534      * @throws ParseException if there are problems turning the option value into the desired type
535      * @see PatternOptionBuilder
536      * @since 1.2
537      */
538     public <T> T getParsedOptionValue(final String opt) throws ParseException {
539         return getParsedOptionValue(resolveOption(opt));
540     }
541 
542     /**
543      * Gets a version of this {@code Option} converted to a particular type.
544      *
545      * @param opt the name of the option.
546      * @param defaultValue the default value to return if opt is not set.
547      * @param <T> The return type for the method.
548      * @return the value parsed into a particular object.
549      * @throws ParseException if there are problems turning the option value into the desired type
550      * @see PatternOptionBuilder
551      * @since 1.7.0
552      */
553     public <T> T getParsedOptionValue(final String opt, final Supplier<T> defaultValue) throws ParseException {
554         return getParsedOptionValue(resolveOption(opt), defaultValue);
555     }
556 
557     /**
558      * Gets a version of this {@code Option} converted to a particular type.
559      *
560      * @param opt the name of the option.
561      * @param defaultValue the default value to return if opt is not set.
562      * @param <T> The return type for the method.
563      * @return the value parsed into a particular object.
564      * @throws ParseException if there are problems turning the option value into the desired type
565      * @see PatternOptionBuilder
566      * @since 1.7.0
567      */
568     public <T> T getParsedOptionValue(final String opt, final T defaultValue) throws ParseException {
569         return getParsedOptionValue(resolveOption(opt), defaultValue);
570     }
571 
572     /**
573      * Handles deprecated options.
574      *
575      * @param option a deprecated option.
576      */
577     private void handleDeprecated(final Option option) {
578         if (deprecatedHandler != null) {
579             deprecatedHandler.accept(option);
580         }
581     }
582 
583     /**
584      * jkeyes - commented out until it is implemented properly
585      * <p>
586      * Dump state, suitable for debugging.
587      * </p>
588      *
589      * @return Stringified form of this object.
590      */
591 
592     /*
593      * public String toString() { StringBuilder buf = new StringBuilder();
594      *
595      * buf.append("[ CommandLine: [ options: "); buf.append(options.toString()); buf.append(" ] [ args: ");
596      * buf.append(args.toString()); buf.append(" ] ]");
597      *
598      * return buf.toString(); }
599      */
600 
601     /**
602      * Tests to see if an option has been set.
603      *
604      * @param opt character name of the option.
605      * @return true if set, false if not.
606      */
607     public boolean hasOption(final char opt) {
608         return hasOption(String.valueOf(opt));
609     }
610 
611     /**
612      * Tests to see if an option has been set.
613      *
614      * @param opt the option to check.
615      * @return true if set, false if not.
616      * @since 1.5.0
617      */
618     public boolean hasOption(final Option opt) {
619         final boolean result = options.contains(opt);
620         if (result && opt.isDeprecated()) {
621             handleDeprecated(opt);
622         }
623         return result;
624     }
625 
626     /**
627      * Tests to see if an option has been set.
628      *
629      * @param opt Short name of the option.
630      * @return true if set, false if not.
631      */
632     public boolean hasOption(final String opt) {
633         return hasOption(resolveOption(opt));
634     }
635 
636     /**
637      * Returns an iterator over the Option members of CommandLine.
638      *
639      * @return an {@code Iterator} over the processed {@link Option} members of this {@link CommandLine}.
640      */
641     public Iterator<Option> iterator() {
642         return options.iterator();
643     }
644 
645     /**
646      * Parses a list of values as properties.  All odd numbered values are property keys
647      * and even numbered values are property values.  If there are an odd number of values
648      * the last value is assumed to be a boolean with a value of "true".
649      * @param props the properties to update.
650      * @param values the list of values to parse.
651      */
652     private void processPropertiesFromValues(final Properties props, final List<String> values) {
653         for (int i = 0; i < values.size(); i += 2) {
654             if (i + 1 < values.size()) {
655                 props.put(values.get(i), values.get(i + 1));
656             } else {
657                 props.put(values.get(i), "true");
658             }
659         }
660     }
661 
662     /**
663      * Retrieves the option object given the long or short option as a String
664      *
665      * @param opt short or long name of the option, may be null.
666      * @return Canonicalized option.
667      */
668     private Option resolveOption(final String opt) {
669         final String actual = Util.stripLeadingHyphens(opt);
670         if (actual != null) {
671             for (final Option option : options) {
672                 if (actual.equals(option.getOpt()) || actual.equals(option.getLongOpt())) {
673                     return option;
674                 }
675             }
676         }
677         return null;
678     }
679 }