options/0000755000000000000000000000000011705223122011242 5ustar rootrootoptions/test/0000755000000000000000000000000011646610376012240 5ustar rootrootoptions/build.xml0000644000000000000000000000720411703661776013111 0ustar rootroot Builds, tests, and runs the project options. options/catalog.xml0000644000000000000000000000000010627357464013407 0ustar rootrootoptions/src/0000755000000000000000000000000011646610374012046 5ustar rootrootoptions/src/ml/0000755000000000000000000000000011646610374012456 5ustar rootrootoptions/src/ml/options/0000755000000000000000000000000011646610376014153 5ustar rootrootoptions/src/ml/options/XMLParsingException.java0000644000000000000000000000614510751433560020661 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * XMLParsingException is thrown if an XML file provided to define * option sets and options contains errors */ public class XMLParsingException extends RuntimeException { private static final long serialVersionUID = 1L; /** Constructs a new XMLParsingException exception with null as its * detail message. The cause is not initialized, and may subsequently be * initialized by a call to {@link #initCause}. */ public XMLParsingException() { super(); } /** Constructs a new XMLParsingException exception with the specified detail message. * The cause is not initialized, and may subsequently be initialized by a * call to {@link #initCause}. * * @param message the detail message. The detail message is saved for * later retrieval by the {@link #getMessage()} method. */ public XMLParsingException(String message) { super(message); } /** * Constructs a new XMLParsingException exception with the specified detail message and * cause.

Note that the detail message associated with * cause is not automatically incorporated in * this XMLParsingException exception's detail message. * * @param message the detail message (which is saved for later retrieval * by the {@link #getMessage()} method). * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public XMLParsingException(String message, Throwable cause) { super(message, cause); } /** Constructs a new XMLParsingException exception with the specified cause and a * detail message of (cause==null ? null : cause.toString()) * (which typically contains the class and detail message of * cause). This constructor is useful for XMLParsingException exceptions * that are little more than wrappers for other throwables. * * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public XMLParsingException(Throwable cause) { super(cause); } } options/src/ml/options/SchemaValidator.java0000644000000000000000000001164010751433560020060 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; import javax.xml.validation.*; /** * Validator for XML documents using XML schema. This is based on JDK 5.0 and requires * no outside library. */ public class SchemaValidator extends org.xml.sax.helpers.DefaultHandler { private final String CLASS = "SchemaValidator"; private final String xsdFile = "config/options.xsd"; private String error = null; /** * The actual validation method. If validation is not successful, the errors found can be retrieved * using the {@link #getError()} method. *

* @param xmlReader The reader for the XML file to validate *

* @return true if the XML file could be validated against the XML schema, else false * @throws java.io.IOException * @throws org.xml.sax.SAXException */ public boolean validate(java.io.Reader xmlReader) throws java.io.IOException, org.xml.sax.SAXException { if (xmlReader == null) { throw new IllegalArgumentException(CLASS + ": xmlReader may not be null"); } //.... Get the XML schema from the JAR and create a validator SchemaFactory factory = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); ClassLoader loader = this.getClass().getClassLoader(); java.net.URL url = loader.getResource(xsdFile); Schema schema = factory.newSchema(url); Validator validator = schema.newValidator(); validator.setErrorHandler(this); //.... Try to validate the XML file given org.xml.sax.InputSource source = new org.xml.sax.InputSource(new java.io.BufferedReader(xmlReader)); validator.validate(new javax.xml.transform.sax.SAXSource(source)); return getError() == null ? true : false; } //----------------------------------------------------------------------------------------- // Below are helper methods that are required to improve the error handling (specifically, // to make sure all thrown exceptions are reported, and row and column numbers are added // to the output for better debugging //----------------------------------------------------------------------------------------- /** * Retrieve the error message set by the org.xml.sax.ErrorHandler methods. * If no error has been found, null is returned. *

* @return A string describing the error encountered */ public String getError() { return error; } /** * A method required by the org.xml.sax.ErrorHandler interface *

* @param ex A parsing exception */ @Override public void warning(org.xml.sax.SAXParseException ex) throws org.xml.sax.SAXException { getError("Warning", ex); } /** * A method required by the org.xml.sax.ErrorHandler interface *

* @param ex A parsing exception */ @Override public void error(org.xml.sax.SAXParseException ex) throws org.xml.sax.SAXException { getError("Error", ex); } /** * A method required by the org.xml.sax.ErrorHandler interface *

* @param ex A parsing exception */ @Override public void fatalError(org.xml.sax.SAXParseException ex) throws org.xml.sax.SAXException { getError("Fatal Error", ex); } /** * A helper method for the formatting */ private void getError(String type, org.xml.sax.SAXParseException ex) { StringBuilder out = new StringBuilder(200); out.append(type); if (ex == null) { out.append("!!!"); } String systemId = ex.getSystemId(); if (systemId != null) { int index = systemId.lastIndexOf('/'); if (index != -1) { systemId = systemId.substring(index + 1); } out.append(systemId); } out.append(": Row "); out.append(ex.getLineNumber()); out.append(" /`Col "); out.append(ex.getColumnNumber()); out.append(": "); out.append(ex.getMessage()); //.... There may be multiple exceptions thrown, we don't want to miss any information if (error == null) { error = out.toString(); } else { error += "\n" + out.toString(); } } } options/src/ml/options/DefaultHelpPrinter.java0000644000000000000000000002260410751433560020555 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * A simple implementation of the {@link HelpPrinter} interface. This can serve as a * basis for more complex formatting requirements. *

* The following approach is used here for the command line syntax: *

* *
Option Output Format *
Component Example Remark *
OptionData.Type.SIMPLE option * -a *   *
OptionData.Type.VALUE option * -log <logfile> * The text logfile can be changed using OptionData.setValueText() *
OptionData.Type.DETAIL option * -D<detail>=<value> * The text value can be changed using OptionData.setValueText(), * the text detail can be changed using OptionData.setDetailText() *
Option names with alternate keys * (-a|--Access) *   *
Options.Multiplicity.ZERO_OR_ONCE * [-a] *   *
Options.Multiplicity.ONCE_OR_MORE * -v=<value1> [ -v=<value2> [...]] * The text value can be changed using OptionData.setValueText() *
Options.Multiplicity.ZERO_OR_MORE * [-v=<value1> [ -v=<value2> [...]]] * The text value can be changed using OptionData.setValueText() *
Exclusive constraints * { <option1> | <option2> | <option3> } * <optionN> is a placeholder for the general option syntax described above * which is grouped here using the curly brackets and the pipe symbol *
*

*/ public class DefaultHelpPrinter implements HelpPrinter { private final static String CLASS = "DefaultHelpPrinter"; /** * Return the help text describing the different options and data arguments *

* @param set The {@link OptionSet} to format the output for *

* @return A string with the help text for this option set */ @Override public String getHelpText(OptionSet set) { if (set == null) { throw new IllegalArgumentException(CLASS + ": set may not be null"); } //.... Collect option and data item names String st = null; StringBuilder sb = null; java.util.List out = new java.util.ArrayList(); int maxLen = 0; for (OptionData option : set.getOptionData()) { st = option.getSyntax(); if (st.length() > maxLen) { maxLen = st.length(); } out.add(st); } int limit = set.getMaxData(); if (set.hasUnlimitedData()) { limit = set.getMinData() + 1; } for (int i = 0; i < limit; i++) { st = dataSyntax(i, set.getDataText(i), set.getMinData(), set.getMaxData()); if (st.length() > maxLen) { maxLen = st.length(); } out.add(st.toString()); } //.... Assemble final output StringBuilder s = new StringBuilder(100); for (int i = 0; i < maxLen + 3; i++) { s.append(' '); } String blank = s.toString(); sb = new StringBuilder(300); //.... Help texts for options int i = 0; String k = null; String[] texts = null; boolean first = true; for (OptionData option : set.getOptionData()) { k = out.get(i++) + blank; texts = option.getHelpText().split("\n"); first = true; for (String text : texts) { if (first) { sb.append(k.substring(0, maxLen)); sb.append(" : "); first = false; } else { sb.append(blank); } sb.append(text); sb.append('\n'); } } //.... Help texts for data items for (int j = 0; j < limit; j++) { k = out.get(i++) + blank; texts = set.getHelpText(j).split("\n"); first = true; for (String text : texts) { if (first) { sb.append(k.substring(0, maxLen)); sb.append(" : "); first = false; } else { sb.append(blank); } sb.append(text); sb.append('\n'); } } if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); } // Delete last \n return sb.toString(); } /** * Return a string with the command line syntax for the given option set *

* @param set The {@link OptionSet} to format the output for * @param leadingText The text to precede the command line * @param lineBreak A boolean indicating whether the command line for the option set should * be printed with line breaks after each option or not *

* @return A string with the command line syntax for this option set */ @Override public String getCommandLine(OptionSet set, String leadingText, boolean lineBreak) { if (set == null) { throw new IllegalArgumentException(CLASS + ": set may not be null"); } int limit = set.getMaxData(); if (set.hasUnlimitedData()) { limit = set.getMinData() + 1; } StringBuilder sb = new StringBuilder(200); StringBuilder s = new StringBuilder(); String[] d = null; if (leadingText != null) { sb.append(leadingText.trim()); sb.append(' '); d = leadingText.trim().split("\\n"); // We may have \n in the leading text string for (int i = 0; i <= d[d.length - 1].length(); i++) { s.append(' '); } } //.... Options (not part of an ExclusiveConstraint) boolean first = true; for (OptionData option : set.getOptionData()) { if (!option.isExclusive()) { if (lineBreak && !first) { sb.append(s); } else { first = false; } sb.append(option.getSyntax()); if (lineBreak) { sb.append('\n'); } else { sb.append(' '); } } } //.... ExclusiveConstraint options if (set.getConstraints() != null) { ExclusiveConstraint ec = null; for (Constraint constraint : set.getConstraints()) { if (constraint instanceof ExclusiveConstraint) { ec = (ExclusiveConstraint) constraint; if (lineBreak && !first) { sb.append(s); } else { first = false; } sb.append('{'); // This identifies this type of constraint for (OptionData option : ec.getOptionData()) { sb.append(option.getSyntax()); sb.append('|'); // Separator in between options } sb.deleteCharAt(sb.length() - 1); // Remove last | character sb.append('}'); // End of constraint output if (lineBreak) { sb.append('\n'); } else { sb.append(' '); } } } } //.... Data if (set.acceptsData()) { if (lineBreak && set.getOptionData().size() > 0) { sb.append(s); } for (int i = 0; i < limit; i++) { sb.append(dataSyntax(i, set.getDataText(i), set.getMinData(), set.getMaxData())); sb.append(' '); } } sb.deleteCharAt(sb.length() - 1); return sb.toString(); } /** * Helper */ private String dataSyntax(int index, String text, int minData, int maxData) { if (index < minData) { return "<" + text + ">"; } if (maxData == OptionSet.INF) { return "[<" + text + "> [...]]"; } return "[<" + text + ">]"; } } options/src/ml/options/OptionSet.java0000644000000000000000000005467411110551004016734 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * This class holds the information for a set of options. A set can hold any number of * OptionData instances which are checked together to determine success or failure. *

* The approach to use this class looks like this: *

*

    *
  1. The user uses any of the Options.addSet() methods * (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) *
  2. The user adds all required option definitions to each set *
  3. Using any of the Options.check() methods, each set can be checked whether the options * that were specified on the command line satisfy its requirements *
  4. If the check was successful for a given set, several data items are available from this class: * *
*/ public class OptionSet implements Constrainable { private final static String CLASS = "OptionSet"; private static java.util.regex.Pattern keyPattern = java.util.regex.Pattern.compile("\\w+"); private java.util.ArrayList options = new java.util.ArrayList(); private java.util.HashMap keys = new java.util.HashMap(); private java.util.HashSet altKeys = new java.util.HashSet(); private java.util.ArrayList unmatched = new java.util.ArrayList(); private java.util.ArrayList data = new java.util.ArrayList(); private String name = null; private String[] dataText = null; private String[] helpText = null; private int minData = 0; private int maxData = 0; private Options.Prefix prefix = null; private Options.Prefix altPrefix = null; private Options.Multiplicity defaultMultiplicity = null; private Options.Separator valueSeparator = null; private Options.Separator detailSeparator = null; private boolean isDefault = false; private boolean unlimitedData = false; private int limit = 0; private java.util.List constraints = null; /** * A constant indicating an unlimited number of supported data items */ public static final int INF = -1; /** * A copying constructor. This is for setup purposes only and does not copy any result data. */ OptionSet(String name, OptionSet os) { this(name, os.getPrefix(), os.getAltPrefix(), os.getValueSeparator(), os.getDetailSeparator(), os.getDefaultMultiplicity(), os.getMinData(), os.getMaxData(), false); this.limit = os.getLimit(); for (int i = 0; i < limit; i++) { helpText[i] = os.getHelpText(i); dataText[i] = os.getDataText(i); } for (String s : os.getAltKeys()) { altKeys.add(s); } OptionData nod = null; for (OptionData od : os.getOptionData()) { nod = new OptionData(od); options.add(nod); keys.put(od.getKey(), nod); } } Options.Multiplicity getDefaultMultiplicity() { return defaultMultiplicity; } java.util.HashMap getKeys() { return keys; } java.util.HashSet getAltKeys() { return altKeys; } /** * Constructor */ OptionSet(String name, Options.Prefix prefix, Options.Prefix altPrefix, Options.Separator valueSeparator, Options.Separator detailSeparator, Options.Multiplicity defaultMultiplicity, int minData, int maxData, boolean isDefault) { if (name == null) { throw new IllegalArgumentException(CLASS + ": name 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.altPrefix = altPrefix; this.defaultMultiplicity = defaultMultiplicity; this.valueSeparator = valueSeparator; this.detailSeparator = detailSeparator; this.name = name; this.minData = minData; this.maxData = maxData; //.... Unless we support an unlimited number of data items, we can define texts for up to maxData // data items. Otherwise, we only can use up to (minData + 1) definitions: minData for the // first required ones, and 1 more which goes into the [] brackets limit = maxData; if (maxData == Integer.MAX_VALUE) { unlimitedData = true; limit = minData + 1; } dataText = new String[limit]; for (int i = 0; i < limit; i++) // Set the default for the data text { dataText[i] = "data"; } helpText = new String[limit]; for (int i = 0; i < limit; i++) // Set the default for the help text { helpText[i] = ""; } this.isDefault = isDefault; // Whether this is the default set } /** * Indicate whether this set has no upper limit for the number of allowed data items *

* @return A boolean indicating whether this set has no upper limit for the number of allowed data items */ public boolean hasUnlimitedData() { return unlimitedData; } /** * Indicate whether this set is the default set or not *

* @return A boolean indicating whether this set is the default set or not */ public boolean isDefault() { return isDefault; } /** * Add a constraint for this option set *

* @param constraint The {@link Constraint} to add */ @Override public void addConstraint(Constraint constraint) { if (constraint == null) { throw new IllegalArgumentException(CLASS + ": constraint may not be null"); } if (!constraint.supports(this)) { throw new IllegalArgumentException(CLASS + ": the given constraint can not be applied to option sets"); } if (constraints == null) { constraints = new java.util.ArrayList(); } constraints.add(constraint); } /** * Get the constraints defined for this option set *

* @return The defined constraints for this option (or null if no constraints have been defined) */ @Override public java.util.List getConstraints() { return constraints; } /** * Set the data text for a data item on the command line. This is exploited e. g. in {@link HelpPrinter} instances. *

* @param index The index for this data item on the command line. Must be within the allowed range of * 0 ... maxData - 1 for this set. If this set supports an unlimited * number of data items, the allowed range is 0 ... minData. * @param text The text to use for this data item in the command line syntax *

* @return This set to allow for invocation chaining */ public OptionSet setDataText(int index, String text) { if (text == null) { throw new IllegalArgumentException(CLASS + ": text may not be null"); } if (index < 0 || index >= limit) { throw new IllegalArgumentException(CLASS + ": invalid value for index"); } this.dataText[index] = text.trim(); return this; } /** * Set the help text for a data item on the command line. This is exploited e. g. in {@link HelpPrinter} instances. *

* @param index The index for this data item on the command line. Must be within the allowed range of * 0 ... maxData - 1 for this set. If this set supports an unlimited * number of data items, the allowed range is 0 ... minData. * @param text The help text to use to describe the purpose of the data item *

* @return This set to allow for invocation chaining */ public OptionSet setHelpText(int index, String text) { if (text == null) { throw new IllegalArgumentException(CLASS + ": text may not be null"); } if (index < 0 || index >= limit) { throw new IllegalArgumentException(CLASS + ": invalid value for index"); } this.helpText[index] = text.trim(); return this; } /** * Get the data text for a data item on the command line. This is only useful if such a data text is used. *

* @param index The index for this data item on the command line. Must be within the allowed range of * 0 ... maxData - 1 for this set. If this set supports an unlimited * number of data items, the allowed range is 0 ... minData. *

* @return The text used for this data item in the command line syntax */ public String getDataText(int index) { if (index < 0 || index >= limit) { throw new IllegalArgumentException(CLASS + ": invalid value for index"); } return dataText[index]; } /** * Get the help text for a data item on the command line. This is only useful if such a help text is used. *

* @param index The index for this data item on the command line. Must be within the allowed range of * 0 ... maxData - 1 for this set. If this set supports an unlimited * number of data items, the allowed range is 0 ... minData. *

* @return The help text used to describe the purpose of the data item */ public String getHelpText(int index) { if (index < 0 || index >= limit) { throw new IllegalArgumentException(CLASS + ": invalid value for index"); } return helpText[index]; } /** * Get the primary {@link Options.Prefix} for this set. This is primarily intended for use by * {@link HelpPrinter} instances to format their output. *

* @return The {@link Options.Prefix} instance used as primary prefix for this set */ Options.Prefix getPrefix() { return prefix; } /** * Get the alternate {@link Options.Prefix} for this set. This is primarily intended for use by * {@link HelpPrinter} instances to format their output. *

* @return The {@link Options.Prefix} instance used as alternate prefix for this set */ Options.Prefix getAltPrefix() { return altPrefix; } /** * Get a list of all the options defined for this set *

* @return A list of {@link OptionData} instances defined for this set */ public java.util.List getOptionData() { return options; } /** * Get the data for a specific option, identified by its key name (which is unique) *

* @param key The key for the option *

* @return The {@link OptionData} instance */ 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. *

* @param key The key for the option *

* @return true or false, depending on the outcome of the check */ 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).isSet(); } /** * Return the name of the set *

* @return The name of the set */ public String getName() { return name; } /** * Getter method for minData property *

* @return The value for the minData property */ public int getMinData() { return minData; } /** * Getter method for maxData property *

* @return The value for the maxData property */ public int getMaxData() { if (hasUnlimitedData()) { return INF; } else { return maxData; } } /** * Getter method for valueSeparator property *

* @return The value for the valueSeparator property */ Options.Separator getValueSeparator() { return valueSeparator; } /** * Getter method for detailSeparator property *

* @return The value for the detailSeparator property */ Options.Separator getDetailSeparator() { return detailSeparator; } /** * Helper method required for option set cloning */ int getLimit() { return limit; } /** * Indicate whether this set accepts data (which means that maxData is 1 or larger). *

* @return A boolean indicating whether this set accepts data */ public boolean acceptsData() { return (minData + maxData) == 0 ? false : true; } /** * 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) *

* @return A list of strings with all data items found */ public java.util.List getData() { return data; } /** * Return the number of data items found (these are the items on the command line * which do not start with the prefix, i. e. non-option arguments) *

* @return The number of all data items found */ public int getDataCount() { return data.size(); } /** * Return a specific data item. *

* @param index * @return The requested data item */ public String getData(int index) { if (index < 0 || index >= getDataCount()) { if (getDataCount() == 0) { throw new IllegalArgumentException(CLASS + ": No data items are available"); } else { int n = getDataCount() - 1; throw new IllegalArgumentException(CLASS + ": Invalid index value - must be between 0 and " + n); } } return data.get(index); } /** * 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) *

* @return A list of strings with all unmatched items found */ public java.util.List getUnmatched() { return unmatched; } /** * Return the number of 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) *

* @return The number of all unmatched items found */ public int getUnmatchedCount() { return unmatched.size(); } /** * Return a specific unmatched item. *

* @param index * @return The requested unmatched item */ public String getUnmatched(int index) { if (index < 0 || index >= getUnmatchedCount()) { if (getUnmatchedCount() == 0) { throw new IllegalArgumentException(CLASS + ": No unmatched items are available"); } else { int n = getUnmatchedCount() - 1; throw new IllegalArgumentException(CLASS + ": Invalid index value - must be between 0 and " + n); } } return unmatched.get(index); } // ========================================================================================== // Add a non-value option // ========================================================================================== /** * Add the given option to the set. *

* @param type The type of the option * @param key The name of the option *

* @return The newly created option (to support invocation chaining) */ public OptionData addOption(OptionData.Type type, String key) { return addOption(type, key, null, type.detail() ? detailSeparator : valueSeparator, defaultMultiplicity); } /** * Add the given option to the set. *

* @param type The type of the option * @param key The name of the option * @param multiplicity The multiplicity of the option *

* @return The newly created option (to support invocation chaining) */ public OptionData addOption(OptionData.Type type, String key, Options.Multiplicity multiplicity) { return addOption(type, key, null, type.detail() ? detailSeparator : valueSeparator, multiplicity); } /** * Add the given option to the set. *

* @param type The type of the option * @param key The name of the option * @param altKey The alternate name of the option *

* @return The newly created option (to support invocation chaining) */ public OptionData addOption(OptionData.Type type, String key, String altKey) { return addOption(type, key, altKey, type.detail() ? detailSeparator : valueSeparator, defaultMultiplicity); } /** * Add the given option to the set. *

* @param type The type of the option * @param key The name of the option * @param altKey The alternate name of the option * @param multiplicity The multiplicity of the option *

* @return The newly created option (to support invocation chaining) */ public OptionData addOption(OptionData.Type type, String key, String altKey, Options.Multiplicity multiplicity) { return addOption(type, key, altKey, type.detail() ? detailSeparator : valueSeparator, 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. */ OptionData addOption(OptionData.Type type, String key, String altKey, Options.Separator separator, Options.Multiplicity multiplicity) { if (type == null) { throw new IllegalArgumentException(CLASS + ": type may not be null"); } 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 (keys.containsKey(key)) { throw new IllegalArgumentException(CLASS + ": the key " + key + " has already been defined for this OptionSet"); } if (altKey != null && altKeys.contains(altKey)) { throw new IllegalArgumentException(CLASS + ": the alternate key " + altKey + " has already been defined for this OptionSet"); } //.... Check keys for valid names (especially no whitespace) java.util.regex.Matcher m = keyPattern.matcher(key); if (!m.matches()) { throw new IllegalArgumentException(CLASS + ": invalid key: may only contain [a-zA-Z_0-9]"); } if (altKey != null) { m = keyPattern.matcher(altKey); if (!m.matches()) { throw new IllegalArgumentException(CLASS + ": invalid alternate key: may only contain [a-zA-Z_0-9]"); } } OptionData od = new OptionData(type, prefix, altPrefix, key, altKey, separator, multiplicity); options.add(od); keys.put(key, od); if (altKey != null) { altKeys.add(altKey); } return od; } /** * A convenience method that prints all the results obtained for this option set to * System.out. This is quite handy to quickly check whether a set definition * yields the expected results for a given set of command line arguments. */ public void printResults() { for (OptionData od : getOptionData()) { System.out.println("Option: " + od.getSyntax() + " (found " + od.getResultCount() + " time(s))"); for (int i = 0; i < od.getResultCount(); i++) { if (od.useDetail()) { System.out.println("- Detail " + i + ": " + od.getResultDetail(i)); } if (od.useValue()) { System.out.println("- Value " + i + ": " + od.getResultValue(i)); } } } for (String s : getData()) { System.out.println("Data : " + s); } for (String s : getUnmatched()) { System.out.println("Unmatched : " + s); } } } options/src/ml/options/XMLConstraint.java0000644000000000000000000000402010751433560017511 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * Constraints implementing this interface have - beyond the {@link Constraint} interface - the capability * to be created through XML configuration files. In this case, a public no-arg constructor * is also required. */ public interface XMLConstraint extends Constraint { /** * This method is used to initialize a constraint based on data read from an XML configuration * file. The method is invoked internally during setup with the instance of * {@link Constrainable} to which the constraint applies and a list of JDOM elements, * which contain the details about the constraint itself. *

* This method initializes the constraint and attaches it to the list of constraints * of the {@link Constrainable} instance. *

* @param constrainable The {@link Constrainable} instance to which this constraint applies * @param list A list of JDOM elements to be used to initialize the constraint. Specifically, * these are tags of the form *

* <param name="..." value="..." /> *

* containing key/value pairs with information. The expected pairs are specific * to each implementation. */ public void init(Constrainable constrainable, java.util.List list); } options/src/ml/options/Constraint.java0000644000000000000000000000255410751433560017142 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * The interface for all constraints. Custom constraints need to implement this interface. */ public interface Constraint { /** * Check whether a constraint is satisfied. This method can be invoked after a set of * command line arguments has been analyzed such that the results are known for each * option and option set. *

* @return A boolean to indicate whether a constraint is satisfied or not */ public boolean isSatisfied(); /** * Indicates whether a constraint supports a given type of {@link Constrainable} *

* @param constrainable * @return A boolean to indicate whether this {@link Constrainable} is supported */ public boolean supports(Constrainable constrainable); } options/src/ml/options/Constrainable.java0000644000000000000000000000224610751433560017600 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * The interface for objects which can be constrained, i. e. {@link Constraint}s can * be attached to such objects. */ public interface Constrainable { /** * Add a constraint to this instance. *

* @param constraint The {@link Constraint} to add to the list of constraints for this instance */ public void addConstraint(Constraint constraint); /** * Access all known constraints *

* @return A list of {@link Constraint}s for this instance */ public java.util.List getConstraints(); } options/src/ml/options/Options.java0000644000000000000000000015242710751433560016456 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * The central class for option processing. Sets are identified by their name, but there is also * an anonymous default set, which is very convenient if an application requieres only one set. *

* The default values used in this class are: *

* *
Default Values *
ID Parameter Default Individual Setting *
1 Prefix * Prefix.SLASH (Windows)
Prefix.DASH (all others) *
No *
2 Alternate Prefix * Prefix.DOUBLEDASH * No *
3 Separator for value options * Separator.BLANK * No *
4 Separator for detail options * Separator.EQUALS * No *
5 Min. Data * 0 * Option set level *
6 Max. Data * 0 * Option set level *
7 Multiplicity * Multiplicity.ZERO_OR_ONCE * Option level *
*

* All of these values can be changed using one of the setDefault() methods. However, for * 1 - 4 this can only be done before any actual set or option has been created (otherwise an * UnsupportedOperationException is thrown). 5 - 7 can be called * anytime, but they affect only sets and options which are created afterwards. */ public class Options { private final static String CLASS = "Options"; /** * The name used internally for the default set */ private final static String DEFAULT_SET = "DEFAULT_OPTION_SET"; // ========================================================================================== // Helper enums // ========================================================================================== /** * An enum encapsulating the possible separators between value options and their actual values. */ public enum Separator { /** * Separate option and value by ":" */ COLON(':'), /** * Separate option and value by "=" */ EQUALS('='), /** * Separate option and value by blank space */ BLANK(' '); // Or, more precisely, whitespace (as allowed by the CLI) private char c; private Separator(char c) { this.c = c; } /** * Return the actual separator character *

* @return The actual separator character */ char getName() { return c; } } // ========================================================================================== /** * An enum encapsulating the possible prefixes identifying options (and separating them from command line data items) */ public enum Prefix { /** * Options start with a "-" (typically on Unix platforms) */ DASH("-"), /** * Options start with a "--" (like GNU-style options on Unix platforms) */ DOUBLEDASH("--"), /** * Options start with a "/" (typically on Windows platforms) */ SLASH("/"); private String c; private Prefix(String c) { this.c = c; } /** * Return the actual prefix character *

* @return The actual prefix character */ String getName() { return c; } } // ========================================================================================== /** * An enum encapsulating the possible multiplicities for options */ public enum Multiplicity { /** * Option needs to occur exactly once */ ONCE(true), /** * Option needs to occur at least once */ ONCE_OR_MORE(true), /** * Option needs to occur either once or not at all */ ZERO_OR_ONCE(false), /** * Option can occur any number of times */ ZERO_OR_MORE(false); private boolean required = false; private Multiplicity(boolean required) { this.required = required; } boolean isRequired() { return required; } } // ========================================================================================== // Instance members // ========================================================================================== private java.util.TreeMap optionSets = new java.util.TreeMap(); private String[] arguments = null; private boolean ignoreUnmatched = false; private StringBuilder checkErrors = new StringBuilder(); //.... Defaults private Prefix defaultPrefix = getDefaultPrefix(); private Prefix defaultAltPrefix = Prefix.DOUBLEDASH; private Separator defaultValueSeparator = Separator.BLANK; private Separator defaultDetailSeparator = Separator.EQUALS; private Multiplicity defaultMultiplicity = Multiplicity.ZERO_OR_ONCE; private int defaultMinData = 0; private int defaultMaxData = 0; /** * Constructor *

* @param args The command line arguments to check */ public Options(String args[]) { if (args == null) { throw new IllegalArgumentException(CLASS + ": args may not be null"); } arguments = new String[args.length]; int i = 0; for (String s : args) { arguments[i++] = s; } } /** * This constructor uses the XML file provided by the reader to set up option sets and options. *

* @param args The command line arguments to check * @param reader The reader instance providing the XML file * @throws org.jdom.JDOMException */ @SuppressWarnings("unchecked") public Options(String args[], java.io.Reader reader) throws org.jdom.JDOMException { this(args); if (reader == null) { throw new IllegalArgumentException(CLASS + ": reader may not be null"); } //.... Copy the XML content into a string. This is done since we need to read the data // twice (once for validation, once for evaluation), and not all readers support the // reset() method. StringBuilder sb = new StringBuilder(1000); String line = null; java.io.BufferedReader r = new java.io.BufferedReader(reader); try { while ((line = r.readLine()) != null) { sb.append(line); sb.append('\n'); } } catch (java.io.IOException ex) { throw new XMLParsingException(CLASS + ": Error while reading XML file!\n" + ex.getMessage()); } line = sb.toString(); //.... Try to validate the XML document against the schema SchemaValidator validator = new SchemaValidator(); try { if (!validator.validate(new java.io.BufferedReader(new java.io.StringReader(line)))) { throw new XMLParsingException(CLASS + ": Error in XML file validation against schema!\n" + validator.getError()); } } catch (java.io.IOException ex) { throw new XMLParsingException(CLASS + ": Error in XML file validation against schema!\n" + ex.getMessage()); } catch (org.xml.sax.SAXException ex) { throw new XMLParsingException(CLASS + ": Error in XML file validation against schema!\n" + ex.getMessage()); } validator = null; //.... Retrieve the data and create the option sets and options try { org.jdom.input.SAXBuilder builder = new org.jdom.input.SAXBuilder(); org.jdom.Document doc = builder.build(new java.io.BufferedReader(new java.io.StringReader(line))); //... Process the tag org.jdom.Element root = doc.getRootElement(); String value = null; String values[] = null; if (root.getAttribute("defData") != null) { value = root.getAttributeValue("defData"); if (value.indexOf(':') < 0) { setDefault(Integer.parseInt(value)); } else { values = value.split(":"); if (values[1].equals("INF")) { setDefault(Integer.parseInt(values[0]), Integer.MAX_VALUE); } else { setDefault(Integer.parseInt(values[0]), Integer.parseInt(values[1])); } } } if (root.getAttribute("defMult") != null) { setDefault(Multiplicity.valueOf(root.getAttributeValue("defMult"))); } if (root.getAttribute("defSep") != null) { value = root.getAttributeValue("defSep"); if (value.indexOf(':') < 0) { setDefault(Separator.valueOf(value)); } else { values = value.split(":"); setDefault(Separator.valueOf(values[0]), Separator.valueOf(values[1])); } } if (root.getAttribute("defPrefix") != null) { value = root.getAttributeValue("defPrefix"); if (value.indexOf(':') < 0) { setDefault(Prefix.valueOf(value)); } else { values = value.split(":"); setDefault(Prefix.valueOf(values[0]), Prefix.valueOf(values[1])); } } //... Process the tag(s) OptionSet set = null; boolean found = false; for (org.jdom.Element element : (java.util.List) root.getChildren("set")) { if (element.getAttribute("data") != null) { // Create the set value = element.getAttributeValue("data"); if (value.indexOf(':') < 0) { set = addSet(element.getAttributeValue("name"), Integer.parseInt(value)); } else { values = value.split(":"); if (values[1].equals("INF")) { // Allow unlimited number of data items set = addSet(element.getAttributeValue("name"), Integer.parseInt(values[0]), Integer.MAX_VALUE); } else { set = addSet(element.getAttributeValue("name"), Integer.parseInt(values[0]), Integer.parseInt(values[1])); } } } else { set = addSet(element.getAttributeValue("name")); } processSet(set, element); found = true; } //... Process the tag (if present) if (root.getChild("defaultSet") != null) { processSet(getSet(), root.getChild("defaultSet")); found = true; } if (!found) { throw new XMLParsingException(CLASS + ": At least one option set needs to be defined"); } //.... Process the

* @param defaultValueSeparator The default separator to use for all value options *

* @return This instance to allow for invocation chaining */ public Options setDefault(Separator defaultValueSeparator) { if (defaultValueSeparator == null) { throw new IllegalArgumentException(CLASS + ": defaultValueSeparator may not be null"); } if (optionSets.size() > 0) { throw new UnsupportedOperationException(CLASS + ": method can not be invoked, OptionSets have already been defined"); } this.defaultValueSeparator = defaultValueSeparator; return this; } /** * Define the defaults to use for the separators for value and detail options. Note that this method can * only be invoked before any option set has been created. *

* @param defaultValueSeparator The default separator to use for all value options * @param defaultDetailSeparator The default separator to use for all detail options *

* @return This instance to allow for invocation chaining */ public Options setDefault(Separator defaultValueSeparator, Separator defaultDetailSeparator) { if (defaultValueSeparator == null) { throw new IllegalArgumentException(CLASS + ": defaultValueSeparator may not be null"); } if (defaultDetailSeparator == null) { throw new IllegalArgumentException(CLASS + ": defaultDetailSeparator may not be null"); } if (optionSets.size() > 0) { throw new UnsupportedOperationException(CLASS + ": method can not be invoked, OptionSets have already been defined"); } this.defaultValueSeparator = defaultValueSeparator; this.defaultDetailSeparator = defaultDetailSeparator; return this; } /** * Define the default to use for the option prefix. Note that this method can * only be invoked before any option set has been created. *

* @param defaultPrefix The prefix to use for all options *

* @return This instance to allow for invocation chaining */ public Options setDefault(Prefix defaultPrefix) { if (defaultPrefix == null) { throw new IllegalArgumentException(CLASS + ": defaultPrefix may not be null"); } if (optionSets.size() > 0) { throw new UnsupportedOperationException(CLASS + ": method can not be invoked, OptionSets have already been defined"); } this.defaultPrefix = defaultPrefix; return this; } /** * Define the defaults to use for the option prefixes. Note that this method can * only be invoked before any option set has been created. *

* @param defaultPrefix The prefix to use for all options * @param defaultAltPrefix The prefix to use for all alternate keys for options *

* @return This instance to allow for invocation chaining */ public Options setDefault(Prefix defaultPrefix, Prefix defaultAltPrefix) { if (defaultPrefix == null) { throw new IllegalArgumentException(CLASS + ": defaultPrefix may not be null"); } if (defaultAltPrefix == null) { throw new IllegalArgumentException(CLASS + ": defaultAltPrefix may not be null"); } if (defaultPrefix.equals(defaultAltPrefix)) { throw new IllegalArgumentException(CLASS + ": The prefixes must be different"); } if (optionSets.size() > 0) { throw new UnsupportedOperationException(CLASS + ": method can not be invoked, OptionSets have already been defined"); } this.defaultPrefix = defaultPrefix; this.defaultAltPrefix = defaultAltPrefix; return this; } /** * Define the default to use for the multiplicity for options. This applies only to * option sets and options within these sets which are created after this call. *

* @param defaultMultiplicity The default multiplicity to use for all options *

* @return This instance to allow for invocation chaining */ public Options setDefault(Multiplicity defaultMultiplicity) { if (defaultMultiplicity == null) { throw new IllegalArgumentException(CLASS + ": defaultMultiplicity may not be null"); } this.defaultMultiplicity = defaultMultiplicity; return this; } /** * Define the defaults to use for the number of data items for a set. This applies only to * option sets which are created after this call. *

* @param defaultData The default minimum and maximum number of data items *

* @return This instance to allow for invocation chaining */ public Options setDefault(int defaultData) { if (defaultData < 0) { throw new IllegalArgumentException(CLASS + ": defaultData must be >= 0"); } this.defaultMinData = defaultData; this.defaultMaxData = defaultData; return this; } /** * Define the defaults to use for the number of data items for a set. This applies only to * option sets which are created after this call. *

* @param defaultMinData The default minimum number of data items * @param defaultMaxData The default maximum number of data items *

* @return This instance to allow for invocation chaining */ public Options setDefault(int defaultMinData, int defaultMaxData) { if (defaultMinData < 0) { throw new IllegalArgumentException(CLASS + ": defaultMinData must be >= 0"); } int limit = defaultMaxData; if (defaultMaxData == OptionSet.INF) { limit = Integer.MAX_VALUE; } if (limit < defaultMinData) { throw new IllegalArgumentException(CLASS + ": defaultMaxData must be >= defaultMinData"); } this.defaultMinData = defaultMinData; this.defaultMaxData = limit; return this; } // ========================================================================================== // The actual API // ========================================================================================== /** * Return the (first) matching set. This invocation does not ignore unmatched options and requires that * data items are the last ones on the command line. It is equivalent to calling * getMatchingSet(false, true). *

* @return The first set which matches (i. e. the check() method returns true) - or * null, if no set matches. */ public OptionSet getMatchingSet() { return getMatchingSet(false, true); } /** * Return the (first) matching set. *

* @param ignoreUnmatched A boolean to select whether unmatched options can be ignored in the checks or not * @param requireDataLast A boolean to indicate whether the data items * have to be the last ones on the command line or not *

* @return The first set which matches (i. e. the check() method returns true) - or * null, if no set matches. */ public OptionSet getMatchingSet(boolean ignoreUnmatched, boolean requireDataLast) { // If we have no set at this stage, we need to create the default set since // chances are the user just wants to check for data (no options), and thus // getSet() has not been invoked by the user at this stage. if (optionSets.isEmpty()) { getSet(); } // Run the checks for all known sets for (String name : optionSets.keySet()) { if (check(name, ignoreUnmatched, requireDataLast)) { return optionSets.get(name); } } return null; } /** * Add an option set. *

* @param name The name for the set. This must be a unique identifier * @param minData The minimum number of data items for this set * @param maxData The maximum number of data items for this set (if set to OptionSet.INF, this * effectively corresponds to an unlimited number) *

* @return The new OptionSet instance created. This is useful to allow * chaining of addOption() calls right after this method */ public OptionSet addSet(String name, int minData, int maxData) { if (name == null) { throw new IllegalArgumentException(CLASS + ": name may not be null"); } if (optionSets.containsKey(name)) { throw new IllegalArgumentException(CLASS + ": a set with the name " + name + " has already been defined"); } int limit = maxData; if (maxData == OptionSet.INF) { limit = Integer.MAX_VALUE; } OptionSet os = new OptionSet(name, defaultPrefix, defaultAltPrefix, defaultValueSeparator, defaultDetailSeparator, defaultMultiplicity, minData, limit, name.equals(DEFAULT_SET)); optionSets.put(name, os); return os; } /** * Add an option set. *

* @param name The name for the set. This must be a unique identifier * @param data The minimum and maximum number of data items for this set *

* @return The new OptionSet instance created. This is useful to allow chaining * of addOption() calls right after this method */ public OptionSet addSet(String name, int data) { return addSet(name, data, data); } /** * Add an option set. The defaults for the number of data items are used. *

* @param name The name for the set. This must be a unique identifier *

* @return The new OptionSet instance created. This is useful to allow * chaining of addOption() calls right after this method */ public OptionSet addSet(String name) { return addSet(name, defaultMinData, defaultMaxData); } /** * Add an option set by cloning an existing set. Note that is designed for setup purposes only, i. e. no * check result data is copied either for the set or any options. This method can be very handy if an application * requires two (or more) sets which have a lot of options in common and differ only in a few of them. In this * case, one would first create a set with the common options, then clone any number of additionally required * sets, and add the non-common options to each of these sets. *

* Note that it is not possible to change the number of data items required for the new set. *

* @param name The name for the new set. This must be a unique identifier * @param set The set to clone the new set from *

* @return The new OptionSet instance created. This is useful to allow chaining * of addOption() calls right after this method */ public OptionSet addSet(String name, OptionSet set) { if (name == null) { throw new IllegalArgumentException(CLASS + ": name may not be null"); } if (set == null) { throw new IllegalArgumentException(CLASS + ": set may not be null"); } if (optionSets.containsKey(name)) { throw new IllegalArgumentException(CLASS + ": a set with the name " + name + " has already been defined"); } OptionSet os = new OptionSet(name, set); optionSets.put(name, os); return os; } /** * Return an option set - or null, if no set with the given name exists *

* @param name The name for the set to retrieve *

* @return The set to retrieve (or null, if no set with the given name exists) */ public OptionSet getSet(String name) { return optionSets.get(name); } /** * Print a help description for this instance using a {@link DefaultHelpPrinter}. This method * provides a basic service in the sense that it loops over all known option sets * and prints the command line for each set. If printTexts is true, also * descriptive texts are printed for all options and the data arguments. *

* Note that default values are used for all the components of the helper text, which can be * overridden by various methods available in the {@link OptionSet} and {@link OptionData} classes. *

* @param leadingText The text to precede the command line for each * option set (see {@link HelpPrinter#getCommandLine(OptionSet, String, boolean)}) * @param lineBreak A boolean indicating whether the command lines for the option sets should * be printed with line breaks or not * (see {@link HelpPrinter#getCommandLine(OptionSet, String, boolean)}) * @param printTexts A boolean indicating whether the full help information should be printer (command lines * and description texts) or just the command lines */ public void printHelp(String leadingText, boolean lineBreak, boolean printTexts) { printHelp(new DefaultHelpPrinter(), leadingText, lineBreak, printTexts); } /** * Print a help description for this instance using the provided {@link HelpPrinter}. This method * provides a basic service in the sense that it loops over all known option sets * and prints the command line for each set. If printTexts is true, also * descriptive texts are printed for all options and the data arguments. *

* Note that default values are used for all the components of the helper text, which can be * overridden by various methods available in the {@link OptionSet} and {@link OptionData} classes. *

* @param helpPrinter The {@link HelpPrinter} to use to format the output * @param leadingText The text to precede the command line for each * option set (see {@link HelpPrinter#getCommandLine(OptionSet, String, boolean)}) * @param lineBreak A boolean indicating whether the command lines for the option sets should * be printed with line breaks or not * (see {@link HelpPrinter#getCommandLine(OptionSet, String, boolean)}) * @param printTexts A boolean indicating whether the full help information should be printer (command lines * and description texts) or just the command lines */ public void printHelp(HelpPrinter helpPrinter, String leadingText, boolean lineBreak, boolean printTexts) { if (helpPrinter == null) { throw new IllegalArgumentException(CLASS + ": helpPrinter may not be null"); } if (leadingText == null) { throw new IllegalArgumentException(CLASS + ": leadingText may not be null"); } OptionSet set = null; //.... No sets are defined, we only work with the default set if (getSetNames().size() == 0) { set = getSet(); System.out.println(helpPrinter.getCommandLine(set, leadingText, lineBreak)); if (printTexts) { System.out.print('\n'); System.out.println(helpPrinter.getHelpText(set)); } //.... Loop over all defined sets } else { java.util.Set sets = getSetNames(); for (String name : sets) { set = getSet(name); System.out.println(helpPrinter.getCommandLine(set, leadingText, lineBreak)); if (printTexts) { System.out.print('\n'); System.out.println(helpPrinter.getHelpText(set)); if (sets.size() > 1) { System.out.print('\n'); } } } } } /** * Get a set view on the known option set names. This is not public since it includes the default * set name as well, which we don't want to expose. *

* @return A set containing the names of the option sets, or null if no such sets are defined *

*/ java.util.Set getSetNames() { return optionSets.keySet(); } /** * This returns the (anonymous) default set *

* @return The default set */ public OptionSet getSet() { if (getSet(DEFAULT_SET) == null) { addSet(DEFAULT_SET, defaultMinData, defaultMaxData); } return getSet(DEFAULT_SET); } /** * Determine a default prefix depending on the OS platform. This uses the os.name Java system property. * For Windows, Prefix.SLASH is used, else Prefix.DASH. This will likely need to be * adapted over time for other platforms and VMs, depending on the string they return for that Java system property. *

* @return The default prefix for the current platform */ private static Prefix getDefaultPrefix() { String os = System.getProperty("os.name"); if (os.startsWith("Windows")) { return Prefix.SLASH; } else { return Prefix.DASH; } } /** * This is the overloaded {@link Object#toString()} method. *

* @return A string representing the instance */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("defaultPrefix = "); sb.append(defaultPrefix); sb.append('\n'); sb.append("defaultAltPrefix = "); sb.append(defaultAltPrefix); sb.append('\n'); sb.append("defaultValueSeparator = "); sb.append(defaultValueSeparator); sb.append('\n'); sb.append("defaultDetailSeparator = "); sb.append(defaultDetailSeparator); sb.append('\n'); sb.append("defaultMultiplicity = "); sb.append(defaultMultiplicity); sb.append('\n'); sb.append("defaultMinData = "); sb.append(defaultMinData); sb.append('\n'); sb.append("defaultMaxData = "); sb.append(defaultMaxData); sb.append('\n'); for (OptionSet set : optionSets.values()) { sb.append("Set: "); sb.append(set.getName()); sb.append('\n'); for (OptionData data : set.getOptionData()) { sb.append(data.toString()); sb.append('\n'); } } return sb.toString(); } // ========================================================================================== // The checks // ========================================================================================== /** * The error messages collected during the last option check * (invocation of any of the check() methods). This * is useful to determine what was wrong with the command * line arguments provided *

* @return A string with all collected error messages */ public String getCheckErrors() { return checkErrors.toString(); } /** * Run the checks for the default set with default parameters. This is equivalent * to calling check(false, true). If the default set has not yet been * used at all, it is created here with the default settings. *

* @return A boolean indicating whether all checks were successful or not */ public boolean check() { if (getSet(DEFAULT_SET) == null) { addSet(DEFAULT_SET, defaultMinData, defaultMaxData); } return check(DEFAULT_SET, false, true); } /** * Run the checks for the default set. If the default set has not yet been * used at all, it is created here with the default settings. *

* @param ignoreUnmatched A boolean to select whether unmatched options can be ignored in the checks or not * @param requireDataLast A boolean to indicate whether the data items have to be the last ones on the command line or not *

* @return A boolean indicating whether all checks were successful or not */ public boolean check(boolean ignoreUnmatched, boolean requireDataLast) { if (getSet(DEFAULT_SET) == null) { addSet(DEFAULT_SET, defaultMinData, defaultMaxData); } return check(DEFAULT_SET, ignoreUnmatched, requireDataLast); } /** * Run the checks for the given set with default parameters. This is equivalent * to calling check(name, false, true). *

* @param name The name for the set to check *

* @return A boolean indicating whether all checks were successful or not */ public boolean check(String name) { return check(name, false, true); } /** * Run the checks for the given set. *

* @param name The name for the set to check * @param ignoreUnmatched A boolean to select whether unmatched options can be ignored in the checks or not * @param requireDataLast A boolean to indicate whether the data items have to be the last * ones on the command line or not *

* @return A boolean indicating whether all checks were successful or not */ public boolean check(String name, boolean ignoreUnmatched, boolean requireDataLast) { if (name == null) { throw new IllegalArgumentException(CLASS + ": name may not be null"); } if (optionSets.get(name) == null) { throw new IllegalArgumentException(CLASS + ": Unknown OptionSet: " + name); } checkErrors.append("Checking set "); checkErrors.append(name); checkErrors.append('\n'); //.... Access the data for the set to use OptionSet set = optionSets.get(name); java.util.List options = set.getOptionData(); java.util.List data = set.getData(); java.util.List unmatched = set.getUnmatched(); //.... Catch some trivial cases if (options.size() == 0) { // No options have been defined at all if (arguments.length == 0) { if (set.acceptsData()) { checkErrors.append("The set expects data, but no arguments have been given\n"); return false; } else { // No options and no data expected, no arguments given - technically true, but useless return true; } } } else if (arguments.length == 0) { // Options have been defined, but no arguments given checkErrors.append("Options have been defined, but no arguments have been given; nothing to check\n"); return false; } //.... Parse all the arguments given int ipos = 0; int offset = 0; int start = 0; java.util.regex.Matcher m = null; String value = null; String detail = null; String next = null; String key = null; String pre = defaultPrefix.getName(); String altPre = defaultAltPrefix.getName(); boolean add = true; boolean[] matched = new boolean[arguments.length]; for (int i = 0; i < matched.length; i++) // Initially, we assume there was no match at all { matched[i] = false; } while (true) { value = null; detail = null; offset = 0; start = 1; add = true; key = arguments[ipos]; for (OptionData optionData : options) { // For each argument, we need to check all defined options m = optionData.getPattern().matcher(key); if (m.lookingAt()) { if (optionData.useValue()) { // The code section for value options if (optionData.hasAlternateKey()) { start = 2; } if (optionData.useDetail()) { detail = m.group(start); offset = 2; // required for correct Matcher.group access below } if (optionData.getSeparator() == Separator.BLANK) { // In this case, the next argument must be the value if (ipos + 1 == arguments.length) { // The last argument, thus no value follows it: Error checkErrors.append("At end of arguments - no value found following argument "); checkErrors.append(key); checkErrors.append('\n'); add = false; } else { next = arguments[ipos + 1]; if (next.startsWith(pre) || next.startsWith(altPre)) { // The next item is not a value: Error checkErrors.append("No value found following argument "); checkErrors.append(key); checkErrors.append('\n'); add = false; } else { value = next; matched[ipos++] = true; // Mark the key and the value matched[ipos] = true; } } } else { // The value follows the separator in this case value = m.group(start + offset); matched[ipos] = true; } } else { // Simple, non-value options matched[ipos] = true; } if (add) { optionData.addResult(value, detail); // Store the result } break; // No need to check more options, we have a match } } ipos++; // Advance to the next argument to check if (ipos >= arguments.length) { break; } // Terminating condition for the check loop } //.... Identify unmatched arguments and actual (non-option) data int first = -1; // Required later for requireDataLast for (int i = 0; i < matched.length; i++) { // Assemble the list of unmatched options if (!matched[i]) { if (arguments[i].startsWith(pre) || arguments[i].startsWith(altPre)) { // An unmatched option unmatched.add(arguments[i]); checkErrors.append("No matching option found for argument "); checkErrors.append(arguments[i]); checkErrors.append('\n'); } else { // This is actual data if (first < 0) { first = i; } data.add(arguments[i]); } } } //.... Checks to determine overall success, start with the multiplicity of options boolean err = true; for (OptionData optionData : options) { if (!optionData.isExclusive()) { // Only check options which are not part of an ExclusiveConstraint key = optionData.getKey(); err = false; // Local check result for one option switch (optionData.getMultiplicity()) { case ONCE: if (optionData.getResultCount() != 1) { err = true; } break; case ONCE_OR_MORE: if (optionData.getResultCount() == 0) { err = true; } break; case ZERO_OR_ONCE: if (optionData.getResultCount() > 1) { err = true; } break; } if (err) { checkErrors.append("Wrong number of occurences found for argument "); checkErrors.append(pre); checkErrors.append(key); checkErrors.append('\n'); return false; } } } //.... Check defined constraints for all options for (OptionData optionData : options) { if (optionData.isSet() && (optionData.getConstraints() != null)) { for (Constraint constraint : optionData.getConstraints()) { if (!constraint.isSatisfied()) { checkErrors.append("Constraint "); checkErrors.append(constraint.toString()); checkErrors.append(" violated for option '"); checkErrors.append(optionData.getKey()); checkErrors.append("'\n"); return false; } } } } //.... Check defined constraints for the current set if (set.getConstraints() != null) { for (Constraint constraint : set.getConstraints()) { if (!constraint.isSatisfied()) { checkErrors.append("Constraint "); checkErrors.append(constraint.toString()); checkErrors.append(" violated for option set '"); checkErrors.append(set.getName()); checkErrors.append("'\n"); return false; } } } //.... Check range for data int limit = set.getMaxData(); if (set.hasUnlimitedData()) { limit = Integer.MAX_VALUE; } if (data.size() < set.getMinData() || data.size() > limit) { checkErrors.append("Invalid number of data arguments: "); checkErrors.append(data.size()); checkErrors.append(" (allowed range: "); checkErrors.append(set.getMinData()); checkErrors.append(" ... "); checkErrors.append(set.getMaxData()); checkErrors.append(")\n"); return false; } //.... Check for location of the data in the list of command line arguments if (requireDataLast && data.size() > 0) { if (first + data.size() != arguments.length) { checkErrors.append("Invalid data specification: data arguments are not the last ones on the command line\n"); return false; } } //.... Check for unmatched arguments if (!ignoreUnmatched && unmatched.size() > 0) { return false; } // Don't accept unmatched arguments //.... If we made it to here, all checks were successful return true; } // ========================================================================================== // Add a value option for all sets // ========================================================================================== /** * Add the given option to all known sets. *

* @param type The type of the option * @param key The name of the option */ public void addOptionAllSets(OptionData.Type type, String key) { for (String name : optionSets.keySet()) { optionSets.get(name).addOption(type, key, null, type.detail() ? defaultDetailSeparator : defaultValueSeparator, defaultMultiplicity); } } /** * Add the given option to all known sets. *

* @param type The type of the option * @param key The name of the option * @param multiplicity The multiplicity of the option */ public void addOptionAllSets(OptionData.Type type, String key, Multiplicity multiplicity) { for (String name : optionSets.keySet()) { optionSets.get(name).addOption(type, key, null, type.detail() ? defaultDetailSeparator : defaultValueSeparator, multiplicity); } } /** * Add the given option to all known sets. *

* @param type The type of the option * @param key The name of the option * @param altKey The alternate name of the option */ public void addOptionAllSets(OptionData.Type type, String key, String altKey) { for (String name : optionSets.keySet()) { optionSets.get(name).addOption(type, key, altKey, type.detail() ? defaultDetailSeparator : defaultValueSeparator, defaultMultiplicity); } } /** * Add the given option to all known sets. *

* @param type The type of the option * @param key The name of the option * @param altKey The alternate name of the option * @param multiplicity The multiplicity of the option */ public void addOptionAllSets(OptionData.Type type, String key, String altKey, Multiplicity multiplicity) { for (String name : optionSets.keySet()) { optionSets.get(name).addOption(type, key, altKey, type.detail() ? defaultDetailSeparator : defaultValueSeparator, multiplicity); } } } options/src/ml/options/OptionData.java0000644000000000000000000005114010751433560017053 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; import java.util.ArrayList; import java.util.List; /** * This class holds all the data for an option. This includes the prefix, the key, the separators * (for value and detail options), the multiplicity, and all the other settings describing the option. The class * is designed to be only a data container from a user perspective, i. e. the user has access to * any data determined by the {@link Options#check()} methods, but not access to any of the other methods * which are used internally for the operation of the actual check. */ public class OptionData implements Constrainable { private final static String CLASS = "OptionData"; private Options.Prefix prefix = null; private Options.Prefix altPrefix = null; private String key = null; private String altKey = null; private String helpText = ""; private String valueText = "value"; private String detailText = "detail"; private boolean detail = false; private Options.Separator separator = null; private boolean value = false; private boolean exclusive = false; private Options.Multiplicity multiplicity = null; private java.util.regex.Pattern pattern = null; private int counter = 0; private java.util.List values = null; private java.util.List details = null; private java.util.List constraints = null; private Type type = null; /** * An enum describing the different available types of options */ public enum Type { /** * An option which acts as a switch (i. e. no value or detail argument is taken) */ SIMPLE(false, false), /** * An option which expects a value to be specified along with it */ VALUE(true, false), /** * An option which expects both a value and details further describing the value to be specified along with it */ DETAIL(true, true); boolean value = false; boolean detail = false; Type(boolean value, boolean detail) { this.value = value; this.detail = detail; } boolean value() { return value; } boolean detail() { return detail; } } /** * A copying constructor. This is for setup purposes only, i. e. result data is NOT copied. */ OptionData(OptionData od) { this(od.getType(), od.getPrefix(), od.getAltPrefix(), od.getKey(), od.getAltKey(), od.getSeparator(), od.getMultiplicity()); this.helpText = od.getHelpText(); this.valueText = od.getValueText(); this.detailText = od.getDetailText(); } /** * The constructor */ OptionData(Type type, Options.Prefix prefix, Options.Prefix altPrefix, String key, String altKey, Options.Separator separator, Options.Multiplicity multiplicity) { if (type == null) { throw new IllegalArgumentException(CLASS + ": type may not be null"); } if (prefix == null) { throw new IllegalArgumentException(CLASS + ": prefix may not be null"); } if (altPrefix == null) { throw new IllegalArgumentException(CLASS + ": altPrefix may not be null"); } if (key == null) { throw new IllegalArgumentException(CLASS + ": key may not be null"); } if (multiplicity == null) { throw new IllegalArgumentException(CLASS + ": multiplicity may not be null"); } //.... The data describing the option this.type = type; this.prefix = prefix; this.altPrefix = altPrefix; this.key = key; this.altKey = altKey; this.separator = separator; this.multiplicity = multiplicity; value = type.value(); detail = type.detail(); //.... Create the pattern to match this option String keyPattern = null; if (altKey == null) { keyPattern = prefix.getName() + key; } else { keyPattern = "(" + prefix.getName() + key + "|" + altPrefix.getName() + altKey + ")"; } if (value) { if (separator.equals(Options.Separator.BLANK)) { if (detail) { pattern = java.util.regex.Pattern.compile(keyPattern + "((\\w|\\.)+)$"); } else { pattern = java.util.regex.Pattern.compile(keyPattern + "$"); } } else { if (detail) { pattern = java.util.regex.Pattern.compile(keyPattern + "((\\w|\\.)+)" + separator.getName() + "(.+)$"); } else { pattern = java.util.regex.Pattern.compile(keyPattern + separator.getName() + "(.+)$"); } } } else { pattern = java.util.regex.Pattern.compile(keyPattern + "$"); } //.... Structures to hold result data if (value) { values = new java.util.ArrayList(); if (detail) { details = new java.util.ArrayList(); } } } // ========================================================================================== // Inquiry methods // ========================================================================================== /** * Check whether this option has a defined alternate key value *

* @return A boolean indicating whether this option has a defined alternate key value */ boolean hasAlternateKey() { return altKey == null ? false : true; } /** * Getter method for prefix property *

* @return The value for the prefix property */ Options.Prefix getPrefix() { return prefix; } /** * Getter method for altPrefix property *

* @return The value for the altPprefix property */ Options.Prefix getAltPrefix() { return altPrefix; } /** * Getter method for type property *

* @return The value for the type property */ Type getType() { return type; } /** * Getter method for key property *

* @return The value for the key property */ String getKey() { return key; } /** * Getter method for altKey property *

* @return The value for the altKey property */ String getAltKey() { return altKey; } /** * Getter method for detail property *

* @return The value for the detail property */ boolean useDetail() { return detail; } /** * Getter method for separator property *

* @return The value for the separator property */ Options.Separator getSeparator() { return separator; } /** * Getter method for value property *

* @return The value for the value property */ boolean useValue() { return value; } /** * Getter method for multiplicity property *

* @return The value for the multiplicity property */ Options.Multiplicity getMultiplicity() { return multiplicity; } /** * Setter method for multiplicity property *

* @param multiplicity The value for the multiplicity property */ void setMultiplicity(Options.Multiplicity multiplicity) { if (multiplicity == null) { throw new IllegalArgumentException(CLASS + ": multiplicity may not be null"); } this.multiplicity = multiplicity; } /** * Getter method for pattern property *

* @return The value for the pattern property */ java.util.regex.Pattern getPattern() { return pattern; } // ========================================================================================== // Result management // ========================================================================================== /** * Check whether this option has been found on the command line *

* @return A boolean indicating whether this option has been found on the command line */ public boolean isSet() { return getResultCount() > 0 ? true : false; } /** * Get the number of results found for this option, which is number of times the key matched *

* @return The number of results */ public int getResultCount() { if (value) { return values.size(); } else { return counter; } } /** * Get the value with the given index. The index can range between 0 and {@link #getResultCount()} - 1. * However, only for value options, a non-null value will be returned. Non-value options always * return null. *

* @param index The index for the desired value *

* @return The option value with the given index */ public String getResultValue(int index) { if (!value) { return null; } if (index < 0 || index >= getResultCount()) { throw new IllegalArgumentException(CLASS + ": illegal value for index"); } return values.get(index); } /** * Return a list of all result values *

* @return A list with all result values */ public List getResultValues() { List list = new ArrayList(); for (int index = 0; index < getResultCount(); index++) { list.add(getResultValue(index)); } return list; } /** * Get the detail with the given index. The index can range between 0 and {@link #getResultCount()} - 1. * However, only for value options which take details, a non-null detail will be returned. Non-value options * and value options which do not take details always return null. *

* @param index The index for the desired value *

* @return The option detail with the given index */ public String getResultDetail(int index) { if (!detail) { return null; } if (index < 0 || index >= getResultCount()) { throw new IllegalArgumentException(CLASS + ": illegal value for index"); } return details.get(index); } /** * Return a list of all option details *

* @return A list with all option details */ public List getResultDetails() { List list = new ArrayList(); for (int index = 0; index < getResultCount(); index++) { list.add(getResultDetail(index)); } return list; } /** * Store the data for a match found */ void addResult(String valueData, String detailData) { if (value) { if (valueData == null) { throw new IllegalArgumentException(CLASS + ": valueData may not be null"); } values.add(valueData); if (detail) { if (detailData == null) { throw new IllegalArgumentException(CLASS + ": detailData may not be null"); } details.add(detailData); } } counter++; } // ========================================================================================== // Description management // ========================================================================================== /** * Set the text to be used for the <value> argument of a value option. * This is used in the {@link HelpPrinter} output. *

* @param text The text used for the <value> argument of a value option *

* @return The option instance itself to allow incovation chaining */ public OptionData setValueText(String text) { if (text == null) { throw new IllegalArgumentException(CLASS + ": text may not be null"); } this.valueText = text.trim(); return this; } /** * Set the text to be used for the <detail> argument of a value option. * This is used in the {@link HelpPrinter} output. *

* @param text The text used for the <detail> argument of a value option *

* @return The option instance itself to allow incovation chaining */ public OptionData setDetailText(String text) { if (text == null) { throw new IllegalArgumentException(CLASS + ": text may not be null"); } this.detailText = text.trim(); return this; } /** * Set the text describing the purpose of the option. This is used in the {@link HelpPrinter} output. *

* @param text The text describing the purpose of the option *

* @return The option instance itself to allow incovation chaining */ public OptionData setHelpText(String text) { if (text == null) { throw new IllegalArgumentException(CLASS + ": text may not be null"); } this.helpText = text.trim(); return this; } /** * Return the text describing the purpose of the option *

* @return The text describing the purpose of the option (or an empty string, if that text has not been set) */ public String getHelpText() { return helpText; } /** * Return the text to be used for the <value> argument of a value option *

* @return The text to be used for the <value> argument of a value option (or a default value if this * text has not been set, or if this is not a value option at all) */ public String getValueText() { return valueText; } /** * Return the text to be used for the <detail> argument of a detail option *

* @return The text to be used for the <detail> argument of a detail option (or a default value if this * text has not been set, or if this is not a detail option at all) */ public String getDetailText() { return detailText; } /** * Add a constraint for this option *

* @param constraint The {@link Constraint} to add */ @Override public void addConstraint(Constraint constraint) { if (constraint == null) { throw new IllegalArgumentException(CLASS + ": constraint may not be null"); } if (!constraint.supports(this)) { throw new IllegalArgumentException(CLASS + ": the given constraint can not be applied to options"); } if (constraints == null) { constraints = new java.util.ArrayList(); } constraints.add(constraint); } /** * */ boolean isExclusive() { return exclusive; } /** * */ void setExclusive(boolean exclusive) { this.exclusive = exclusive; } /** * Get the constraints defined for this option *

* @return The defined constraints for this option (or null if no constraints have been defined) */ @Override public java.util.List getConstraints() { return constraints; } /** * Get the command line syntax for this option. This method accounts for all characteristics * of the option such as separators, multiplicity, alternate keys and the like. *

* @return A string with the command line syntax */ public String getSyntax() { StringBuilder sb = new StringBuilder(20); boolean mult = (multiplicity == Options.Multiplicity.ZERO_OR_MORE) || (multiplicity == Options.Multiplicity.ONCE_OR_MORE) ? true : false; boolean opt = (multiplicity == Options.Multiplicity.ONCE_OR_MORE) || (multiplicity == Options.Multiplicity.ONCE) ? false : true; if (opt) { sb.append('['); } // Option can also be omitted printFullOption(sb, mult); if (opt) { sb.append(']'); } // Option can also be omitted return sb.toString(); } /** * Helper method: print the full text for an option, accounting for multiplicity */ void printFullOption(StringBuilder sb, boolean mult) { printOption(sb); if (mult) { // Option can occur more than once printTexts(sb, 1); sb.append(" ["); printOption(sb); printTexts(sb, 2); sb.append(" [...]]"); } else { printTexts(sb, 0); } } /** * Helper method: add the descriptive texts for value and detail options */ void printTexts(StringBuilder sb, int i) { if (detail) { sb.append('<'); sb.append(detailText); if (i > 0) { sb.append(i); } sb.append('>'); } if (value) { sb.append(separator.getName()); sb.append('<'); sb.append(valueText); if (i > 0) { sb.append(i); } sb.append('>'); } } /** * Helper method: prints the key and - if present - the alternate key for an option, adds () if necessary */ void printOption(StringBuilder sb) { if (altKey != null) { sb.append('('); } sb.append(prefix.getName()); sb.append(key); if (altKey != null) { sb.append('|'); sb.append(altPrefix.getName()); sb.append(altKey); sb.append(')'); } } /** * This is the overloaded {@link Object#toString()} method. *

* @return A string representing the instance */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Prefix : "); sb.append(prefix); sb.append('\n'); sb.append("AltPrefix : "); sb.append(altPrefix); sb.append('\n'); sb.append("Key : "); sb.append(key); sb.append('\n'); if (hasAlternateKey()) { sb.append("AltKey : "); sb.append(altKey); sb.append('\n'); } sb.append("Detail : "); sb.append(detail); sb.append('\n'); sb.append("Separator : "); sb.append(separator); sb.append('\n'); sb.append("Value : "); sb.append(value); sb.append('\n'); sb.append("Multiplicity: "); sb.append(multiplicity); sb.append('\n'); sb.append("Pattern : "); sb.append(pattern); sb.append('\n'); sb.append("HelpText : "); sb.append(helpText); sb.append('\n'); sb.append("ValueText : "); sb.append(valueText); sb.append('\n'); sb.append("DetailText : "); sb.append(detailText); sb.append('\n'); if (constraints != null) { for (Constraint constraint : constraints) { sb.append("Constraint : "); sb.append(constraint.toString()); sb.append('\n'); } } sb.append("Results # : "); sb.append(counter); sb.append('\n'); if (value) { if (detail) { for (int i = 0; i < values.size(); i++) { sb.append(details.get(i)); sb.append(" / "); sb.append(values.get(i)); sb.append('\n'); } } else { for (int i = 0; i < values.size(); i++) { sb.append(values.get(i)); sb.append('\n'); } } } return sb.toString(); } } options/src/ml/options/HelpPrinter.java0000644000000000000000000000315610751433560017251 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * This interface is supposed to be implemented by all classes providing help printing * capabilities. */ public interface HelpPrinter { /** * Return a string with the command line syntax for this option set *

* @param set The {@link OptionSet} to format the output for * @param leadingText The text to precede the command line * @param lineBreak A boolean indicating whether the command line for the option set should * be printed with line breaks after each option or not *

* @return A string with the command line syntax for this option set */ public String getCommandLine(OptionSet set, String leadingText, boolean lineBreak); /** * Return the help text describing the different options and data arguments *

* @param set The {@link OptionSet} to format the output for *

* @return A string with the help text for this option set */ public String getHelpText(OptionSet set); } options/src/ml/options/ValueConstraint.java0000644000000000000000000003677710751433560020155 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * A constraint for options taking a value. It allows to constrain the values * acceptable for such an option to e. g. a list of strings. */ public class ValueConstraint implements XMLConstraint { private static final String CLASS = "ValueConstraint"; /** * An enum with the supported subtypes for this constraint type */ public enum Type { /** * A type defining a set of acceptable string values */ STRING_ARRAY, /** * A type defining a set of acceptable int values */ INT_ARRAY, /** * A type defining a range of acceptable int values */ INT_RANGE; } private String[] s_values = null; private int[] i_values = null; private int imin = 0; private int imax = 0; private boolean caseSensitive = true; private Type type = null; private OptionData optionData = null; /** * The public no-org constructor. This is a prereq for all constraints since it is used * for initialization based on XML data. */ public ValueConstraint() { } /** * This method is used to initialize this constraint based on data read from an XML configuration * file. The method is invoked internally during setup with the instance of * {@link Constrainable} to which the constraint applies and a list of JDOM elements, * which contain the details about the constraint itself. *

* This method initializes the constraint and attaches it to the list of constraints * of the {@link Constrainable} instance. *

* The parameters expected in the XML <param> tags for this constraint * are *

* *
Name Value Status *
type Same as the type parameter in {@link #add(OptionData, Type, String)} Required *
spec Same as the spec parameter in {@link #add(OptionData, Type, String)} Required *
*

* @param constrainable The {@link Constrainable} instance to which this constraint applies * @param list A list of JDOM elements to be used to initialize the constraint. Specifically, * these are tags of the form *

* <param name="..." value="..." /> *

* containing key/value pairs with information. */ @Override public void init(Constrainable constrainable, java.util.List list) { if (list == null) { throw new IllegalArgumentException(CLASS + ": list may not be null"); } if (constrainable == null) { throw new IllegalArgumentException(CLASS + ": constrainable may not be null"); } if (!supports(constrainable)) { throw new IllegalArgumentException(CLASS + ": Constrainable must be instance of OptionData"); } //.... Extract all parameters java.util.Map params = new java.util.HashMap(); for (org.jdom.Element param : list) { params.put(param.getAttributeValue("name").trim(), param.getAttributeValue("value").trim()); } //.... Checks if (!params.containsKey("type")) { throw new IllegalArgumentException(CLASS + ": missing element with attribute named 'type'"); } if (!params.containsKey("spec")) { throw new IllegalArgumentException(CLASS + ": missing element with attribute named 'spec'"); } //.... Add the constraint add((OptionData) constrainable, Type.valueOf(params.get("type")), params.get("spec")); } /** * Add a constraint of {@link Type} STRING_ARRAY for the given option *

* @param optionData * @param values A string array with the acceptable values for the option * @param caseSensitive Whether the string comparisons are to be made case sensitive or not */ public static void add(OptionData optionData, String[] values, boolean caseSensitive) { if (optionData == null) { throw new IllegalArgumentException(CLASS + ": optionData may not be null"); } optionData.addConstraint(new ValueConstraint(optionData, values, caseSensitive)); } /** * Add a constraint of {@link Type} INT_ARRAY for the given option *

* @param optionData * @param values An integer array with the acceptable values for the option */ public static void add(OptionData optionData, int[] values) { if (optionData == null) { throw new IllegalArgumentException(CLASS + ": optionData may not be null"); } optionData.addConstraint(new ValueConstraint(optionData, values)); } /** * Add a constraint of {@link Type} INT_RANGE for the given option *

* @param optionData * @param imin The minimum acceptable integer value * @param imax The maximum acceptable integer value (must be greater than or equal to imin) */ public static void add(OptionData optionData, int imin, int imax) { if (optionData == null) { throw new IllegalArgumentException(CLASS + ": optionData may not be null"); } optionData.addConstraint(new ValueConstraint(optionData, imin, imax)); } /** * Add a constraint of the given {@link Type} with the specified details *

* @param optionData * @param type The type for this constraint * @param spec A string specifying the details for this constraint: *

* *
Type Format for specification *
STRING_ARRAY All values separated by vertical bar (e. g. Foo|Bah|Yeah). If the first * string is preceded by '+', the checks are run case insensitive (default * is to run them case sensitive) *
INT_ARRAY All values separated by vertical bar (e. g. 1|2|7) *
INT_RANGE MIN:MAX (e. g. 7:12) *
*/ public static void add(OptionData optionData, Type type, String spec) { if (optionData == null) { throw new IllegalArgumentException(CLASS + ": optionData may not be null"); } optionData.addConstraint(new ValueConstraint(optionData, type, spec)); } /** * Constructor for {@link Type} STRING_ARRAY *

* @param values A string array with the acceptable values for the option * @param caseSensitive Whether the string comparisons are to be made case sensitive or not */ ValueConstraint(OptionData optionData, String[] values, boolean caseSensitive) { if (values == null) { throw new IllegalArgumentException(CLASS + ": values may not be null"); } if (values.length == 0) { throw new IllegalArgumentException(CLASS + ": values must contain at least one element"); } s_values = values; type = Type.STRING_ARRAY; this.caseSensitive = caseSensitive; this.optionData = optionData; } /** * Constructor for {@link Type} INT_ARRAY *

* @param values An integer array with the acceptable values for the option */ ValueConstraint(OptionData optionData, int[] values) { if (values == null) { throw new IllegalArgumentException(CLASS + ": values may not be null"); } if (values.length == 0) { throw new IllegalArgumentException(CLASS + ": values must contain at least one element"); } i_values = values; type = Type.INT_ARRAY; this.optionData = optionData; } /** * Constructor for {@link Type} INT_RANGE *

* @param imin The minimum acceptable integer value * @param imax The maximum acceptable integer value (must be greater than or equal to imin) */ ValueConstraint(OptionData optionData, int imin, int imax) { if (imax < imin) { throw new IllegalArgumentException(CLASS + ": imax must greater than or equal to imin"); } this.imin = imin; this.imax = imax; type = Type.INT_RANGE; this.optionData = optionData; } /** * Constructor for any {@link Type} *

* @param type The type for this constraint * @param spec A string specifying the details for this constraint: *

* *
Type Format for specification *
STRING_ARRAY All values separated by vertical bar (e. g. Foo|Bah|Yeah). If the first * string is preceded by '+', the checks are run case insensitive (default * is to run them case sensitive) *
INT_ARRAY All values separated by vertical bar (e. g. 1|2|7) *
INT_RANGE MIN:MAX (e. g. 7:12) *
*/ ValueConstraint(OptionData optionData, Type type, String spec) { if (type == null) { throw new IllegalArgumentException(CLASS + ": type may not be null"); } if (spec == null) { throw new IllegalArgumentException(CLASS + ": spec may not be null"); } this.type = type; this.optionData = optionData; switch (type) { case STRING_ARRAY: s_values = spec.split("\\|"); if (s_values[0].startsWith("+")) { caseSensitive = false; s_values[0] = s_values[0].substring(1); } break; case INT_ARRAY: s_values = spec.split("\\|"); i_values = new int[s_values.length]; try { int i = 0; for (String s : s_values) { i_values[i++] = Integer.parseInt(s); } } catch (NumberFormatException ex) { throw new IllegalArgumentException(CLASS + ": Invalid specification for type " + type + ": " + spec); } break; case INT_RANGE: s_values = spec.split(":"); if (s_values.length != 2) { throw new IllegalArgumentException(CLASS + ": Invalid specification for type " + type + ": " + spec); } try { imin = Integer.parseInt(s_values[0]); imax = Integer.parseInt(s_values[1]); } catch (NumberFormatException ex) { throw new IllegalArgumentException(CLASS + ": Invalid specification for type " + type + ": " + spec); } break; } } /** * The actual check routine *

* @return A boolean indicating whether the constraint is satisfied or not */ @Override public boolean isSatisfied() { String test = null; for (int i = 0; i < optionData.getResultCount(); i++) { test = optionData.getResultValue(i); switch (type) { case STRING_ARRAY: if (caseSensitive) { for (String s : s_values) { if (s.equals(test)) { return true; } } } else { for (String s : s_values) { if (s.equalsIgnoreCase(test)) { return true; } } } break; case INT_ARRAY: int t = 0; try { t = Integer.parseInt(test); } catch (NumberFormatException ex) { return false; } for (int ii : i_values) { if (ii == t) { return true; } } break; case INT_RANGE: t = 0; try { t = Integer.parseInt(test); } catch (NumberFormatException ex) { return false; } if ((t >= imin) && (t <= imax)) { return true; } break; } } return false; } /** * Indicates whether a constraint supports a given type of {@link Constrainable} *

* @param constrainable * @return A boolean to indicate whether this {@link Constrainable} is supported. This constraint only * supports {@link OptionData} constrainables */ @Override public boolean supports(Constrainable constrainable) { if (constrainable == null) { throw new IllegalArgumentException(CLASS + ": constrainable may not be null"); } if (constrainable instanceof OptionData) { return true; } else { return false; } } /** * Return the type for this constraint *

* @return The type for this constraint */ Type getType() { return type; } /** * This is the overloaded {@link Object#toString()} method *

* @return A string representing the instance */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(type.name()); sb.append(": "); switch (type) { case STRING_ARRAY: if (!caseSensitive) { sb.append('+'); } for (String s : s_values) { sb.append(s); sb.append('|'); } sb.deleteCharAt(sb.length() - 1); break; case INT_ARRAY: for (int i : i_values) { sb.append(i); sb.append('|'); } sb.deleteCharAt(sb.length() - 1); break; case INT_RANGE: sb.append(imin); sb.append(':'); sb.append(imax); break; } return sb.toString(); } } options/src/ml/options/ExclusiveConstraint.java0000644000000000000000000002274010751433560021031 0ustar rootroot/** * Copyright 2007 Dr. Matthias Laux * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ml.options; /** * A constraint combining one or more options such that just one of them * can occur. This type of constraint can only be added to an option set as * it combines one or more options. *

* Constraints of this kind are also accounted for in the {@link DefaultHelpPrinter} * to format the output provided. */ public class ExclusiveConstraint implements XMLConstraint { private static final String CLASS = "ExclusiveConstraint"; private java.util.List optionData = new java.util.ArrayList(); private Options.Multiplicity multiplicity = null; /** * The public no-org constructor. This is a prereq for all constraints since it is used * for initialization based on XML data. */ public ExclusiveConstraint() { } /** * This method is used to initialize this constraint based on data read from an XML configuration * file. The method is invoked internally during setup with the instance of * {@link Constrainable} to which the constraint applies and a list of JDOM elements, * which contain the details about the constraint itself. *

* This method initializes the constraint and attaches it to the list of constraints * of the {@link Constrainable} instance. *

* The parameters expected in the XML <param> tags for this constraint * are *

* *
Name Value Status *
keys Same as the keys * parameter in {@link #add(OptionSet, Options.Multiplicity, String[])} Required *
mult Same as the multiplicity * parameter in {@link #add(OptionSet, Options.Multiplicity, String[])} Optional *
*

* @param constrainable The {@link Constrainable} instance to which this constraint applies * @param list A list of JDOM elements to be used to initialize the constraint. Specifically, * these are tags of the form *

* <param name="..." value="..." /> *

* containing key/value pairs with information. */ @Override public void init(Constrainable constrainable, java.util.List list) { if (list == null) { throw new IllegalArgumentException(CLASS + ": list may not be null"); } if (constrainable == null) { throw new IllegalArgumentException(CLASS + ": constrainable may not be null"); } if (!supports(constrainable)) { throw new IllegalArgumentException(CLASS + ": Constrainable must be instance of OptionSet"); } //.... Extract all parameters java.util.Map params = new java.util.HashMap(); for (org.jdom.Element param : list) { params.put(param.getAttributeValue("name").trim(), param.getAttributeValue("value").trim()); } //.... Checks if (!params.containsKey("keys")) { throw new IllegalArgumentException(CLASS + ": missing element with attribute named 'keys'"); } Options.Multiplicity mult = Options.Multiplicity.valueOf(params.get("mult")); //.... Add the constraint if (params.containsKey("mult")) { add((OptionSet) constrainable, mult, params.get("keys").split("\\|")); } else { add((OptionSet) constrainable, params.get("keys").split("\\|")); } } /** * Add a constraint to the given option set *

* @param optionSet The {@link OptionSet} to add this constraint to * @param multiplicity The {@link Options.Multiplicity} to use for all options tied together by these constraints. * A Multiplicity defined previously for any option contained in this constraint * is overridden. * @param keys The keys of the options to tie together by this constraint. At least two keys * must be given here, and the corresponding options must already be defined in the set. */ public static void add(OptionSet optionSet, Options.Multiplicity multiplicity, String... keys) { if (optionSet == null) { throw new IllegalArgumentException(CLASS + ": optionSet may not be null"); } if (multiplicity == null) { throw new IllegalArgumentException(CLASS + ": multiplicity may not be null"); } if (keys.length < 2) { throw new IllegalArgumentException(CLASS + ": at least two keys must be provided"); } optionSet.addConstraint(new ExclusiveConstraint(optionSet, multiplicity, keys)); } /** * Add a constraint to the given option set using the default multiplicity defined for this set *

* @param optionSet The {@link OptionSet} to add this constraint to * @param keys The keys of the options to tie together by this constraint. At least two keys * must be given here, and the corresponding options must already be defined in the set. */ public static void add(OptionSet optionSet, String... keys) { if (optionSet == null) { throw new IllegalArgumentException(CLASS + ": optionSet may not be null"); } if (keys.length < 2) { throw new IllegalArgumentException(CLASS + ": at least two keys must be provided"); } optionSet.addConstraint(new ExclusiveConstraint(optionSet, optionSet.getDefaultMultiplicity(), keys)); } /** * Constructor */ ExclusiveConstraint(OptionSet optionSet, Options.Multiplicity multiplicity, String[] keys) { OptionData od = null; for (String key : keys) { od = optionSet.getOption(key); if (od.isExclusive()) { throw new IllegalArgumentException(CLASS + ": option '" + key + "' is already part of an " + CLASS); } optionData.add(od); od.setExclusive(true); od.setMultiplicity(multiplicity); this.multiplicity = multiplicity; } } /** * */ Options.Multiplicity getMultiplicity() { return multiplicity; } /** * */ java.util.List getOptionData() { return optionData; } /** * Indicates whether a constraint supports a given type of {@link Constrainable} *

* @param constrainable * @return A boolean to indicate whether this {@link Constrainable} is supported. This constraint only * supports {@link OptionSet} constrainables */ @Override public boolean supports(Constrainable constrainable) { if (constrainable == null) { throw new IllegalArgumentException(CLASS + ": constrainable may not be null"); } if (constrainable instanceof OptionSet) { return true; } else { return false; } } /** * The actual check routine *

* @return A boolean indicating whether the constraint is satisfied or not */ @Override public boolean isSatisfied() { //.... Check whether only one of the grouped options appears boolean found = false; OptionData odata = null; for (OptionData od : optionData) { if (od.getResultCount() > 0) { if (found) { return false; } // We found the second one - failure found = true; // We found the first one odata = od; } } if (!found) { return false; } // No occurence found - constraint not satisfied //.... Check multiplicity for the one option found switch (multiplicity) { case ONCE: if (odata.getResultCount() != 1) { return false; } break; case ONCE_OR_MORE: if (odata.getResultCount() == 0) { return false; } break; case ZERO_OR_ONCE: if (odata.getResultCount() > 1) { return false; } break; } return true; } /** * This is the overloaded {@link Object#toString()} method *

* @return A string representing the instance */ @Override public String toString() { StringBuilder sb = new StringBuilder(); for (OptionData od : optionData) { sb.append(od.getKey()); sb.append("|"); } sb.deleteCharAt(sb.length() - 1); return sb.toString(); } } options/src/config/0000755000000000000000000000000011646610374013313 5ustar rootrootoptions/src/config/options.xsd0000644000000000000000000002013210750122432015510 0ustar rootroot options/LICENSE-2.0.txt0000644000000000000000000002613610717315126013402 0ustar rootroot Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. options/nbproject/0000755000000000000000000000000011703663326013244 5ustar rootrootoptions/nbproject/project.xml0000644000000000000000000000110111244760356015426 0ustar rootroot org.netbeans.modules.java.j2seproject options 1.6.5 options/nbproject/build-impl.xml0000644000000000000000000015602011703661776016037 0ustar rootroot Must set src.dir Must set test.src.dir Must set build.dir Must set dist.dir Must set build.classes.dir Must set dist.javadoc.dir Must set build.test.classes.dir Must set build.test.results.dir Must set build.classes.excludes Must set dist.jar Must set javac.includes Must set JVM to use for profiling in profiler.info.jvm Must set profiler agent JVM arguments in profiler.info.jvmargs.agent Must select some files in the IDE or set javac.includes To run this application from the command line without Ant, try: java -cp "${run.classpath.with.dist.jar}" ${main.class} To run this application from the command line without Ant, try: java -jar "${dist.jar.resolved}" Must select one file in the IDE or set run.class Must select one file in the IDE or set run.class Must select one file in the IDE or set debug.class Must select one file in the IDE or set debug.class Must set fix.includes Must select one file in the IDE or set profile.class Must select some files in the IDE or set javac.includes Some tests failed; see details above. Must select some files in the IDE or set test.includes Some tests failed; see details above. Must select one file in the IDE or set test.class Must select one file in the IDE or set applet.url Must select one file in the IDE or set applet.url options/nbproject/private/0000755000000000000000000000000011703663326014716 5ustar rootrootoptions/nbproject/private/private.xml0000644000000000000000000000032311426061610017076 0ustar rootroot options/nbproject/private/private.properties0000644000000000000000000000044311703663326020507 0ustar rootrootapplication.args= compile.on.save=false do.depend=false do.jar=true javac.debug=true javadoc.preview=true jaxbwiz.endorsed.dirs=C:\\Program Files\\NetBeans 6.8\\ide12\\modules\\ext\\jaxb\\api user.properties.file=C:\\Documents and Settings\\i000698\\.netbeans\\7.0\\build.properties options/nbproject/private/config.properties0000644000000000000000000000000011244760356020270 0ustar rootrootoptions/nbproject/project.properties0000644000000000000000000000464411703663326017040 0ustar rootrootannotation.processing.enabled=true annotation.processing.enabled.in.editor=false annotation.processing.run.all.processors=true application.args= application.title=options application.vendor= build.classes.dir=${build.dir}/classes build.classes.excludes=**/*.java,**/*.form # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated build.generated.sources.dir=${build.dir}/generated-sources # Only compile against the classpath explicitly listed here: build.sysclasspath=ignore build.test.classes.dir=${build.dir}/test/classes build.test.results.dir=${build.dir}/test/results debug.classpath=\ ${run.classpath} debug.test.classpath=\ ${run.test.classpath} # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/options.jar dist.javadoc.dir=${dist.dir}/javadoc endorsed.classpath= excludes= file.reference.jdom-1.1.1.jar=C:\\Work\\Development\\Java\\lib\\jdom-1.1.1.jar includes=** jar.archive.disabled=${jnlp.enabled} jar.compress=false jar.index=${jnlp.enabled} javac.classpath=\ ${file.reference.jdom-1.1.1.jar} # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false javac.processorpath=\ ${javac.classpath} javac.source=1.6 javac.target=1.6 javac.test.classpath=\ ${javac.classpath}:\ ${build.classes.dir} javadoc.additionalparam= javadoc.author=false javadoc.encoding= javadoc.noindex=false javadoc.nonavbar=false javadoc.notree=false javadoc.private=false javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api" jnlp.codebase.type=no.codebase jnlp.descriptor=application jnlp.enabled=false jnlp.mixed.code=default jnlp.offline-allowed=false jnlp.signed=false jnlp.signing= jnlp.signing.alias= jnlp.signing.keystore= meta.inf.dir=${src.dir}/META-INF mkdist.disabled=false platform.active=default_platform run.classpath=\ ${javac.classpath}:\ ${build.classes.dir} # Space-separated list of JVM arguments used when running the project # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value # or test-sys-prop.name=value to set system properties for unit tests): run.jvmargs= run.test.classpath=\ ${javac.test.classpath}:\ ${build.test.classes.dir} src.dir=src test.src.dir=test options/nbproject/genfiles.properties0000644000000000000000000000073311703661776017170 0ustar rootrootbuild.xml.data.CRC32=32f23a77 build.xml.script.CRC32=e348ee9b build.xml.stylesheet.CRC32=28e38971@1.44.1.45 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=32f23a77 nbproject/build-impl.xml.script.CRC32=35271214 nbproject/build-impl.xml.stylesheet.CRC32=0ae3a408@1.44.1.45