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.Collection;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.LinkedHashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  /**
30   * Main entry-point into the library.
31   * <p>
32   * Options represents a collection of {@link Option} objects, which
33   * describe the possible options for a command-line.
34   * <p>
35   * It may flexibly parse long and short options, with or without
36   * values.  Additionally, it may parse only a portion of a commandline,
37   * allowing for flexible multi-stage parsing.
38   *
39   * @see org.apache.commons.cli.CommandLine
40   */
41  public class Options implements Serializable
42  {
43      /** The serial version UID. */
44      private static final long serialVersionUID = 1L;
45  
46      /** a map of the options with the character key */
47      private final Map<String, Option> shortOpts = new LinkedHashMap<String, Option>();
48  
49      /** a map of the options with the long key */
50      private final Map<String, Option> longOpts = new LinkedHashMap<String, Option>();
51  
52      /** a map of the required options */
53      // N.B. This can contain either a String (addOption) or an OptionGroup (addOptionGroup)
54      // TODO this seems wrong
55      private final List<Object> requiredOpts = new ArrayList<Object>();
56  
57      /** a map of the option groups */
58      private final Map<String, OptionGroup> optionGroups = new LinkedHashMap<String, OptionGroup>();
59  
60      /**
61       * Add the specified option group.
62       *
63       * @param group the OptionGroup that is to be added
64       * @return the resulting Options instance
65       */
66      public Options addOptionGroup(final OptionGroup group)
67      {
68          if (group.isRequired())
69          {
70              requiredOpts.add(group);
71          }
72  
73          for (final Option option : group.getOptions())
74          {
75              // an Option cannot be required if it is in an
76              // OptionGroup, either the group is required or
77              // nothing is required
78              option.setRequired(false);
79              addOption(option);
80  
81              optionGroups.put(option.getKey(), group);
82          }
83  
84          return this;
85      }
86  
87      /**
88       * Lists the OptionGroups that are members of this Options instance.
89       *
90       * @return a Collection of OptionGroup instances.
91       */
92      Collection<OptionGroup> getOptionGroups()
93      {
94          return new HashSet<OptionGroup>(optionGroups.values());
95      }
96  
97      /**
98       * Add an option that only contains a short name.
99       * 
100      * <p>
101      * The option does not take an argument.
102      * </p>
103      *
104      * @param opt Short single-character name of the option.
105      * @param description Self-documenting description
106      * @return the resulting Options instance
107      * @since 1.3
108      */
109     public Options addOption(final String opt, final String description)
110     {
111         addOption(opt, null, false, description);
112         return this;
113     }
114 
115     /**
116      * Add an option that only contains a short-name.
117      *
118      * <p>
119      * It may be specified as requiring an argument.
120      * </p>
121      *
122      * @param opt Short single-character name of the option.
123      * @param hasArg flag signalling if an argument is required after this option
124      * @param description Self-documenting description
125      * @return the resulting Options instance
126      */
127     public Options addOption(final String opt, final boolean hasArg, final String description)
128     {
129         addOption(opt, null, hasArg, description);
130         return this;
131     }
132 
133     /**
134      * Add an option that contains a short-name and a long-name.
135      *
136      * <p>
137      * It may be specified as requiring an argument.
138      * </p>
139      *
140      * @param opt Short single-character name of the option.
141      * @param longOpt Long multi-character name of the option.
142      * @param hasArg flag signalling if an argument is required after this option
143      * @param description Self-documenting description
144      * @return the resulting Options instance
145      */
146     public Options addOption(final String opt, final String longOpt, final boolean hasArg, final String description)
147     {
148         addOption(new Option(opt, longOpt, hasArg, description));
149         return this;
150     }
151 
152     /**
153      * Add an option that contains a short-name and a long-name.
154      * 
155      * <p>
156      * The added option is set as required. It may be specified as requiring an argument. This method is a shortcut for:
157      * </p>
158      *
159      * <pre>
160      * <code>
161      * Options option = new Option(opt, longOpt, hasArg, description);
162      * option.setRequired(true);
163      * options.add(option);
164      * </code>
165      * </pre>
166      *
167      * @param opt Short single-character name of the option.
168      * @param longOpt Long multi-character name of the option.
169      * @param hasArg flag signalling if an argument is required after this option
170      * @param description Self-documenting description
171      * @return the resulting Options instance
172      * @since 1.4
173      */
174     public Options addRequiredOption(final String opt, final String longOpt, final boolean hasArg, final String description)
175     {
176         final Option option = new Option(opt, longOpt, hasArg, description);
177         option.setRequired(true);
178         addOption(option);
179         return this;
180     }
181 
182     /**
183      * Adds an option instance
184      *
185      * @param opt the option that is to be added
186      * @return the resulting Options instance
187      */
188     public Options addOption(final Option opt)
189     {
190         final String key = opt.getKey();
191 
192         // add it to the long option list
193         if (opt.hasLongOpt())
194         {
195             longOpts.put(opt.getLongOpt(), opt);
196         }
197 
198         // if the option is required add it to the required list
199         if (opt.isRequired())
200         {
201             if (requiredOpts.contains(key))
202             {
203                 requiredOpts.remove(requiredOpts.indexOf(key));
204             }
205             requiredOpts.add(key);
206         }
207 
208         shortOpts.put(key, opt);
209 
210         return this;
211     }
212 
213     /**
214      * Retrieve a read-only list of options in this set
215      *
216      * @return read-only Collection of {@link Option} objects in this descriptor
217      */
218     public Collection<Option> getOptions()
219     {
220         return Collections.unmodifiableCollection(helpOptions());
221     }
222 
223     /**
224      * Returns the Options for use by the HelpFormatter.
225      *
226      * @return the List of Options
227      */
228     List<Option> helpOptions()
229     {
230         return new ArrayList<Option>(shortOpts.values());
231     }
232 
233     /**
234      * Returns the required options.
235      *
236      * @return read-only List of required options
237      */
238     public List getRequiredOptions()
239     {
240         return Collections.unmodifiableList(requiredOpts);
241     }
242 
243     /**
244      * Retrieve the {@link Option} matching the long or short name specified.
245      *
246      * <p>
247      * The leading hyphens in the name are ignored (up to 2).
248      * </p>
249      *
250      * @param opt short or long name of the {@link Option}
251      * @return the option represented by opt
252      */
253     public Option getOption(String opt)
254     {
255         opt = Util.stripLeadingHyphens(opt);
256 
257         if (shortOpts.containsKey(opt))
258         {
259             return shortOpts.get(opt);
260         }
261 
262         return longOpts.get(opt);
263     }
264 
265     /**
266      * Returns the options with a long name starting with the name specified.
267      * 
268      * @param opt the partial name of the option
269      * @return the options matching the partial name specified, or an empty list if none matches
270      * @since 1.3
271      */
272     public List<String> getMatchingOptions(String opt)
273     {
274         opt = Util.stripLeadingHyphens(opt);
275         
276         final List<String> matchingOpts = new ArrayList<String>();
277 
278         // for a perfect match return the single option only
279         if (longOpts.keySet().contains(opt))
280         {
281             return Collections.singletonList(opt);
282         }
283 
284         for (final String longOpt : longOpts.keySet())
285         {
286             if (longOpt.startsWith(opt))
287             {
288                 matchingOpts.add(longOpt);
289             }
290         }
291         
292         return matchingOpts;
293     }
294 
295     /**
296      * Returns whether the named {@link Option} is a member of this {@link Options}.
297      *
298      * @param opt short or long name of the {@link Option}
299      * @return true if the named {@link Option} is a member of this {@link Options}
300      */
301     public boolean hasOption(String opt)
302     {
303         opt = Util.stripLeadingHyphens(opt);
304 
305         return shortOpts.containsKey(opt) || longOpts.containsKey(opt);
306     }
307 
308     /**
309      * Returns whether the named {@link Option} is a member of this {@link Options}.
310      *
311      * @param opt long name of the {@link Option}
312      * @return true if the named {@link Option} is a member of this {@link Options}
313      * @since 1.3
314      */
315     public boolean hasLongOption(String opt)
316     {
317         opt = Util.stripLeadingHyphens(opt);
318 
319         return longOpts.containsKey(opt);
320     }
321 
322     /**
323      * Returns whether the named {@link Option} is a member of this {@link Options}.
324      *
325      * @param opt short name of the {@link Option}
326      * @return true if the named {@link Option} is a member of this {@link Options}
327      * @since 1.3
328      */
329     public boolean hasShortOption(String opt)
330     {
331         opt = Util.stripLeadingHyphens(opt);
332 
333         return shortOpts.containsKey(opt);
334     }
335 
336     /**
337      * Returns the OptionGroup the <code>opt</code> belongs to.
338      *
339      * @param opt the option whose OptionGroup is being queried.
340      * @return the OptionGroup if <code>opt</code> is part of an OptionGroup, otherwise return null
341      */
342     public OptionGroup getOptionGroup(final Option opt)
343     {
344         return optionGroups.get(opt.getKey());
345     }
346 
347     /**
348      * Dump state, suitable for debugging.
349      *
350      * @return Stringified form of this object
351      */
352     @Override
353     public String toString()
354     {
355         final StringBuilder buf = new StringBuilder();
356 
357         buf.append("[ Options: [ short ");
358         buf.append(shortOpts.toString());
359         buf.append(" ] [ long ");
360         buf.append(longOpts);
361         buf.append(" ]");
362 
363         return buf.toString();
364     }
365 }