/* * 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.exceptions.ReviewedStingException; import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; /** * Describes the source field which defines a command-line argument. * A parsed-object version of the command-line argument will be * injected into an object containing this field. * * @author mhanna * @version 0.1 */ public class ArgumentSource { /** * Field into which to inject command-line arguments. */ public final Field[] parentFields; /** * Field into which to inject command-line arguments. */ public final Field field; /** * Type descriptor to use when parsing new argument types. */ private final ArgumentTypeDescriptor typeDescriptor; /** * Create a new command-line argument target. * @param parentFields Parent fields containing the the field. Field must be annotated with 'ArgumentCollection'. * @param field Field containing the argument. Field must be annotated with 'Input' or 'Output'. * @param typeDescriptor custom type descriptor to use when parsing. */ protected ArgumentSource( Field[] parentFields, Field field, ArgumentTypeDescriptor typeDescriptor) { this.parentFields = parentFields; this.field = field; this.typeDescriptor = typeDescriptor; } /** * Somewhat hackish copy constructor to track fields with a custom type descriptor. * TODO: Separate type descriptor from ArgumentSource in general usage. * @param typeDescriptor New type descriptor for the object. */ public ArgumentSource copyWithCustomTypeDescriptor(final ArgumentTypeDescriptor typeDescriptor) { return new ArgumentSource(parentFields,field,typeDescriptor); } /** * True if this argument source equals other. * @param other Another object, possibly an argument source, to test for equality. Any object can * be tested, but only instances of ArgumentSource will result in equals returning true. * @return True if this argument source matches other. False otherwise. */ @Override public boolean equals( Object other ) { if( other == null ) return false; if( !(other instanceof ArgumentSource) ) return false; ArgumentSource otherArgumentSource = (ArgumentSource)other; return this.field == otherArgumentSource.field && Arrays.equals(this.parentFields, otherArgumentSource.parentFields); } /** * Returns an appropriate hash code for this argument source. * @return A uniformly distributed hashcode representing this argument source. */ @Override public int hashCode() { return field.hashCode(); } /** * Generate a list of all argument definitions to which this argument source maps. * @return A non-null, non-empty list of argument definitions. */ public List createArgumentDefinitions() { return typeDescriptor.createArgumentDefinitions( this ); } /** * Parses the specified value based on the specified type. * @param values String representation of all values passed. * @return the parsed value of the object. */ public Object parse( ParsingEngine parsingEngine, ArgumentMatches values ) { return typeDescriptor.parse( parsingEngine, this, values ); } /** * Returns whether this field is required. Note that flag fields are always forced to 'not required'. * @return True if the field is mandatory and not a boolean flag. False otherwise. */ public boolean isRequired() { return (Boolean)CommandLineUtils.getValue(ArgumentTypeDescriptor.getArgumentAnnotation(this),"required"); } /** * Returns true if the argument is a flag (a 0-valued argument). * @return True if argument is a flag; false otherwise. */ public boolean isFlag() { return (field.getType() == Boolean.class) || (field.getType() == Boolean.TYPE); } /** * Can this argument support multiple values, or just one? * @return True if the argument supports multiple values. */ public boolean isMultiValued() { return typeDescriptor.isMultiValued( this ); } /** * Should the given class be hidden from the command-line argument system. * @return True if so. False otherwise. */ public boolean isHidden() { return field.isAnnotationPresent(Hidden.class) || field.isAnnotationPresent(Deprecated.class); } /** * Is this command-line argument dependent on some primitive argument types? * @return True if this command-line argument depends on other arguments; false otherwise. */ public boolean isDependent() { return typeDescriptor instanceof MultiplexArgumentTypeDescriptor; } /** * Returns whether the field has been deprecated and should no longer be used. * @return True if field has been deprecated. */ public boolean isDeprecated() { return field.isAnnotationPresent(Deprecated.class); } /** * Returns false if a type-specific default can be employed. * @return True to throw in a type specific default. False otherwise. */ public boolean createsTypeDefault() { return typeDescriptor.createsTypeDefault(this); } /** * Generates a default for the given type. * @param parsingEngine the parsing engine used to validate this argument type descriptor. * @return A default value for the given type. */ public Object createTypeDefault(ParsingEngine parsingEngine) { return typeDescriptor.createTypeDefault(parsingEngine,this,field.getType()); } /** * Builds out a new type descriptor for the given dependent argument as a function * of the containing object. * @param parsingEngine the parsing engine to use when building out this custom type descriptor. * @param containingObject The containing object. * @return An argument type descriptor for the custom derivative field. */ public MultiplexArgumentTypeDescriptor createDependentTypeDescriptor(ParsingEngine parsingEngine,Object containingObject) { if(!isDependent()) throw new ReviewedStingException("Field " + field.getName() + " is independent; no dependent type descriptor can be derived."); return ((MultiplexArgumentTypeDescriptor)typeDescriptor).createCustomTypeDescriptor(parsingEngine,this,containingObject); } /** * Gets a string representation of the argument source for debugging. * @return String representation of the argument source. */ public String toString() { return field.getDeclaringClass().getSimpleName() + ": " + field.getName(); } }