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  package org.apache.commons.cli2.option;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.Comparator;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.ListIterator;
26  import java.util.Set;
27  
28  import org.apache.commons.cli2.Argument;
29  import org.apache.commons.cli2.DisplaySetting;
30  import org.apache.commons.cli2.Group;
31  import org.apache.commons.cli2.OptionException;
32  import org.apache.commons.cli2.WriteableCommandLine;
33  import org.apache.commons.cli2.resource.ResourceConstants;
34  
35  /**
36   * A Parent implementation representing normal options.
37   */
38  public class DefaultOption
39      extends ParentImpl {
40      /**
41       * The default token used to prefix a short option
42       */
43      public static final String DEFAULT_SHORT_PREFIX = "-";
44  
45      /**
46       * The default token used to prefix a long option
47       */
48      public static final String DEFAULT_LONG_PREFIX = "--";
49  
50      /**
51       * The default value for the burstEnabled constructor parameter
52       */
53      public static final boolean DEFAULT_BURST_ENABLED = true;
54      private final String preferredName;
55      private final Set aliases;
56      private final Set burstAliases;
57      private final Set triggers;
58      private final Set prefixes;
59      private final String shortPrefix;
60      private final boolean burstEnabled;
61      private final int burstLength;
62  
63      /**
64       * Creates a new DefaultOption
65       *
66       * @param shortPrefix the prefix used for short options
67       * @param longPrefix the prefix used for long options
68       * @param burstEnabled should option bursting be enabled
69       * @param preferredName the preferred name for this Option, this should begin with either shortPrefix or longPrefix
70       * @param description a description of this Option
71       * @param aliases the alternative names for this Option
72       * @param burstAliases the aliases that can be burst
73       * @param required whether the Option is strictly required
74       * @param argument the Argument belonging to this Parent, or null
75       * @param children the Group children belonging to this Parent, ot null
76       * @param id the unique identifier for this Option
77       * @throws IllegalArgumentException if the preferredName or an alias isn't
78       *     prefixed with shortPrefix or longPrefix
79       */
80      public DefaultOption(final String shortPrefix,
81                           final String longPrefix,
82                           final boolean burstEnabled,
83                           final String preferredName,
84                           final String description,
85                           final Set aliases,
86                           final Set burstAliases,
87                           final boolean required,
88                           final Argument argument,
89                           final Group children,
90                           final int id) {
91          super(argument, children, description, id, required);
92  
93          this.shortPrefix = shortPrefix;
94          this.burstEnabled = burstEnabled;
95  
96          this.burstLength = shortPrefix.length() + 1;
97  
98          this.preferredName = preferredName;
99          this.aliases =
100             (aliases == null) ? Collections.EMPTY_SET
101                               : Collections.unmodifiableSet(new HashSet(aliases));
102 
103         this.burstAliases =
104             (burstAliases == null) ? Collections.EMPTY_SET
105                                    : Collections.unmodifiableSet(new HashSet(burstAliases));
106 
107         final Set newTriggers = new HashSet();
108         newTriggers.add(preferredName);
109         newTriggers.addAll(this.aliases);
110         newTriggers.addAll(this.burstAliases);
111         this.triggers = Collections.unmodifiableSet(newTriggers);
112 
113         final Set newPrefixes = new HashSet(super.getPrefixes());
114         newPrefixes.add(shortPrefix);
115         newPrefixes.add(longPrefix);
116         this.prefixes = Collections.unmodifiableSet(newPrefixes);
117 
118         checkPrefixes(newPrefixes);
119     }
120 
121     public boolean canProcess(final WriteableCommandLine commandLine,
122                               final String argument) {
123         return (argument != null) &&
124                (super.canProcess(commandLine, argument) ||
125                ((argument.length() >= burstLength) &&
126                burstAliases.contains(argument.substring(0, burstLength))));
127     }
128 
129     public void processParent(WriteableCommandLine commandLine,
130                               ListIterator arguments)
131         throws OptionException {
132         final String argument = (String) arguments.next();
133 
134         if (triggers.contains(argument)) {
135             commandLine.addOption(this);
136             arguments.set(preferredName);
137         } else if (burstEnabled && (argument.length() >= burstLength)) {
138             final String burst = argument.substring(0, burstLength);
139 
140             if (burstAliases.contains(burst)) {
141                 commandLine.addOption(this);
142 
143                 //HMM test bursting all vs bursting one by one.
144                 arguments.set(preferredName);
145 
146                 if (getArgument() == null) {
147                     arguments.add(shortPrefix + argument.substring(burstLength));
148                 } else {
149                     arguments.add(argument.substring(burstLength));
150                 }
151 
152                 arguments.previous();
153             } else {
154                 throw new OptionException(this, ResourceConstants.CANNOT_BURST, argument);
155             }
156         } else {
157             throw new OptionException(this, ResourceConstants.UNEXPECTED_TOKEN, argument);
158         }
159     }
160 
161     public Set getTriggers() {
162         return triggers;
163     }
164 
165     public Set getPrefixes() {
166         return prefixes;
167     }
168 
169     public void validate(WriteableCommandLine commandLine)
170         throws OptionException {
171         if (isRequired() && !commandLine.hasOption(this)) {
172             throw new OptionException(this, ResourceConstants.OPTION_MISSING_REQUIRED,
173                                       getPreferredName());
174         }
175 
176         super.validate(commandLine);
177     }
178 
179     public void appendUsage(final StringBuffer buffer,
180                             final Set helpSettings,
181                             final Comparator comp) {
182         // do we display optionality
183         final boolean optional =
184             !isRequired() && helpSettings.contains(DisplaySetting.DISPLAY_OPTIONAL);
185         final boolean displayAliases = helpSettings.contains(DisplaySetting.DISPLAY_ALIASES);
186 
187         if (optional) {
188             buffer.append('[');
189         }
190 
191         buffer.append(preferredName);
192 
193         if (displayAliases && !aliases.isEmpty()) {
194             buffer.append(" (");
195 
196             final List list = new ArrayList(aliases);
197             Collections.sort(list);
198 
199             for (final Iterator i = list.iterator(); i.hasNext();) {
200                 final String alias = (String) i.next();
201                 buffer.append(alias);
202 
203                 if (i.hasNext()) {
204                     buffer.append(',');
205                 }
206             }
207 
208             buffer.append(')');
209         }
210 
211         super.appendUsage(buffer, helpSettings, comp);
212 
213         if (optional) {
214             buffer.append(']');
215         }
216     }
217 
218     public String getPreferredName() {
219         return preferredName;
220     }
221 }