001: /*
002: * Copyright (c) 2001-2007, Jean Tessier
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: *
016: * * Neither the name of Jean Tessier nor the names of his contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032:
033: package com.jeantessier.commandline;
034:
035: import java.util.*;
036:
037: /**
038: * Command-line parser.
039: */
040: public class CommandLine implements Visitable {
041: private static final boolean DEFAULT_STRICT = true;
042:
043: private boolean strict;
044: private ParameterStrategy parameterStrategy;
045:
046: private Map<String, CommandLineSwitch> map = new TreeMap<String, CommandLineSwitch>();
047:
048: public CommandLine() {
049: this (DEFAULT_STRICT, new CollectingParameterStrategy());
050: }
051:
052: public CommandLine(boolean strict) {
053: this (strict, new CollectingParameterStrategy());
054: }
055:
056: public CommandLine(ParameterStrategy parameterStrategy) {
057: this (DEFAULT_STRICT, parameterStrategy);
058: }
059:
060: public CommandLine(boolean strict,
061: ParameterStrategy parameterStrategy) {
062: setStrict(strict);
063: setParameterStrategy(parameterStrategy);
064: }
065:
066: public boolean isStrict() {
067: return strict;
068: }
069:
070: public void setStrict(boolean strict) {
071: this .strict = strict;
072: }
073:
074: public ParameterStrategy getParameterStrategy() {
075: return parameterStrategy;
076: }
077:
078: public void setParameterStrategy(ParameterStrategy parameterStrategy) {
079: this .parameterStrategy = parameterStrategy;
080: }
081:
082: public ToggleSwitch addToggleSwitch(String name) {
083: return addSwitch(new ToggleSwitch(name));
084: }
085:
086: public ToggleSwitch addToggleSwitch(String name,
087: boolean defaultValue) {
088: return addSwitch(new ToggleSwitch(name, defaultValue));
089: }
090:
091: public SingleValueSwitch addSingleValueSwitch(String name) {
092: return addSwitch(new SingleValueSwitch(name));
093: }
094:
095: public SingleValueSwitch addSingleValueSwitch(String name,
096: boolean mandatory) {
097: return addSwitch(new SingleValueSwitch(name, mandatory));
098: }
099:
100: public SingleValueSwitch addSingleValueSwitch(String name,
101: String defaultValue) {
102: return addSwitch(new SingleValueSwitch(name, defaultValue));
103: }
104:
105: public SingleValueSwitch addSingleValueSwitch(String name,
106: String defaultValue, boolean mandatory) {
107: return addSwitch(new SingleValueSwitch(name, defaultValue,
108: mandatory));
109: }
110:
111: public OptionalValueSwitch addOptionalValueSwitch(String name) {
112: return addSwitch(new OptionalValueSwitch(name));
113: }
114:
115: public OptionalValueSwitch addOptionalValueSwitch(String name,
116: boolean mandatory) {
117: return addSwitch(new OptionalValueSwitch(name, mandatory));
118: }
119:
120: public OptionalValueSwitch addOptionalValueSwitch(String name,
121: String defaultValue) {
122: return addSwitch(new OptionalValueSwitch(name, defaultValue));
123: }
124:
125: public OptionalValueSwitch addOptionalValueSwitch(String name,
126: String defaultValue, boolean mandatory) {
127: return addSwitch(new OptionalValueSwitch(name, defaultValue,
128: mandatory));
129: }
130:
131: public MultipleValuesSwitch addMultipleValuesSwitch(String name) {
132: return addSwitch(new MultipleValuesSwitch(name));
133: }
134:
135: public MultipleValuesSwitch addMultipleValuesSwitch(String name,
136: boolean mandatory) {
137: return addSwitch(new MultipleValuesSwitch(name, mandatory));
138: }
139:
140: public MultipleValuesSwitch addMultipleValuesSwitch(String name,
141: String defaultValue) {
142: return addSwitch(new MultipleValuesSwitch(name, defaultValue));
143: }
144:
145: public MultipleValuesSwitch addMultipleValuesSwitch(String name,
146: String defaultValue, boolean mandatory) {
147: return addSwitch(new MultipleValuesSwitch(name, defaultValue,
148: mandatory));
149: }
150:
151: /**
152: * Returns an {@link AliasSwitch} mapping name to switchNames.
153: *
154: * @param name the name of the new alias.
155: * @param switchNames the switches that the alias maps to.
156: * @return an AliasSwitch for the new alias.
157: * @throws IllegalArgumentException if any switch name is unknown.
158: *
159: * @see AliasSwitch
160: */
161: public AliasSwitch addAliasSwitch(String name,
162: String... switchNames) {
163: CommandLineSwitch[] switches = new CommandLineSwitch[switchNames.length];
164: for (int i = 0; i < switchNames.length; i++) {
165: switches[i] = getSwitch(switchNames[i], true);
166: }
167:
168: return addSwitch(new AliasSwitch(name, switches));
169: }
170:
171: private <T extends CommandLineSwitch> T addSwitch(T cls) {
172: map.put(cls.getName(), cls);
173: return cls;
174: }
175:
176: /**
177: * Returns a {@link CommandLineSwitch} matching name, if any.
178: *
179: * @param name the name of the switch to lookup.
180: * @return a switch matching name.
181: * @throws IllegalArgumentException if this CommandLine is strict and name is unknown.
182: *
183: * @see CommandLineSwitch
184: */
185: public CommandLineSwitch getSwitch(String name) {
186: return getSwitch(name, isStrict());
187: }
188:
189: /**
190: * Returns a {@link CommandLineSwitch} matching name, if any.
191: *
192: * @param name the name of the CommandLineSwitch to lookup.
193: * @param strict if true, will throw an exception if name is unknown.
194: * @return a CommandLineSwitch matching name.
195: * @throws IllegalArgumentException if strict is true and name is unknown.
196: */
197: public CommandLineSwitch getSwitch(String name, boolean strict) {
198: CommandLineSwitch cls = map.get(name);
199:
200: if (cls == null) {
201: if (strict) {
202: throw new IllegalArgumentException("Unknown switch \""
203: + name + "\"");
204: } else {
205: cls = new OptionalValueSwitch(name);
206: addSwitch(cls);
207: }
208: }
209:
210: return cls;
211: }
212:
213: public boolean getToggleSwitch(String name) {
214: boolean result = false;
215:
216: CommandLineSwitch cls = map.get(name);
217: if (cls != null) {
218: result = (Boolean) cls.getValue();
219: }
220:
221: return result;
222: }
223:
224: public String getSingleSwitch(String name) {
225: return getStringSwitch(name);
226: }
227:
228: public String getOptionalSwitch(String name) {
229: return getStringSwitch(name);
230: }
231:
232: public List<String> getMultipleSwitch(String name) {
233: return getListSwitch(name);
234: }
235:
236: private String getStringSwitch(String name) {
237: String result = null;
238:
239: CommandLineSwitch cls = map.get(name);
240: if (cls != null) {
241: result = cls.getValue().toString();
242: }
243:
244: return result;
245: }
246:
247: private List<String> getListSwitch(String name) {
248: List<String> result = null;
249:
250: CommandLineSwitch cls = map.get(name);
251: if (cls != null && cls.getValue() instanceof List) {
252: result = (List<String>) cls.getValue();
253: }
254:
255: return result;
256: }
257:
258: public boolean isPresent(String name) {
259: boolean result = false;
260:
261: CommandLineSwitch cls = map.get(name);
262: if (cls != null) {
263: result = cls.isPresent();
264: }
265:
266: return result;
267: }
268:
269: public Set<String> getKnownSwitches() {
270: return map.keySet();
271: }
272:
273: public Collection<CommandLineSwitch> getSwitches() {
274: return map.values();
275: }
276:
277: public Set<String> getPresentSwitches() {
278: Set<String> result = new TreeSet<String>();
279:
280: for (String name : getKnownSwitches()) {
281: CommandLineSwitch cls = map.get(name);
282:
283: if (cls.isPresent()) {
284: result.add(name);
285: }
286: }
287:
288: return result;
289: }
290:
291: public List<String> getParameters() {
292: return parameterStrategy.getParameters();
293: }
294:
295: public Collection<CommandLineException> parse(String args[]) {
296: Collection<CommandLineException> exceptions = new ArrayList<CommandLineException>();
297:
298: int i = 0;
299: while (i < args.length) {
300: try {
301: if (args[i].startsWith("-")) {
302: String name = args[i].substring(1);
303: String value = null;
304:
305: if (i + 1 < args.length
306: && !map.containsKey(args[i + 1]
307: .substring(1))) {
308: value = args[i + 1];
309: }
310:
311: i += getSwitch(name).parse(value);
312: } else {
313: i += parameterStrategy.accept(args[i]);
314: }
315: } catch (CommandLineException e) {
316: exceptions.add(e);
317: }
318: }
319:
320: // Checking that all manadatory switches are present
321: for (CommandLineSwitch cls : map.values()) {
322: try {
323: cls.validate();
324: } catch (CommandLineException e) {
325: exceptions.add(e);
326: }
327: }
328:
329: // Checking that all mandatory parameters are present
330: try {
331: parameterStrategy.validate();
332: } catch (CommandLineException e) {
333: exceptions.add(e);
334: }
335:
336: return exceptions;
337: }
338:
339: public void accept(Visitor visitor) {
340: visitor.visitCommandLine(this);
341: }
342: }
|