All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.biojava.nbio.structure.align.util.CliTools Maven / Gradle / Ivy

There is a newer version: 7.1.3
Show newest version
/*
 *                    BioJava development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  If you do not have a copy,
 * see:
 *
 *      http://www.gnu.org/copyleft/lesser.html
 *
 * Copyright for this code is held jointly by the individual
 * authors.  These should be listed in @author doc comments.
 *
 * For more information on the BioJava project and its aims,
 * or to join the biojava-l mailing list, visit the home page
 * at:
 *
 *      http://www.biojava.org/
 *
 */
/*
 *                  BioJava development code
 *
 * Copyright for this code is held jointly by the individual
 * authors.  These should be listed in @author doc comments.
 *
 * For more information on the BioJava project and its aims,
 * or to join the biojava-l mailing list, visit the home page
 * at:
 *
 *      http://www.biojava.org/
 *
 */

package org.biojava.nbio.structure.align.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * Utilities for autoconfiguring javabeans based on command line arguments.
 *
 * @author Thomas Down
 */

public class CliTools {
	private CliTools() {
	}


	/**
	 * Configure a JavaBean based on a set of command line arguments.
	 * For a command line construct such as "-foo 42", this method will use
	 * available BeanInfo (usually obtained by introspection)
	 * to find a property named "foo".  The argument will be interpreted
	 * according to the type of the "foo" property, then the appropriate
	 * mutator method (generally named setFoo) will be called to configure
	 * the property on the bean.
	 *
	 * 

* Currently supported property types are int, double, * boolean, String, File, Reader, Writer, InputStream, OutputStream, Enum, * plus arrays of all the above types. In the case of arrays, the option * may appear multiple times on the command line, otherwise recurrance of * the same option is an error. *

* *

* For stream types, the parameter is interpreted as a filename unless it * is equal to "-" in which case standard input or standard output are * used as appropriate. Each of the standard streams may only be used * one. *

* *

* In the future, this method will probably be extended to handle multiple * parameter occurances, and use Annotations to generate more useful help * messages when something goes wrong. *

* * @param bean * @param args * @return A string array which contains any 'anonymous' arguments (may be empty) * @throws ConfigurationException */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static String[] configureBean(Object bean, String[] args) throws ConfigurationException { BeanInfo bi; try { bi = Introspector.getBeanInfo(bean.getClass()); } catch (Exception ex) { throw new ConfigurationException("Couldn't get information for target bean " + ex.getMessage()); } Map propertiesByName = new HashMap<>(); for (PropertyDescriptor pd : bi.getPropertyDescriptors() ) { propertiesByName.put(pd.getName(), pd); } List anonArgs = new ArrayList<>(); Map> arrayProps = new HashMap<>(); Set usedProps = new HashSet<>(); boolean stdInUsed = false; boolean stdOutUsed = false; for (int i = 0; i < args.length; ++i) { String arg = args[i]; //System.out.println("checking argument: " + arg); if ( arg == null) continue; if ((arg.length() > 0 ) && arg.charAt(0) == '-') { PropertyDescriptor pd = propertiesByName.get(arg.substring(1)); boolean arrayMode = false; Object propVal = null; Class propType = null; if (pd == null) { if (arg.startsWith("-no")) { String altPropName = Introspector.decapitalize(arg.substring(3)); pd = propertiesByName.get(altPropName); if (pd == null) { throw new ConfigurationException("No property named " + arg.substring(1) + " or " + altPropName); } propType = pd.getPropertyType(); if (propType == Boolean.TYPE) { propVal = Boolean.FALSE; } else { throw new ConfigurationException("Negatory option " + arg + " does not refer to a boolean property"); } } else { throw new ConfigurationException("No property named " + arg.substring(1)); } } else { propType = pd.getPropertyType(); if (propType.isArray()) { arrayMode = true; propType = propType.getComponentType(); } if (propType == Integer.TYPE) { try { propVal = Integer.valueOf(args[++i]); } catch (Exception ex) { throw new ConfigurationException("Option " + arg + " requires an integer parameter"); } } else if (propType == Double.TYPE || propType == Double.class ) { try { propVal = Double.valueOf(args[++i]); } catch (Exception ex) { throw new ConfigurationException("Option " + arg + " requires a numerical parameter"); } } else if (propType == String.class) { propVal = args[++i]; } else if (propType == Boolean.TYPE) { String val = args[++i]; if ( val == null ) propVal = Boolean.TRUE; else { if ( "true".equalsIgnoreCase(val) || "t".equalsIgnoreCase(val)) propVal = Boolean.TRUE; else if( "false".equalsIgnoreCase(val) || "f".equalsIgnoreCase(val)) propVal = Boolean.FALSE; else throw new ConfigurationException("Option "+arg+" requires a boolean parameter"); } } else if (File.class.isAssignableFrom(propType)) { // can't distinguish if the file is for reading or writing // at the moment, so accept it without validation. propVal = new File(args[++i]); } else if (Reader.class.isAssignableFrom(propType)) { String name = args[++i]; if ("-".equals(name)) { if (stdInUsed) { throw new ConfigurationException("Can't use standard input more than once"); } propVal = new InputStreamReader(System.in); stdInUsed = true; } else { try { propVal = new FileReader(new File(name)); } catch (Exception ex) { throw new ConfigurationException("Can't open " + name + " for input"); } } } else if (InputStream.class.isAssignableFrom(propType)) { String name = args[++i]; if ("-".equals(name)) { if (stdInUsed) { throw new ConfigurationException("Can't use standard input more than once"); } propVal = System.in; stdInUsed = true; } else { try { propVal = new FileInputStream(new File(name)); } catch (Exception ex) { throw new ConfigurationException("Can't open " + name + " for input"); } } } else if (Writer.class.isAssignableFrom(propType)) { String name = args[++i]; if ("-".equals(name)) { if (stdOutUsed) { throw new ConfigurationException("Can't use standard output more than once"); } propVal = new OutputStreamWriter(System.out); stdOutUsed = true; } else { try { propVal = new FileWriter(new File(name)); } catch (Exception ex) { throw new ConfigurationException("Can't open " + name + " for output"); } } } else if (OutputStream.class.isAssignableFrom(propType)) { String name = args[++i]; if ("-".equals(name)) { if (stdOutUsed) { throw new ConfigurationException("Can't use standard output more than once"); } propVal = System.out; stdOutUsed = true; } else { try { propVal = new FileOutputStream(new File(name)); } catch (Exception ex) { throw new ConfigurationException("Can't open " + name + " for output"); } } } else if( propType.isEnum()) { String name = args[++i]; try { propVal = Enum.valueOf(propType, name); } catch (Exception ex) { try { // Try with uppercase version, as common for enums propVal = Enum.valueOf(propType, name.toUpperCase()); } catch (Exception ex2) { //give up StringBuilder errMsg = new StringBuilder(); errMsg.append("Option ").append(arg); errMsg.append(" requires a ").append(propType.getSimpleName()); errMsg.append(" parameter. One of: "); for(Object val: propType.getEnumConstants() ) { Enum enumVal = (Enum) val; errMsg.append(enumVal.name()); errMsg.append(" "); } throw new ConfigurationException(errMsg.toString()); } } } else { System.err.println("Unsupported optionType for " + arg + " propType:" + propType); System.exit(1); } } //System.out.println("setting to: " + propVal + " " + propVal.getClass().getName()); if (arrayMode) { List valList = arrayProps.get(pd); if (valList == null) { valList = new ArrayList(); arrayProps.put(pd, valList); } valList.add(propVal); } else { if (usedProps.contains(pd)) { throw new ConfigurationException("Multiple values supplied for " + pd.getName()); } try { pd.getWriteMethod().invoke(bean, new Object[] {propVal}); } catch (InvocationTargetException ex) { throw new ConfigurationException("Error configuring '" + pd.getName() + "'"); } catch (Exception ex) { throw new ConfigurationException("Error configuring '" + pd.getName() + "'"); } usedProps.add(pd); } } else { anonArgs.add(arg); } } for (Iterator api = arrayProps.entrySet().iterator(); api.hasNext(); ) { Map.Entry me = (Map.Entry) api.next(); PropertyDescriptor pd = (PropertyDescriptor) me.getKey(); List vals = (List) me.getValue(); Class compType = pd.getPropertyType().getComponentType(); Object valArray; if (compType.isPrimitive()) { if (compType == Integer.TYPE) { valArray = CollectionTools.toIntArray(vals); } else if (compType == Double.TYPE) { valArray = CollectionTools.toDoubleArray(vals); } else { throw new ConfigurationException("Arrays of type " + compType.getName() + " are currently unsupported"); } } else { valArray = vals.toArray((Object[]) Array.newInstance(compType, vals.size())); } try { pd.getWriteMethod().invoke(bean, new Object[] {valArray}); } catch (InvocationTargetException ex) { throw new ConfigurationException("Error configuring '" + pd.getName() + "'"); } catch (Exception ex) { throw new ConfigurationException("Error configuring '" + pd.getName() + "'"); } } return anonArgs.toArray(new String[anonArgs.size()]); } /** * Constructs a comma-separated list of values for an enum. * * Example: * > getEnumValues(ScoringStrategy.class) * "CA_SCORING, SIDE_CHAIN_SCORING, SIDE_CHAIN_ANGLE_SCORING, CA_AND_SIDE_CHAIN_ANGLE_SCORING, or SEQUENCE_CONSERVATION" * @param enumClass * @return */ public static > String getEnumValuesAsString(Class enumClass) { //ScoringStrategy[] vals = ScoringStrategy.values(); T[] vals = enumClass.getEnumConstants(); StringBuilder str = new StringBuilder(); if(vals.length == 1) { str.append(vals[0].name()); } else if(vals.length > 1 ) { for(int i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy