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