diff --git a/java/src/org/broadinstitute/sting/commandline/ArgumentDefinition.java b/java/src/org/broadinstitute/sting/commandline/ArgumentDefinition.java index 985645a8d..227588edb 100644 --- a/java/src/org/broadinstitute/sting/commandline/ArgumentDefinition.java +++ b/java/src/org/broadinstitute/sting/commandline/ArgumentDefinition.java @@ -25,8 +25,10 @@ package org.broadinstitute.sting.commandline; +import org.broadinstitute.sting.utils.StingException; import org.broadinstitute.sting.utils.Utils; +import java.lang.annotation.Annotation; import java.util.List; /** @@ -118,6 +120,75 @@ public class ArgumentDefinition { this.validOptions = validOptions; } + /** + * Creates a new argument definition. + * @param annotation The annotation on the field. + * @param defaultFullName Default full name for this argument definition. + * @param defaultShortName Default short name for this argument definition. + * @param isFlag Whether or not this argument should be treated as a flag. + * @param isMultiValued Whether or not this argument supports multiple values. + * @param validOptions is there a particular list of options that's valid for this argument definition? List them if so, otherwise set this to null. + */ + public ArgumentDefinition( Annotation annotation, + String defaultFullName, + String defaultShortName, + boolean isFlag, + boolean isMultiValued, + List validOptions) { + + String fullName = (String)getValue(annotation, "fullName"); + String shortName = (String)getValue(annotation, "shortName"); + boolean isFullNameProvided = fullName.trim().length() > 0; + boolean isShortNameProvided = shortName.trim().length() > 0; + + fullName = isFullNameProvided ? fullName.trim() : defaultFullName; + + // If the short name is provided, use that. If the user hasn't provided any names at all, use + // the default. If somewhere in the middle, leave the short name blank. + if( isShortNameProvided ) + shortName = shortName.trim(); + else if( !isFullNameProvided ) + shortName = defaultShortName; + else + shortName = null; + + this.ioType = getIOType(annotation); + this.fullName = fullName; + this.shortName = shortName; + this.doc = getDoc(annotation); + this.required = isRequired(annotation, isFlag); + this.isFlag = isFlag; + this.isMultiValued = isMultiValued; + this.exclusiveOf = getExclusiveOf(annotation); + this.validation = getValidationRegex(annotation); + this.validOptions = validOptions; + } + + /** + * Creates a new argument definition. + * @param annotation The annotation on the field. + * @param fieldName Default full name for this argument definition. + * @param isFlag Whether or not this argument should be treated as a flag. + * @param isMultiValued Whether or not this argument supports multiple values. + * @param validOptions is there a particular list of options that's valid for this argument definition? List them if so, otherwise set this to null. + */ + public ArgumentDefinition( Annotation annotation, + String fieldName, + boolean isFlag, + boolean isMultiValued, + List validOptions) { + this.ioType = getIOType(annotation); + this.fullName = getFullName(annotation, fieldName); + this.shortName = getShortName(annotation); + this.doc = getDoc(annotation); + this.required = isRequired(annotation, isFlag); + this.isFlag = isFlag; + this.isMultiValued = isMultiValued; + this.exclusiveOf = getExclusiveOf(annotation); + this.validation = getValidationRegex(annotation); + this.validOptions = validOptions; + } + @Override public int hashCode() { int hashCode = fullName.hashCode(); @@ -136,4 +207,92 @@ public class ArgumentDefinition { return Utils.equals(fullName,other.fullName) && Utils.equals(shortName,other.shortName); } + + /** + * Returns the ArgumentIOType for the annotation. + * @param annotation @Input or @Output + * @return ArgumentIOType.Input, Output, or Unknown + */ + public static ArgumentIOType getIOType(Annotation annotation) { + if (annotation instanceof Input) return ArgumentIOType.INPUT; + if (annotation instanceof Output) return ArgumentIOType.OUTPUT; + return ArgumentIOType.UNKNOWN; + } + + /** + * A hack to get around the fact that Java doesn't like inheritance in Annotations. + * @param annotation to run the method on + * @param method the method to invoke + * @return the return value of the method + */ + private static Object getValue(Annotation annotation, String method) { + try { + return annotation.getClass().getMethod(method).invoke(annotation); + } catch (Exception e) { + throw new StingException("Unable to access method " + method + " on annotation " + annotation.getClass(), e); + } + } + + /** + * Retrieves the full name of the argument, specifiable with the '--' prefix. The full name can be + * either specified explicitly with the fullName annotation parameter or implied by the field name. + * @param annotation Original field annotation. + * @param fieldName Original field name. + * @return full name of the argument. Never null. + */ + private static String getFullName( Annotation annotation, String fieldName ) { + String fullName = (String)getValue(annotation, "fullName"); + return fullName.trim().length() > 0 ? fullName.trim() : fieldName.toLowerCase(); + } + + /** + * Retrieves the short name of the argument, specifiable with the '-' prefix. The short name can + * be specified or not; if left unspecified, no short name will be present. + * @param annotation Original field annotation. + * @return short name of the argument. Null if no short name exists. + */ + private static String getShortName( Annotation annotation ) { + String shortName = (String)getValue(annotation, "shortName"); + return shortName.trim().length() > 0 ? shortName.trim() : null; + } + + /** + * Documentation for this argument. Mandatory field. + * @param annotation Original field annotation. + * @return Documentation for this argument. + */ + private static String getDoc( Annotation annotation ) { + return (String)getValue(annotation, "doc"); + } + + /** + * Returns whether this field is required. Note that flag fields are always forced to 'not required'. + * @param annotation Original field annotation. + * @param isFlag True if the field is a flag. + * @return True if the field is mandatory and not a boolean flag. False otherwise. + */ + private static boolean isRequired( Annotation annotation, boolean isFlag ) { + boolean required = (Boolean)getValue(annotation, "required"); + return required && !isFlag; + } + + /** + * Specifies other arguments which cannot be used in conjunction with this argument. Comma-separated list. + * @param annotation Original field annotation. + * @return A comma-separated list of exclusive arguments, or null if none are present. + */ + private static String getExclusiveOf( Annotation annotation ) { + String exclusiveOf = (String)getValue(annotation, "exclusiveOf"); + return exclusiveOf.trim().length() > 0 ? exclusiveOf.trim() : null; + } + + /** + * A regular expression which can be used for validation. + * @param annotation Original field annotation. + * @return a JVM regex-compatible regular expression, or null to permit any possible value. + */ + private static String getValidationRegex( Annotation annotation ) { + String validation = (String)getValue(annotation, "validation"); + return validation.trim().length() > 0 ? validation.trim() : null; + } } diff --git a/java/src/org/broadinstitute/sting/commandline/ArgumentDescription.java b/java/src/org/broadinstitute/sting/commandline/ArgumentDescription.java deleted file mode 100644 index e0e1b80c7..000000000 --- a/java/src/org/broadinstitute/sting/commandline/ArgumentDescription.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2010, The Broad Institute - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -package org.broadinstitute.sting.commandline; - -import org.broadinstitute.sting.utils.StingException; - -import java.lang.annotation.Annotation; - -/** - * Should be an interface, but java doesn't like inheritance in Annotations. - */ -public class ArgumentDescription { - private Annotation annotation; - - public ArgumentDescription(Annotation annotation) { - this.annotation = annotation; - } - - /** - * A hack to get around the fact that Java doesn't like inheritance in Annotations. - * @param method the method to invoke - * @return the return value of the method - */ - private Object invoke(String method) { - try { - return this.annotation.getClass().getMethod(method).invoke(this.annotation); - } catch (Exception e) { - throw new StingException("Unable to access method " + method + " on annotation " + annotation.getClass(), e); - } - } - - /** - * The directionality of the command-line argument. - * @return INPUT, OUTPUT, or UNKNOWN - */ - public ArgumentIOType getIOType() { - if (annotation instanceof Input) return ArgumentIOType.INPUT; - if (annotation instanceof Output) return ArgumentIOType.OUTPUT; - return ArgumentIOType.UNKNOWN; - } - - /** - * The full name of the command-line argument. Full names should be - * prefixed on the command-line with a double dash (--). - * @return Selected full name, or "" to use the default. - */ - public String fullName() { return (String)invoke("fullName"); } - - /** - * Specified short name of the command. Short names should be prefixed - * with a single dash. Argument values can directly abut single-char - * short names or be separated from them by a space. - * @return Selected short name, or "" for none. - */ - public String shortName() { return (String)invoke("shortName"); } - - /** - * Documentation for the command-line argument. Should appear when the - * --help argument is specified. - * @return Doc string associated with this command-line argument. - */ - public String doc() { return (String)invoke("doc"); } - - /** - * Is this command-line argument required. The application should exit - * printing help if this command-line argument is not specified. - * @return True if the argument is required. False otherwise. - */ - public boolean required() { return (Boolean)invoke("required"); } - - /** - * Should this command-line argument be exclusive of others. Should be - * a comma-separated list of names of arguments of which this should be - * independent. - * @return A comma-separated string listing other arguments of which this - * argument should be independent. - */ - public String exclusiveOf() { return (String)invoke("exclusiveOf"); } - - /** - * Provide a regexp-based validation string. - * @return Non-empty regexp for validation, blank otherwise. - */ - public String validation() { return (String)invoke("validation"); } -} diff --git a/java/src/org/broadinstitute/sting/commandline/ArgumentTypeDescriptor.java b/java/src/org/broadinstitute/sting/commandline/ArgumentTypeDescriptor.java index ffcca6b68..12da5f2a2 100644 --- a/java/src/org/broadinstitute/sting/commandline/ArgumentTypeDescriptor.java +++ b/java/src/org/broadinstitute/sting/commandline/ArgumentTypeDescriptor.java @@ -28,6 +28,7 @@ package org.broadinstitute.sting.commandline; import org.broadinstitute.sting.utils.StingException; import org.apache.log4j.Logger; +import java.lang.annotation.Annotation; import java.lang.reflect.*; import java.util.*; @@ -122,91 +123,15 @@ public abstract class ArgumentTypeDescriptor { * @return The default definition for this argument source. */ protected ArgumentDefinition createDefaultArgumentDefinition( ArgumentSource source ) { - return new ArgumentDefinition( getIOType(source), - getFullName(source), - getShortName(source), - getDoc(source), - isRequired(source), + return new ArgumentDefinition( getArgumentAnnotation(source), + source.field.getName(), source.isFlag(), source.isMultiValued(), - getExclusiveOf(source), - getValidationRegex(source), getValidOptions(source) ); } public abstract Object parse( ArgumentSource source, Class type, ArgumentMatches matches ); - /** - * Specifies other arguments which cannot be used in conjunction with tihs argument. Comma-separated list. - * @param source Original field specifying command-line arguments. - * @return A comma-separated list of exclusive arguments, or null if none are present. - */ - protected ArgumentIOType getIOType( ArgumentSource source ) { - ArgumentDescription description = getArgumentDescription(source); - return description.getIOType(); - } - - /** - * Retrieves the full name of the argument, specifiable with the '--' prefix. The full name can be - * either specified explicitly with the fullName annotation parameter or implied by the field name. - * @param source Original field specifying command-line arguments. - * @return full name of the argument. Never null. - */ - protected String getFullName( ArgumentSource source ) { - ArgumentDescription description = getArgumentDescription(source); - return description.fullName().trim().length() > 0 ? description.fullName().trim() : source.field.getName().toLowerCase(); - } - - /** - * Retrieves the short name of the argument, specifiable with the '-' prefix. The short name can - * be specified or not; if left unspecified, no short name will be present. - * @param source Original field specifying command-line arguments. - * @return short name of the argument. Null if no short name exists. - */ - protected String getShortName( ArgumentSource source ) { - ArgumentDescription description = getArgumentDescription(source); - return description.shortName().trim().length() > 0 ? description.shortName().trim() : null; - } - - /** - * Documentation for this argument. Mandatory field. - * @param source Original field specifying command-line arguments. - * @return Documentation for this argument. - */ - protected String getDoc( ArgumentSource source ) { - ArgumentDescription description = getArgumentDescription(source); - return description.doc(); - } - - /** - * Returns whether this field is required. Note that flag fields are always forced to 'not required'. - * @param source Original field specifying command-line arguments. - * @return True if the field is mandatory and not a boolean flag. False otherwise. - */ - protected boolean isRequired( ArgumentSource source ) { - ArgumentDescription description = getArgumentDescription(source); - return description.required() && !source.isFlag(); - } - - /** - * Specifies other arguments which cannot be used in conjunction with tihs argument. Comma-separated list. - * @param source Original field specifying command-line arguments. - * @return A comma-separated list of exclusive arguments, or null if none are present. - */ - protected String getExclusiveOf( ArgumentSource source ) { - ArgumentDescription description = getArgumentDescription(source); - return description.exclusiveOf().trim().length() > 0 ? description.exclusiveOf().trim() : null; - } - - /** - * A regular expression which can be used for validation. - * @param source Original field specifying command-line arguments. - * @return a JVM regex-compatible regular expression, or null to permit any possible value. - */ - protected String getValidationRegex( ArgumentSource source ) { - ArgumentDescription description = getArgumentDescription(source); - return description.validation().trim().length() > 0 ? description.validation().trim() : null; - } /** * If the argument source only accepts a small set of options, populate the returned list with @@ -259,15 +184,15 @@ public abstract class ArgumentTypeDescriptor { * @return Argument description annotation associated with the given field. */ @SuppressWarnings("unchecked") - protected ArgumentDescription getArgumentDescription( ArgumentSource source ) { + protected Annotation getArgumentAnnotation( ArgumentSource source ) { for (Class annotation: ARGUMENT_ANNOTATIONS) if (source.field.isAnnotationPresent(annotation)) - return new ArgumentDescription(source.field.getAnnotation(annotation)); + return source.field.getAnnotation(annotation); throw new StingException("ArgumentAnnotation is not present for the argument field: " + source.field.getName()); } @SuppressWarnings("unchecked") - public static boolean isArgumentDescriptionPresent(Field field) { + public static boolean isArgumentAnnotationPresent(Field field) { for (Class annotation: ARGUMENT_ANNOTATIONS) if (field.isAnnotationPresent(annotation)) return true; diff --git a/java/src/org/broadinstitute/sting/commandline/ParsingEngine.java b/java/src/org/broadinstitute/sting/commandline/ParsingEngine.java index 52d8b1a59..2055faea9 100755 --- a/java/src/org/broadinstitute/sting/commandline/ParsingEngine.java +++ b/java/src/org/broadinstitute/sting/commandline/ParsingEngine.java @@ -308,7 +308,7 @@ public class ParsingEngine { while( sourceClass != null ) { Field[] fields = sourceClass.getDeclaredFields(); for( Field field: fields ) { - if( ArgumentTypeDescriptor.isArgumentDescriptionPresent(field) ) + if( ArgumentTypeDescriptor.isArgumentAnnotationPresent(field) ) argumentSources.add( new ArgumentSource(sourceClass,field) ); if( field.isAnnotationPresent(ArgumentCollection.class) ) argumentSources.addAll( extractArgumentSources(field.getType()) ); diff --git a/java/src/org/broadinstitute/sting/gatk/io/stubs/GenotypeWriterArgumentTypeDescriptor.java b/java/src/org/broadinstitute/sting/gatk/io/stubs/GenotypeWriterArgumentTypeDescriptor.java index b207655c5..48848c0a0 100644 --- a/java/src/org/broadinstitute/sting/gatk/io/stubs/GenotypeWriterArgumentTypeDescriptor.java +++ b/java/src/org/broadinstitute/sting/gatk/io/stubs/GenotypeWriterArgumentTypeDescriptor.java @@ -32,6 +32,7 @@ import org.broadinstitute.sting.utils.genotype.GenotypeWriterFactory; import org.broadinstitute.sting.gatk.GenomeAnalysisEngine; import java.io.File; +import java.lang.annotation.Annotation; import java.util.List; import java.util.Arrays; @@ -154,32 +155,13 @@ public class GenotypeWriterArgumentTypeDescriptor extends ArgumentTypeDescriptor * @return Argument definition for the BAM file itself. Will not be null. */ private ArgumentDefinition createGenotypeFileArgumentDefinition(ArgumentSource source) { - ArgumentDescription description = this.getArgumentDescription(source); + Annotation annotation = this.getArgumentAnnotation(source); - boolean isFullNameProvided = description.fullName().trim().length() > 0; - boolean isShortNameProvided = description.shortName().trim().length() > 0; - - String fullName = isFullNameProvided ? description.fullName().trim() : "variants_out"; - - // If the short name is provided, use that. If the user hasn't provided any names at all, use - // the default. If somewhere in the middle, leave the short name blank. - String shortName; - if( isShortNameProvided ) - shortName = description.shortName().trim(); - else if( !isFullNameProvided ) - shortName = "varout"; - else - shortName = null; - - return new ArgumentDefinition( getIOType(source), - fullName, - shortName, - getDoc(source), - isRequired(source), + return new ArgumentDefinition( annotation, + "variants_out", + "varout", false, source.isMultiValued(), - getExclusiveOf(source), - getValidationRegex(source), null ); } @@ -189,7 +171,8 @@ public class GenotypeWriterArgumentTypeDescriptor extends ArgumentTypeDescriptor * @return Argument definition for the BAM file itself. Will not be null. */ private ArgumentDefinition createGenotypeFormatArgumentDefinition(ArgumentSource source) { - return new ArgumentDefinition( getIOType(source), + Annotation annotation = this.getArgumentAnnotation(source); + return new ArgumentDefinition( ArgumentDefinition.getIOType(annotation), "variant_output_format", "vf", "Format to be used to represent variants; default is VCF", diff --git a/java/src/org/broadinstitute/sting/gatk/io/stubs/SAMFileWriterArgumentTypeDescriptor.java b/java/src/org/broadinstitute/sting/gatk/io/stubs/SAMFileWriterArgumentTypeDescriptor.java index f6fd39107..9d538e562 100644 --- a/java/src/org/broadinstitute/sting/gatk/io/stubs/SAMFileWriterArgumentTypeDescriptor.java +++ b/java/src/org/broadinstitute/sting/gatk/io/stubs/SAMFileWriterArgumentTypeDescriptor.java @@ -31,6 +31,7 @@ import org.broadinstitute.sting.gatk.GenomeAnalysisEngine; import org.broadinstitute.sting.gatk.io.StingSAMFileWriter; import net.sf.samtools.SAMFileWriter; +import java.lang.annotation.Annotation; import java.util.List; import java.util.Arrays; import java.io.File; @@ -94,32 +95,12 @@ public class SAMFileWriterArgumentTypeDescriptor extends ArgumentTypeDescriptor * @return Argument definition for the BAM file itself. Will not be null. */ private ArgumentDefinition createBAMArgumentDefinition(ArgumentSource source) { - ArgumentDescription description = this.getArgumentDescription(source); - - boolean isFullNameProvided = description.fullName().trim().length() > 0; - boolean isShortNameProvided = description.shortName().trim().length() > 0; - - String fullName = isFullNameProvided ? description.fullName().trim() : DEFAULT_ARGUMENT_FULLNAME; - - // If the short name is provided, use that. If the user hasn't provided any names at all, use - // the default. If somewhere in the middle, leave the short name blank. - String shortName; - if( isShortNameProvided ) - shortName = description.shortName().trim(); - else if( !isFullNameProvided ) - shortName = DEFAULT_ARGUMENT_SHORTNAME; - else - shortName = null; - - return new ArgumentDefinition( getIOType(source), - fullName, - shortName, - getDoc(source), - isRequired(source), + Annotation annotation = this.getArgumentAnnotation(source); + return new ArgumentDefinition( annotation, + DEFAULT_ARGUMENT_FULLNAME, + DEFAULT_ARGUMENT_SHORTNAME, false, source.isMultiValued(), - getExclusiveOf(source), - getValidationRegex(source), null ); } @@ -129,7 +110,8 @@ public class SAMFileWriterArgumentTypeDescriptor extends ArgumentTypeDescriptor * @return Argument definition for the BAM file itself. Will not be null. */ private ArgumentDefinition createBAMCompressionArgumentDefinition(ArgumentSource source) { - return new ArgumentDefinition( getIOType(source), + Annotation annotation = this.getArgumentAnnotation(source); + return new ArgumentDefinition( ArgumentDefinition.getIOType(annotation), COMPRESSION_FULLNAME, COMPRESSION_SHORTNAME, "Compression level to use for writing BAM files", diff --git a/scala/src/org/broadinstitute/sting/queue/QCommandLine.scala b/scala/src/org/broadinstitute/sting/queue/QCommandLine.scala index 79f030070..f59ea960b 100755 --- a/scala/src/org/broadinstitute/sting/queue/QCommandLine.scala +++ b/scala/src/org/broadinstitute/sting/queue/QCommandLine.scala @@ -6,7 +6,7 @@ import collection.mutable.ListBuffer import org.broadinstitute.sting.queue.util.Logging object QCommandLine extends Application with Logging { - var usage = """usage: java -jar Queue.jar [ -P name=value ] [ -P file.properties ] [ -I input.file ] [ -I input_files.list ] [ -bsub ] [ -dry ] [ -debug ] -S pipeline.scala""" + var usage = """usage: java -jar Queue.jar [-P name=value] [-P file.properties] [-I input.file] [-I input_files.list] [-bsub] [-bsubWait] [-dry] [-debug] -S pipeline.scala""" override def main(args: Array[String]) = { val qArgs: QArguments = try {