package org.broadinstitute.sting.utils.cmdLine; import org.apache.commons.cli.*; import org.apache.log4j.Logger; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.HashSet; import java.util.Set; import org.broadinstitute.sting.utils.Pair; /** * User: aaron * Date: Mar 19, 2009 * Time: 6:54:15 PM *

* The Broad Institute * SOFTWARE COPYRIGHT NOTICE AGREEMENT * This software and its documentation are copyright 2009 by the * Broad Institute/Massachusetts Institute of Technology. All rights are reserved. *

* This software is supplied without any warranty or guaranteed support whatsoever. Neither * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality. */ public class ArgumentParser { // what program are we parsing for private String programName; // where we eventually want the values to land private HashMap> m_storageLocations = new HashMap>(); // create Options object protected Options m_options = new Options(); /** * our log, which we want to capture anything from org.broadinstitute.sting */ protected static Logger logger = Logger.getLogger(ArgumentParser.class); // the reference to the command line program to fill in Object prog; public ArgumentParser(String programName, Object prog) { this.programName = programName; this.prog = prog; } /** * print out the help information */ public void printHelp() { // automatically generate the help statement HelpFormatter formatter = new HelpFormatter(); formatter.printHelp(100, "java -Xmx4096m -jar dist/GenomeAnalysisTK.jar", "", m_options, "", true); } /** * addOptionalArg *

* Adds an optional argument to check on the command line * * @param name the name of the argument, the long name * @param letterform the short form * @param description the description of the argument * @param fieldname the field to set when we've parsed this option */ public void addOptionalArg(String name, String letterform, String description, String fieldname) { // we always want the help option to be available Option opt = OptionBuilder.withLongOpt(name).withArgName(name) .hasArg() .withDescription(description) .create(letterform); // add it to the option AddToOptionStorage(opt, fieldname); } /** * Used locally to add to the options storage we have, for latter processing * * @param opt the option * @param fieldname what field it should be stuck into on the calling class */ private void AddToOptionStorage(Option opt, String fieldname) { AddToOptionStorage( opt, getField(prog, fieldname) ); } /** * Used locally to add to the options storage we have, for latter processing * * @param opt the option * @param field what field it should be stuck into on the calling class */ private void AddToOptionStorage(Option opt, Pair field ) { // first check to see if we've already added an option with the same name if (m_options.hasOption( opt.getOpt() )) throw new IllegalArgumentException(opt.getOpt() + " was already added as an option"); // Doesn't make much sense to have a single (ungrouped) required option. Force to unrequired. if( !opt.hasArg() && opt.isRequired() ) opt.setRequired(false); // add to the option list m_options.addOption(opt); // add the object with it's name to the storage location m_storageLocations.put( opt.getLongOpt(), field ); } /** * Used locally to add a group of mutually exclusive options to options storage. * @param options A list of pairs of param, field to add. */ private void AddToOptionStorage( List>> options ) { OptionGroup optionGroup = new OptionGroup(); boolean isRequired = true; for( Pair> option: options ) { if (m_options.hasOption(option.first.getOpt()) ) throw new IllegalArgumentException(option.first.getOpt() + " was already added as an option"); optionGroup.addOption(option.first); m_storageLocations.put( option.first.getLongOpt(), option.second ); isRequired &= option.first.isRequired(); } optionGroup.setRequired(isRequired); m_options.addOptionGroup(optionGroup); } private Pair getField( Object obj, String fieldName ) { try { return new Pair( obj, obj.getClass().getField(fieldName) ); } catch (NoSuchFieldException e) { logger.fatal("Failed to find the field specified by the fieldname parameter."); throw new RuntimeException(e.getMessage()); } } /** * addRequiredArg *

* Adds a required argument to check on the command line * * @param name the name of the argument, the long name * @param letterform the short form * @param description the description of the argument * @param fieldname what field it should be stuck into on the calling class */ public void addRequiredArg(String name, String letterform, String description, String fieldname) { // we always want the help option to be available Option opt = OptionBuilder.isRequired() .withLongOpt(name) .withArgName(name) .hasArg() .withDescription("(Required Option) " + description) .create(letterform); // add it to the option AddToOptionStorage( opt, fieldname ); } /** * addOptionalArg *

* Adds an optional argument to check on the command line * * @param name the name of the argument, the long name * @param letterform the short form * @param description the description of the argument * @param fieldname what field it should be stuck into on the calling class */ public void addOptionalArgList(String name, String letterform, String description, String fieldname) { // we always want the help option to be available Option opt = OptionBuilder.withLongOpt(name).withArgName(name) .hasArgs() .withDescription(description) .create(letterform); // add it to the option AddToOptionStorage( opt, fieldname ); } /** * addRequiredArg *

* Adds a required argument to check on the command line * * @param name the name of the argument, the long name * @param letterform the short form * @param description the description of the argument * @param fieldname what field it should be stuck into on the calling class */ public void addRequiredArgList(String name, String letterform, String description, String fieldname) { // we always want the help option to be available Option opt = OptionBuilder.isRequired() .withLongOpt(name) .withArgName(name) .hasArgs() .withDescription("(Required Option) " + description) .create(letterform); // add it to the option AddToOptionStorage(opt, fieldname); } /** * addOptionalFlag *

* Adds an optional argument to check on the command line * * @param name the name of the argument, the long name * @param letterform the short form * @param description the description of the argument * @param fieldname what field it should be stuck into on the calling class */ public void addOptionalFlag(String name, String letterform, String description, String fieldname) { // if they've passed a non-Boolean as a object, beat them try { if (!(prog.getClass().getField(fieldname).getType() == Boolean.class)) { throw new IllegalArgumentException("Fields to addOptionalFlag must be of type Boolean"); } } catch (NoSuchFieldException e) { throw new IllegalArgumentException("Fields to addOptionalFlag must exist!"); } // we always want the help option to be available Option opt = OptionBuilder.withLongOpt(name) .withDescription(description) .create(letterform); // add it to the option AddToOptionStorage( opt, fieldname ); } /** * This function is called to validate all the arguments to the program. * If a required Arg isn't found, we generate the help message, and * exit the program * * @param args the command line arguments we recieved */ public void processArgs(String[] args, boolean allowUnrecognized) throws ParseException { OurPosixParser parser = new OurPosixParser(); Collection