From 4f2ccda56a1f430668c732611e4314f35fa3b75c Mon Sep 17 00:00:00 2001 From: hanna Date: Mon, 4 May 2009 00:11:42 +0000 Subject: [PATCH] Interface skeleton for a new command line argument parser. Nowhere near the point of being a drop-in replacement for apache cli yet. git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@588 348d0f76-0448-11de-a6fe-93d51630548a --- .../utils/cmdLine/ArgumentDefinitions.java | 81 ++++++++++++++ .../sting/utils/cmdLine/ArgumentMatches.java | 55 ++++++++++ .../sting/utils/cmdLine/ArgumentParser.java | 2 +- .../sting/utils/cmdLine/ParsingEngine.java | 100 ++++++++++++++++++ .../utils/cmdLine/ParsingEngineTest.java | 74 +++++++++++++ 5 files changed, 311 insertions(+), 1 deletion(-) create mode 100755 java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java create mode 100755 java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentMatches.java create mode 100755 java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java create mode 100755 java/test/org/broadinstitute/sting/utils/cmdLine/ParsingEngineTest.java diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java new file mode 100755 index 000000000..b9d4c47a3 --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java @@ -0,0 +1,81 @@ +package org.broadinstitute.sting.utils.cmdLine; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by IntelliJ IDEA. + * User: mhanna + * Date: May 3, 2009 + * Time: 6:02:04 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. + */ +/** + * A collection of argument definitions. + */ +class ArgumentDefinitions { + /** + * Backing data set of argument stored by short name. + */ + private Map argumentsByShortName = new HashMap(); + + /** + * Does this set of argument definitions specify an argument with the given short name? + * @param shortName The short name. + * @return True if it contains the definition. False otherwise. + */ + public boolean hasArgumentWithShortName( String shortName ) { + return argumentsByShortName.containsKey( shortName ); + } + + /** + * Returns the argument with the given short name. + * @param shortName Argument short name. + * @return The argument definition, or null if nothing matches. + */ + public ArgumentDefinition getArgumentWithShortName( String shortName ) { + return argumentsByShortName.get( shortName ); + } + + /** + * Adds an argument to the this argument definition list. + * @param argument The argument to add. + * @param sourceClass Class where the argument was defined. + * @param sourceField Field in which the argument was defined. + */ + public void add( Argument argument, Class sourceClass, Field sourceField ) { + argumentsByShortName.put( argument.shortName(), + new ArgumentDefinition( argument, sourceClass, sourceField ) ); + } + +} + +/** + * A specific argument definition. Maps one-to-one with a field in some class. + */ +class ArgumentDefinition { + public final Argument argument; + public final Class sourceClass; + public final Field sourceField; + + /** + * Creates a new argument definition. + * @param argument Attributes of the argument, read from the source field. + * @param sourceClass Source class for the argument, provided to the ParsingEngine. + * @param sourceField Source field for the argument, extracted from the sourceClass. + */ + public ArgumentDefinition( Argument argument, Class sourceClass, Field sourceField ) { + this.argument = argument; + this.sourceClass = sourceClass; + this.sourceField = sourceField; + } + +} diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentMatches.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentMatches.java new file mode 100755 index 000000000..07397192c --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentMatches.java @@ -0,0 +1,55 @@ +package org.broadinstitute.sting.utils.cmdLine; + +import java.util.Set; +import java.util.HashSet; +import java.util.Iterator; /** + * Created by IntelliJ IDEA. + * User: mhanna + * Date: May 3, 2009 + * Time: 6:36:43 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. + */ + +/** + * Represents a list of potential matches between the arguments defined + * by the argument sources and the arguments passed in via the command line. + */ +public class ArgumentMatches implements Iterable { + /** + * Collection matches from argument definition to argument value. + * Package protected access is deliberate. + */ + Set argumentMatches = new HashSet(); + + void add( ArgumentDefinition definition, String value ) { + argumentMatches.add( new ArgumentMatch( definition, value ) ); + } + + /** + * Get an iterator cycling through command-line argument <-> definition matches. + * @return Iterator over all argument matches. + */ + public Iterator iterator() { + return argumentMatches.iterator(); + } +} + +/** + * An individual match from argument definition to argument value. + */ +class ArgumentMatch { + public final ArgumentDefinition definition; + public final String value; + + public ArgumentMatch( ArgumentDefinition definition, String value ) { + this.definition = definition; + this.value = value; + } +} \ No newline at end of file diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentParser.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentParser.java index baba87ea0..b72ca6f56 100644 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentParser.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentParser.java @@ -283,7 +283,7 @@ public class ArgumentParser { parser.parse(m_options, args, false); } catch( ParseException e ) { - boolean isIncomplete = e instanceof MissingArgumentException || + boolean isIncomplete = e instanceof org.apache.commons.cli.MissingArgumentException || e instanceof MissingOptionException || e instanceof UnrecognizedOptionException; diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java new file mode 100755 index 000000000..bbb239ad2 --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java @@ -0,0 +1,100 @@ +package org.broadinstitute.sting.utils.cmdLine; + +import org.broadinstitute.sting.utils.StingException; + +import java.lang.reflect.Field; +import java.util.Set; + +/** + * Created by IntelliJ IDEA. + * User: mhanna + * Date: May 3, 2009 + * Time: 4:35:25 PM + * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT + * Software and documentation are copyright 2005 by the Broad Institute. + * All rights are reserved. + * + * Users acknowledge that this software is supplied without any warranty or support. + * The Broad Institute is not responsible for its use, misuse, or + * functionality. + */ + +/** + * A parser for Sting command-line arguments. + */ +public class ParsingEngine { + /** + * A list of defined arguments against which command lines are matched. + */ + private ArgumentDefinitions argumentDefinitions = new ArgumentDefinitions(); + + /** + * Add an argument source. Argument sources are expected to have + * any number of fields with an @Argument annotation attached. + * @param sources A list of argument sources from which to extract + * command-line arguments. + */ + public void addArgumentSources( Class... sources ) { + for( Class source: sources ) { + Field[] fields = source.getFields(); + for( Field field: fields ) { + Argument argument = field.getAnnotation(Argument.class); + if(argument != null) + argumentDefinitions.add( argument, source, field ); + } + } + } + + /** + * Parse the given set of command-line arguments, returning + * an ArgumentMatches object describing the best fit of these + * command-line arguments to the arguments that are actually + * required. + * @param arguments Command-line arguments. + * @return A object indicating which matches are best. Might return + * an empty object, but will never return null. + */ + public ArgumentMatches parse( String[] arguments ) { + ArgumentMatches argumentMatches = new ArgumentMatches(); + + for( int i = 0; i < arguments.length; i++ ) { + String argument = arguments[i].trim(); + if( argument.startsWith("-") ) { + String shortName = argument.substring(1); + if( argumentDefinitions.hasArgumentWithShortName(shortName) ) { + ArgumentDefinition definition = argumentDefinitions.getArgumentWithShortName(shortName); + argumentMatches.add( definition, arguments[i+1].trim() ); + } + } + } + + return argumentMatches; + } + + /** + * Validates the list of command-line argument matches. On + * failure ...TBD... + */ + public void validate( ArgumentMatches argumentMatches ) { + + } + + /** + * Loads a set of matched command-line arguments into the given object. + * @param object Object into which to add arguments. + * @param argumentMatches List of matches. + */ + public void loadArgumentsIntoObject( Object object, ArgumentMatches matches ) { + for( ArgumentMatch match: matches ) { + if( object.getClass().equals(match.definition.sourceClass) ) { + try { + match.definition.sourceField.set( object, match.value ); + } + catch( IllegalAccessException ex ) { + //logger.fatal("processArgs: cannot convert field " + field.toString()); + throw new StingException("processArgs: Failed conversion " + ex.getMessage(), ex); + } + } + } + } +} diff --git a/java/test/org/broadinstitute/sting/utils/cmdLine/ParsingEngineTest.java b/java/test/org/broadinstitute/sting/utils/cmdLine/ParsingEngineTest.java new file mode 100755 index 000000000..7325ea5ce --- /dev/null +++ b/java/test/org/broadinstitute/sting/utils/cmdLine/ParsingEngineTest.java @@ -0,0 +1,74 @@ +package org.broadinstitute.sting.utils.cmdLine; + +import org.broadinstitute.sting.BaseTest; +import org.junit.Test; +import org.junit.Before; +import org.junit.Assert; +/** + * Created by IntelliJ IDEA. + * User: mhanna + * Date: May 3, 2009 + * Time: 6:05:33 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. + */ +/** + * Test suite for the parsing engine. + */ +public class ParsingEngineTest extends BaseTest { + private ParsingEngine parsingEngine; + + @Before + public void setUp() { + parsingEngine = new ParsingEngine(); + } + + private class InputFileArgProvider { + @Argument(fullName="input_file",shortName="I") + public String inputFile; + } + + @Test + public void shortNameArgumentTest() { + final String[] commandLine = new String[] {"-I","na12878.bam"}; + + parsingEngine.addArgumentSources( InputFileArgProvider.class ); + ArgumentMatches argumentMatches = parsingEngine.parse( commandLine ); + parsingEngine.validate(argumentMatches); + + InputFileArgProvider argProvider = new InputFileArgProvider(); + parsingEngine.loadArgumentsIntoObject( argProvider, argumentMatches); + + Assert.assertEquals("Argument is not correctly initialized", "na12878.bam", argProvider.inputFile ); + } + + // To test + // 'Composite' short names + // long names + // flags + // flags with arguments at every point on the line + // flags with arguments at the end of the line + + /* + @Test + public void shortNameCompositeArgumentTest() { + final String[] commandLine = new String[] {"-I na12878.bam"}; + + parsingEngine.addArgumentSources( InputFileArgProvider.class ); + ArgumentMatches argumentMatches = parsingEngine.parse( commandLine ); + parsingEngine.validate(argumentMatches); + + InputFileArgProvider argProvider = new InputFileArgProvider(); + parsingEngine.loadArgumentsIntoObject( argProvider, argumentMatches); + + Assert.assertEquals("Argument is not correctly initialized", "na12878.bam" ); + } + */ + +}