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.Properties;
28  
29  /**
30   * Represents list of arguments parsed against a {@link Options} descriptor.
31   * <p>
32   * It allows querying of a boolean {@link #hasOption(String opt)}, in addition to retrieving the
33   * {@link #getOptionValue(String opt)} for options requiring arguments.
34   * <p>
35   * Additionally, any left-over or unrecognized arguments, are available for further processing.
36   */
37  public class CommandLine implements Serializable {
38  
39      /**
40       * A nested builder class to create {@code CommandLine} instance using descriptive methods.
41       *
42       * @since 1.4
43       */
44      public static final class Builder {
45  
46          /**
47           * CommandLine that is being build by this Builder.
48           */
49          private final CommandLine commandLine = new CommandLine();
50  
51          /**
52           * Adds left-over unrecognized option/argument.
53           *
54           * @param arg the unrecognized option/argument.
55           *
56           * @return this Builder instance for method chaining.
57           */
58          public Builder addArg(final String arg) {
59              commandLine.addArg(arg);
60              return this;
61          }
62  
63          /**
64           * Adds an option to the command line. The values of the option are stored.
65           *
66           * @param opt the processed option.
67           *
68           * @return this Builder instance for method chaining.
69           */
70          public Builder addOption(final Option opt) {
71              commandLine.addOption(opt);
72              return this;
73          }
74  
75          /**
76           * Returns the new instance.
77           *
78           * @return the new instance.
79           */
80          public CommandLine build() {
81              return commandLine;
82          }
83      }
84  
85      /** The serial version UID. */
86      private static final long serialVersionUID = 1L;
87  
88      /** The unrecognized options/arguments */
89      private final List<String> args = new LinkedList<>();
90  
91      /** The processed options */
92      private final List<Option> options = new ArrayList<>();
93  
94      /**
95       * Creates a command line.
96       */
97      protected CommandLine() {
98          // nothing to do
99      }
100 
101     /**
102      * Adds left-over unrecognized option/argument.
103      *
104      * @param arg the unrecognized option/argument.
105      */
106     protected void addArg(final String arg) {
107         if (arg != null) {
108             args.add(arg);
109         }
110     }
111 
112     /**
113      * Adds an option to the command line. The values of the option are stored.
114      *
115      * @param opt the processed option.
116      */
117     protected void addOption(final Option opt) {
118         if (opt != null) {
119             options.add(opt);
120         }
121     }
122 
123     /**
124      * Gets any left-over non-recognized options and arguments
125      *
126      * @return remaining items passed in but not parsed as a {@code List}.
127      */
128     public List<String> getArgList() {
129         return args;
130     }
131 
132     /**
133      * Gets any left-over non-recognized options and arguments
134      *
135      * @return remaining items passed in but not parsed as an array.
136      */
137     public String[] getArgs() {
138         return args.toArray(Util.EMPTY_STRING_ARRAY);
139     }
140 
141     /**
142      * Gets the {@code Object} type of this {@code Option}.
143      *
144      * @deprecated due to System.err message. Instead use getParsedOptionValue(char)
145      * @param opt the name of the option.
146      * @return the type of opt.
147      */
148     @Deprecated
149     public Object getOptionObject(final char opt) {
150         return getOptionObject(String.valueOf(opt));
151     }
152 
153     /**
154      * Gets the {@code Object} type of this {@code Option}.
155      *
156      * @param opt the name of the option.
157      * @return the type of this {@code Option}.
158      * @deprecated due to System.err message. Instead use getParsedOptionValue(String)
159      */
160     @Deprecated
161     public Object getOptionObject(final String opt) {
162         try {
163             return getParsedOptionValue(opt);
164         } catch (final ParseException pe) {
165             System.err.println("Exception found converting " + opt + " to desired type: " + pe.getMessage());
166             return null;
167         }
168     }
169 
170     /**
171      * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
172      * <code>-Dparam1=value1
173      * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
174      * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
175      *
176      * @param option name of the option.
177      * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
178      * @since 1.5.0
179      */
180     public Properties getOptionProperties(final Option option) {
181         final Properties props = new Properties();
182 
183         for (final Option processedOption : options) {
184             if (processedOption.equals(option)) {
185                 final List<String> values = processedOption.getValuesList();
186                 if (values.size() >= 2) {
187                     // use the first 2 arguments as the key/value pair
188                     props.put(values.get(0), values.get(1));
189                 } else if (values.size() == 1) {
190                     // no explicit value, handle it as a boolean
191                     props.put(values.get(0), "true");
192                 }
193             }
194         }
195 
196         return props;
197     }
198 
199     /**
200      * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
201      * <code>-Dparam1=value1
202      * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
203      * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
204      *
205      * @param opt name of the option.
206      * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
207      * @since 1.2
208      */
209     public Properties getOptionProperties(final String opt) {
210         final Properties props = new Properties();
211 
212         for (final Option option : options) {
213             if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) {
214                 final List<String> values = option.getValuesList();
215                 if (values.size() >= 2) {
216                     // use the first 2 arguments as the key/value pair
217                     props.put(values.get(0), values.get(1));
218                 } else if (values.size() == 1) {
219                     // no explicit value, handle it as a boolean
220                     props.put(values.get(0), "true");
221                 }
222             }
223         }
224 
225         return props;
226     }
227 
228     /**
229      * Gets an array of the processed {@link Option}s.
230      *
231      * @return an array of the processed {@link Option}s.
232      */
233     public Option[] getOptions() {
234         return options.toArray(Option.EMPTY_ARRAY);
235     }
236 
237     /**
238      * Gets the first argument, if any, of this option.
239      *
240      * @param opt the character name of the option.
241      * @return Value of the argument if option is set, and has an argument, otherwise null.
242      */
243     public String getOptionValue(final char opt) {
244         return getOptionValue(String.valueOf(opt));
245     }
246 
247     /**
248      * Gets the argument, if any, of an option.
249      *
250      * @param opt character name of the option
251      * @param defaultValue is the default value to be returned if the option is not specified.
252      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
253      */
254     public String getOptionValue(final char opt, final String defaultValue) {
255         return getOptionValue(String.valueOf(opt), defaultValue);
256     }
257 
258     /**
259      * Gets the first argument, if any, of this option.
260      *
261      * @param option the name of the option.
262      * @return Value of the argument if option is set, and has an argument, otherwise null.
263      * @since 1.5.0
264      */
265     public String getOptionValue(final Option option) {
266         if (option == null) {
267             return null;
268         }
269         final String[] values = getOptionValues(option);
270         return values == null ? null : values[0];
271     }
272 
273     /**
274      * Gets the first argument, if any, of an option.
275      *
276      * @param option name of the option.
277      * @param defaultValue is the default value to be returned if the option is not specified.
278      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
279      * @since 1.5.0
280      */
281     public String getOptionValue(final Option option, final String defaultValue) {
282         final String answer = getOptionValue(option);
283         return answer != null ? answer : defaultValue;
284     }
285 
286     /**
287      * Gets the first argument, if any, of this option.
288      *
289      * @param opt the name of the option.
290      * @return Value of the argument if option is set, and has an argument, otherwise null.
291      */
292     public String getOptionValue(final String opt) {
293         return getOptionValue(resolveOption(opt));
294     }
295 
296     /**
297      * Gets the first argument, if any, of an option.
298      *
299      * @param opt name of the option.
300      * @param defaultValue is the default value to be returned if the option is not specified.
301      * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
302      */
303     public String getOptionValue(final String opt, final String defaultValue) {
304         return getOptionValue(resolveOption(opt), defaultValue);
305     }
306 
307     /**
308      * Gets the array of values, if any, of an option.
309      *
310      * @param opt character name of the option.
311      * @return Values of the argument if option is set, and has an argument, otherwise null.
312      */
313     public String[] getOptionValues(final char opt) {
314         return getOptionValues(String.valueOf(opt));
315     }
316 
317     /**
318      * Gets the array of values, if any, of an option.
319      *
320      * @param option string name of the option.
321      * @return Values of the argument if option is set, and has an argument, otherwise null.
322      * @since 1.5.0
323      */
324     public String[] getOptionValues(final Option option) {
325         final List<String> values = new ArrayList<>();
326 
327         for (final Option processedOption : options) {
328             if (processedOption.equals(option)) {
329                 values.addAll(processedOption.getValuesList());
330             }
331         }
332 
333         return values.isEmpty() ? null : values.toArray(EMPTY_STRING_ARRAY);
334     }
335 
336     /**
337      * Gets the array of values, if any, of an option.
338      *
339      * @param opt string name of the option.
340      * @return Values of the argument if option is set, and has an argument, otherwise null.
341      */
342     public String[] getOptionValues(final String opt) {
343         return getOptionValues(resolveOption(opt));
344     }
345 
346     /**
347      * Gets a version of this {@code Option} converted to a particular type.
348      *
349      * @param opt the name of the option.
350      * @return the value parsed into a particular object.
351      * @throws ParseException if there are problems turning the option value into the desired type
352      * @see PatternOptionBuilder
353      * @since 1.5.0
354      */
355     public Object getParsedOptionValue(final char opt) throws ParseException {
356         return getParsedOptionValue(String.valueOf(opt));
357     }
358 
359     /**
360      * Gets a version of this {@code Option} converted to a particular type.
361      *
362      * @param option the name of the option.
363      * @return the value parsed into a particular object.
364      * @throws ParseException if there are problems turning the option value into the desired type
365      * @see PatternOptionBuilder
366      * @since 1.5.0
367      */
368     public Object getParsedOptionValue(final Option option) throws ParseException {
369         if (option == null) {
370             return null;
371         }
372         final String res = getOptionValue(option);
373         if (res == null) {
374             return null;
375         }
376         return TypeHandler.createValue(res, option.getType());
377     }
378 
379     /**
380      * Gets a version of this {@code Option} converted to a particular type.
381      *
382      * @param opt the name of the option.
383      * @return the value parsed into a particular object.
384      * @throws ParseException if there are problems turning the option value into the desired type
385      * @see PatternOptionBuilder
386      * @since 1.2
387      */
388     public Object getParsedOptionValue(final String opt) throws ParseException {
389         return getParsedOptionValue(resolveOption(opt));
390     }
391 
392     /**
393      * jkeyes - commented out until it is implemented properly
394      * <p>
395      * Dump state, suitable for debugging.
396      * </p>
397      *
398      * @return Stringified form of this object.
399      */
400 
401     /*
402      * public String toString() { StringBuilder buf = new StringBuilder();
403      *
404      * buf.append("[ CommandLine: [ options: "); buf.append(options.toString()); buf.append(" ] [ args: ");
405      * buf.append(args.toString()); buf.append(" ] ]");
406      *
407      * return buf.toString(); }
408      */
409 
410     /**
411      * Tests to see if an option has been set.
412      *
413      * @param opt character name of the option.
414      * @return true if set, false if not.
415      */
416     public boolean hasOption(final char opt) {
417         return hasOption(String.valueOf(opt));
418     }
419 
420     /**
421      * Tests to see if an option has been set.
422      *
423      * @param opt the option to check.
424      * @return true if set, false if not.
425      * @since 1.5.0
426      */
427     public boolean hasOption(final Option opt) {
428         return options.contains(opt);
429     }
430 
431     /**
432      * Tests to see if an option has been set.
433      *
434      * @param opt Short name of the option.
435      * @return true if set, false if not.
436      */
437     public boolean hasOption(final String opt) {
438         return hasOption(resolveOption(opt));
439     }
440 
441     /**
442      * Returns an iterator over the Option members of CommandLine.
443      *
444      * @return an {@code Iterator} over the processed {@link Option} members of this {@link CommandLine}.
445      */
446     public Iterator<Option> iterator() {
447         return options.iterator();
448     }
449 
450     /**
451      * Retrieves the option object given the long or short option as a String
452      *
453      * @param opt short or long name of the option, may be null.
454      * @return Canonicalized option.
455      */
456     private Option resolveOption(final String opt) {
457         final String actual = Util.stripLeadingHyphens(opt);
458         if (actual != null) {
459             for (final Option option : options) {
460                 if (actual.equals(option.getOpt()) || actual.equals(option.getLongOpt())) {
461                     return option;
462                 }
463             }
464         }
465         return null;
466     }
467 }