package org.molgenis.compute.commandline.options; /** * This class holds the information for a <i>set</i> of options. A set can hold * any number of <code>OptionData</code> instances which are checked together to * determine success or failure. * <p> * The approach to use this class looks like this: * <p> * <ol> * <li>The user uses any of the <code>Options.addSet()</code> (e. g. * {@link Options#addSet(String)}) to create any number of sets required (or * just relies on the default set, if only one set is required) * <li>The user adds all required option definitions to each set * <li>Using any of the <code>Options.check()</code> methods, each set can be * checked whether the options that were specified on the command line satisfy * its requirements * <li>If the check was successful for a given set, several data items are * available from this class: * <ul> * <li>All options defined for the set (through with e. g. values, details, and * multiplicity are available) * <li>All data items found (these are the items on the command line which do * not start with the prefix, i. e. non-option arguments) * <li>All unmatched arguments on the command line (these are the items on the * command line which start with the prefix, but do not match to one of the * options). Programs can elect to ignore these, or react with an error * </ul> * </ol> */ public class OptionSet { private final static String CLASS = "OptionSet"; private java.util.ArrayList<OptionData> options = new java.util.ArrayList<OptionData>(); private java.util.HashMap<String, OptionData> keys = new java.util.HashMap<String, OptionData>(); private java.util.ArrayList<String> unmatched = new java.util.ArrayList<String>(); private java.util.ArrayList<String> data = new java.util.ArrayList<String>(); private String setName = null; private int minData = 0; private int maxData = 0; private Options.Prefix prefix = null; private Options.Multiplicity defaultMultiplicity = null; /** * Constructor */ OptionSet(Options.Prefix prefix, Options.Multiplicity defaultMultiplicity, String setName, int minData, int maxData) { if (setName == null) throw new IllegalArgumentException(CLASS + ": setName may not be null"); if (minData < 0) throw new IllegalArgumentException(CLASS + ": minData must be >= 0"); if (maxData < minData) throw new IllegalArgumentException(CLASS + ": maxData must be >= minData"); this.prefix = prefix; this.defaultMultiplicity = defaultMultiplicity; this.setName = setName; this.minData = minData; this.maxData = maxData; } /** * Get a list of all the options defined for this set * <p> * * @return A list of {@link OptionData} instances defined for this set */ public java.util.ArrayList<OptionData> getOptionData() { return options; } /** * Get the data for a specific option, identified by its key name (which is * unique) * <p> * * @param key * The key for the option * <p> * @return The {@link OptionData} instance * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or unknown in * this set */ public OptionData getOption(String key) { if (key == null) throw new IllegalArgumentException(CLASS + ": key may not be null"); if (!keys.containsKey(key)) throw new IllegalArgumentException(CLASS + ": unknown key: " + key); return keys.get(key); } /** * Check whether a specific option is set, i. e. whether it was specified at * least once on the command line. * <p> * * @param key * The key for the option * <p> * @return <code>true</code> or <code>false</code>, depending on the outcome * of the check * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or unknown in * this set */ public boolean isSet(String key) { if (key == null) throw new IllegalArgumentException(CLASS + ": key may not be null"); if (!keys.containsKey(key)) throw new IllegalArgumentException(CLASS + ": unknown key: " + key); return keys.get(key).getResultCount() > 0 ? true : false; } /** * Getter method for <code>setName</code> property * <p> * * @return The value for the <code>setName</code> property */ public String getSetName() { return setName; } /** * Getter method for <code>minData</code> property * <p> * * @return The value for the <code>minData</code> property */ public int getMinData() { return minData; } /** * Getter method for <code>maxData</code> property * <p> * * @return The value for the <code>maxData</code> property */ public int getMaxData() { return maxData; } /** * Return the data items found (these are the items on the command line * which do not start with the prefix, i. e. non-option arguments) * <p> * * @return A list of strings with all data items found */ public java.util.ArrayList<String> getData() { return data; } /** * Return all unmatched items found (these are the items on the command line * which start with the prefix, but do not match to one of the options) * <p> * * @return A list of strings with all unmatched items found */ public java.util.ArrayList<String> getUnmatched() { return unmatched; } /** * Add a non-value option with the given key, and the default prefix and * multiplicity * <p> * * @param key * The key for the option * <p> * @return The set instance itself (to support invocation chaining for * <code>addOption()</code> methods) * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or a key with * this name has already been defined */ public OptionSet addOption(String key) { return addOption(key, defaultMultiplicity); } /** * Add a non-value option with the given key and multiplicity, and the * default prefix * <p> * * @param key * The key for the option * @param multiplicity * The multiplicity for the option * <p> * @return The set instance itself (to support invocation chaining for * <code>addOption()</code> methods) * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or a key with * this name has already been defined or if * <code>multiplicity</code> is <code>null</code> */ public OptionSet addOption(String key, Options.Multiplicity multiplicity) { return addOption(key, false, Options.Separator.NONE, false, multiplicity); } /** * Add a value option with the given key and separator, no details, and the * default prefix and multiplicity * <p> * * @param key * The key for the option * @param separator * The separator for the option * <p> * @return The set instance itself (to support invocation chaining for * <code>addOption()</code> methods) * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or a key with * this name has already been defined or if * <code>separator</code> is <code>null</code> */ public OptionSet addOption(String key, Options.Separator separator) { return addOption(key, false, separator, true, defaultMultiplicity); } /** * Add a value option with the given key, separator, and multiplicity, no * details, and the default prefix * <p> * * @param key * The key for the option * @param separator * The separator for the option * @param multiplicity * The multiplicity for the option * <p> * @return The set instance itself (to support invocation chaining for * <code>addOption()</code> methods) * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or a key with * this name has already been defined or if * <code>separator</code> or <code>multiplicity</code> are * <code>null</code> */ public OptionSet addOption(String key, Options.Separator separator, Options.Multiplicity multiplicity) { return addOption(key, false, separator, true, multiplicity); } /** * * Add a value option with the given key and separator, possibly details, * and the default prefix and multiplicity * <p> * * @param key * The key for the option * @param details * A boolean indicating whether details are expected for the * option * @param separator * The separator for the option * <p> * @return The set instance itself (to support invocation chaining for * <code>addOption()</code> methods) * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or a key with * this name has already been defined or if * <code>separator</code> is <code>null</code> */ public OptionSet addOption(String key, boolean details, Options.Separator separator) { return addOption(key, details, separator, true, defaultMultiplicity); } /** * Add a value option with the given key, separator, and multiplicity, * possibly details, and the default prefix * <p> * * @param key * The key for the option * @param details * A boolean indicating whether details are expected for the * option * @param separator * The separator for the option * @param multiplicity * The multiplicity for the option * <p> * @return The set instance itself (to support invocation chaining for * <code>addOption()</code> methods) * <p> * @throws IllegalArgumentException * If the <code>key</code> is <code>null</code> or a key with * this name has already been defined or if * <code>separator</code> or <code>multiplicity</code> are * <code>null</code> */ public OptionSet addOption(String key, boolean details, Options.Separator separator, Options.Multiplicity multiplicity) { return addOption(key, details, separator, true, multiplicity); } /** * The master method to add an option. Since there are combinations which * are not acceptable (like a NONE separator and a true value), this method * is not public. Internally, we only supply acceptable combinations. */ OptionSet addOption(String key, boolean details, Options.Separator separator, boolean value, Options.Multiplicity multiplicity) { if (key == null) throw new IllegalArgumentException(CLASS + ": key may not be null"); if (multiplicity == null) throw new IllegalArgumentException(CLASS + ": multiplicity may not be null"); if (separator == null) throw new IllegalArgumentException(CLASS + ": separator may not be null"); if (keys.containsKey(key)) throw new IllegalArgumentException(CLASS + ": the key " + key + " has already been defined for this OptionSet"); OptionData od = new OptionData(prefix, key, details, separator, value, multiplicity); options.add(od); keys.put(key, od); return this; } }