package ivory.bloomir.util; import java.util.List; import java.util.Map; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * Utility class that helps manage command line options * * @author Nima Asadi */ public class OptionManager { public static final String INDEX_ROOT_PATH = "index"; public static final String POSTINGS_ROOT_PATH = "posting"; public static final String BLOOM_ROOT_PATH = "bloom"; public static final String QUERY_PATH = "query"; public static final String OUTPUT_PATH = "output"; public static final String SPAM_PATH = "spam"; public static final String BITS_PER_ELEMENT = "bpe"; public static final String NUMBER_OF_HASH = "nbHash"; public static final String HITS = "hits"; public static final String DOCUMENT_VECTOR_CLASS = "dvclass"; public static final String DOCUMENT_PATH = "document"; public static final String JUDGMENT_PATH = "candidate"; public static final String FEATURE_PATH = "feature"; private Options options; private CommandLine cmdline; private String className; private Map<String, List<String>> dependencies; /** * @param className Class name (arbitrary) */ public OptionManager(String className) { this.className = Preconditions.checkNotNull(className); options = new Options(); dependencies = Maps.newHashMap(); cmdline = null; } /** * Adds a dependency. If option A is present * then option B will be required when parsing command * line arguments. * * Please use {@link #addOption} to define optionA and * optionB first. * * @param optionA * @param optionB Option B is required if option A is present */ public void addDependency(String optionA, String optionB) { Preconditions.checkNotNull(optionA); Preconditions.checkNotNull(optionB); Preconditions.checkArgument(options.hasOption(optionA), "Option " + optionA + " not defined yet!"); Preconditions.checkArgument(options.hasOption(optionB), "Option " + optionB + " not defined yet!"); if(!dependencies.containsKey(optionA)) { List<String> required = Lists.newArrayList(); dependencies.put(optionA, required); } dependencies.get(optionA).add(optionB); } /** * Creates an Option * * @param option Option name * @param valueType Value type * @param description Description of the option * @param isRequired Whether this option is required or optional */ public void addOption(String option, String valueType, String description, boolean isRequired) { addOption(option, valueType, description, isRequired, true); } /** * Creates an Option * * @param option Option name * @param valueType Value type * @param description Description of the option * @param isRequired Whether this option is required or optional * @param hasArg Whether this option takes argument */ @SuppressWarnings("static-access") public void addOption(String option, String valueType, String description, boolean isRequired, boolean hasArg) { Preconditions.checkNotNull(option); Preconditions.checkNotNull(valueType); Preconditions.checkNotNull(description); options.addOption(OptionBuilder.withArgName(valueType).hasArg(hasArg).isRequired(isRequired) .withDescription(description).create(option)); } /** * Parses command line arguments * * @param args Command line arguments */ public void parse(String[] args) throws ParseException { CommandLineParser parser = new GnuParser(); try { cmdline = parser.parse(options, args); checkDependencies(); } catch(ParseException exp) { System.err.println("Error parsing command line: " + exp.getMessage() + "\n"); printHelp(); throw exp; } } /** * Please use {@link #parse} before calling this method. * * @param option Option name * @return value of the given option */ public String getOptionValue(String option) { Preconditions.checkNotNull(cmdline, "Command line arguments not parsed yet!"); Preconditions.checkArgument(options.hasOption(option), "Option " + option + " does not exist."); return cmdline.getOptionValue(option); } /** * Please use {@link #parse} before calling this method. * * @param option Option name * @return whether the given option is present in the command line arguments */ public boolean foundOption(String option) { Preconditions.checkNotNull(cmdline, "Command line arguments not parsed yet!"); Preconditions.checkArgument(options.hasOption(option), "Option " + option + " does not exist."); return cmdline.hasOption(option); } private void checkDependencies() throws ParseException { Preconditions.checkNotNull(cmdline, "Command line arguments not parsed yet!"); for(Object option: options.getRequiredOptions()) { if(!cmdline.hasOption((String) option)) { throw new ParseException("Option \"" + option + "\" not found."); } } for(String optionA: dependencies.keySet()) { if(!cmdline.hasOption(optionA)) { continue; } for(String optionB: dependencies.get(optionA)) { if(!cmdline.hasOption(optionB)) { throw new ParseException("Option \"" + optionB + "\" not found."); } } } } private void printHelp() { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp(className, options); if(dependencies.size() == 0) { return; } System.out.println("\nDependencies:"); for(String optionA: dependencies.keySet()) { System.out.print("If option \"" + optionA + "\" is given, options {"); for(String optionB: dependencies.get(optionA)) { System.out.print("\"" + optionB + "\", "); } System.out.println("} are required."); } System.out.println(); } }