/**
* CommandLineParser.java
*
* Copyright 2005 by Entwine
* Zurich, Switzerland (CH)
* All rights reserved.
*
* This software is confidential and proprietary information ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into.
*/
package ch.entwine.weblounge.tools.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
/**
* Parses the given commandline and returns its option values and
* parsedCommands.
*
* @author Tobias Wunden
* @version 1.0
*/
public class CommandLineParser {
/** The defined command line options */
@SuppressWarnings("rawtypes")
private Map definedOptions = new HashMap();
/** The required command line options */
@SuppressWarnings("rawtypes")
private Map requiredOptions = new HashMap();
/** The parsed command line options */
@SuppressWarnings("rawtypes")
private Map parsedOptions = new HashMap();
/** The defined command line actions */
@SuppressWarnings("rawtypes")
private Map definedCommands = new HashMap();
/** The parsed command line actions */
@SuppressWarnings("rawtypes")
private Set parsedCommands = new HashSet();
/**
* Creates a new commandline parser for the given arguments.
*/
public CommandLineParser() { }
/**
* Resets the parser to its initial state.
*/
public void reset() {
parsedOptions.clear();
parsedCommands.clear();
}
/**
* Defines the option for the given commandline.
*
* @param option the option
*/
public void defineOption(String option) {
if (option != null) {
definedOptions.put(option, null);
}
}
/**
* Defines the option for the given commandline. The string array
* contains the various typings of the option name.
*
* @param option the option names
*/
public void defineOption(String[] option) {
if (option != null) {
for (int i=0; i < option.length; i++) {
definedOptions.put(option[i], option);
}
}
}
/**
* Defines the option for the given commandline and marks it as
* beeing required.
*
* @param option the required option
*/
public void defineRequiredOption(String option) {
if (option != null) {
definedOptions.put(option, null);
requiredOptions.put(option, null);
}
}
/**
* Defines the option for the given commandline and marks it as beeing
* required. The string array contains the various typings of the option name.
*
* @param option the required option names
*/
public void defineRequiredOption(String[] option) {
if (option != null) {
for (int i=0; i < option.length; i++) {
definedOptions.put(option[i], option);
requiredOptions.put(option[i], option);
}
}
}
/**
* Returns all parsedOptions that have been passed on the commandline.
*
* @return the parsedOptions
*/
public Set getOptions() {
return parsedOptions.keySet();
}
/**
* Returns <code>true</code> if the option has been specified.
*
* @param option the option name
* @return <code>true</code> if the option has been specified
*/
public boolean providesOption(String option) {
return getOption(option) != null;
}
/**
* Returns <code>true</code> if the option has been specified. The
* string array must specifiy the various typings of the option name.
*
* @param option the option names
* @return <code>true</code> if the option has been specified
*/
public boolean providesOption(String[] option) {
return getOption(option) != null;
}
/**
* Returns the option value for <code>option</code> or <code>null</code>
* if no such option has been passed.
*
* @param option the option name
* @return the option value
*/
public String getOption(String option) {
String v = (String)parsedOptions.get(option);
if (v != null) {
return v;
}
String[] options = (String[])definedOptions.get(option);
if (options != null) {
for (int i=0; i < options.length; i++) {
v = (String)parsedOptions.get(options[i]);
if (v != null) {
return v;
}
}
}
return null;
}
/**
* Returns the option value for <code>option</code> or <code>defaultValue</code>
* if no such option has been passed.
*
* @param option the option name
* @return the option value
*/
public String getOption(String option, String defaultValue) {
String v = getOption(option);
return (v != null) ? v : defaultValue;
}
/**
* Returns the option value for <code>option</code> or <code>null</code>
* if no such option has been passed. The string array must specifiy the various
* typings of the option name.
*
* @param option the option names
* @return the option value
*/
public String getOption(String[] option) {
if (option != null) {
for (int i=0; i < option.length; i++) {
String v = (String)parsedOptions.get(option[i]);
if (v != null) {
return v;
}
}
}
return null;
}
/**
* Returns the option value for <code>option</code> or <code>defaultValue</code>
* if no such option has been passed.
*
* @param option the option names
* @return the option value
*/
public String getOption(String[] option, String defaultValue) {
String v = getOption(option);
return (v != null) ? v : defaultValue;
}
/**
* Defines the command for the given commandline.
*
* @param command the command
*/
public void defineCommand(String command) {
if (command != null) {
definedCommands.put(command, null);
}
}
/**
* Defines the command for the given commandline. The string array
* contains the various typings of the command name.
*
* @param command the command names
*/
public void defineCommand(String[] command) {
if (command != null) {
for (int i=0; i < command.length; i++) {
definedCommands.put(command[i], command);
}
}
}
/**
* Returns all parsedCommands that have been passed on the commandline.
*
* @return the parsedCommands
*/
public Set getCommands() {
return parsedCommands;
}
/**
* Returns <code>true</code> if the command has been specified.
*
* @param command the command name
* @return <code>true</code> if the command has been specified
*/
public boolean providesCommand(String command) {
if (parsedCommands.contains(command)) {
return true;
}
String[] commands = (String[])definedCommands.get(command);
return providesCommand(commands);
}
/**
* Returns <code>true</code> if the command has been specified. The
* string array must specifiy the various typings of the command.
*
* @param command the command names
* @return <code>true</code> if the command has been specified
*/
public boolean providesCommand(String[] command) {
if (command != null) {
for (int i=0; i < command.length; i++) {
if (parsedCommands.contains(command[i])) {
return true;
}
}
}
return false;
}
/**
* Parses the commandline and puts the values into the <code>parsedOptions</code>
* and <code>parsedCommands</code> collections.
*
* @param args the commandline arguments
* @throws IllegalStateException if an unknown option or command has been detected
* or if the commandline is malformed
*/
public void parse(String[] args) throws IllegalStateException {
Stack stack = createStack(args);
List required = new ArrayList();
required.addAll(requiredOptions.keySet());
while (!stack.empty()) {
String arg = (String)stack.pop();
if (arg.startsWith("--") && arg.trim().length() > 2) {
int equalsSign = arg.indexOf("=");
if (equalsSign > 2) {
String option = arg.substring(2, equalsSign);
if (definedOptions.containsKey(option)) {
String value = (equalsSign < arg.length() - 1) ? arg.substring(equalsSign + 1) : null;
putOption(option, value);
} else {
throw new IllegalStateException("Argument '" + arg + "' is unknown!");
}
} else if (equalsSign < 0) {
String option = arg.substring(2);
if (definedOptions.containsKey(option)) {
putOption(option, null);
} else if (definedCommands.containsKey(option)) {
parsedCommands.add(option);
} else {
throw new IllegalStateException("Argument '" + arg + "' is unknown!");
}
} else {
throw new IllegalStateException("Commandline is malformed. Found '--' without command name!");
}
} else if (arg.startsWith("-") && arg.trim().length() > 1) {
if (arg.length() > 2) {
for (int i=1; i < arg.length(); i++) {
String command = arg.substring(i, i + 1);
if (definedCommands.containsKey(command)) {
parsedCommands.add(command);
} else {
throw new IllegalStateException("Argument '" + arg + "' is unknown!");
}
}
} else {
String option = arg.substring(1, 2);
if (!stack.empty() && definedOptions.containsKey(option)) {
String value = (String)stack.pop();
putOption(option, value);
} else if (definedCommands.containsKey(option)) {
parsedCommands.add(option);
} else {
throw new IllegalStateException("Commandline is malformed. Found option '" + option + "' without option value!");
}
}
} else if (!arg.startsWith("-")) {
if (definedCommands.containsKey(arg)) {
parsedCommands.add(arg);
} else {
for (int i=0; i < arg.length(); i++) {
String command = arg.substring(i, i + 1);
if (definedCommands.containsKey(command)) {
parsedCommands.add(command);
} else {
throw new IllegalStateException("Command '" + arg + "' is unknown!");
}
}
}
} else {
throw new IllegalStateException("Commandline is malformed. Found '-' without option name or command!");
}
}
checkRequired();
}
/**
* Checks if all required options have been provided. It this is not the case,
* an <code>IllegalArgumentException</code> is thrown.
*/
private void checkRequired() {
Map options = new HashMap();
options.putAll(requiredOptions);
Iterator oi = parsedOptions.keySet().iterator();
while (oi.hasNext()) {
String option = (String)oi.next();
String[] names = (String[])options.remove(option);
if (names != null) {
for (int i=0; i < names.length; i ++) {
options.remove(names[i]);
}
}
}
if (options.size() > 0) {
throw new IllegalStateException("Required options are missing!");
}
}
/**
* Registers the option value while checking for duplicate definition.
*
* @param option the option
* @param value the option value
*/
private void putOption(String option, String value) {
if (providesOption(option)) {
throw new IllegalStateException("Option '" + option + "' has duplicate value!");
}
parsedOptions.put(option, value);
}
/**
* Creates a stack from the given string array.
*
* @param args the string array
* @return the created stack
*/
private Stack createStack(String[] args) {
Stack stack = new Stack();
if (args != null) {
for (int i = args.length - 1; i >= 0; stack.push(args[i--]));
}
return stack;
}
}