package org.maltparser.core.options;
import java.io.*;
import java.net.URL;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Set;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.maltparser.core.exception.MaltChainedException;
import org.maltparser.core.options.option.ClassOption;
import org.maltparser.core.options.option.Option;
import org.maltparser.core.options.option.UnaryOption;
import org.maltparser.core.plugin.PluginLoader;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Option Manager is the management class for all option handling. All queries
* and manipulations of an option or an option value should go through this
* class.
*
* @author Johan Hall
* @since 1.0
*
*/
public class OptionManager {
public static final int DEFAULTVALUE = -1;
private OptionDescriptions optionDescriptions;
private OptionValues optionValues;
private static OptionManager uniqueInstance = new OptionManager();
/**
* Creates the Option Manager
*/
private OptionManager() {
optionValues = new OptionValues();
optionDescriptions = new OptionDescriptions();
}
/**
* Returns a reference to the single instance.
*/
public static OptionManager instance() {
return uniqueInstance;
}
/**
* Loads the option description file
* <code>/appdata/options.xml</code>
*
* @throws MaltChainedException
*/
public void loadOptionDescriptionFile() throws MaltChainedException {
optionDescriptions.parseOptionDescriptionXMLfile(getClass().getResource("/appdata/options.xml"));
}
/**
* Loads the option description file
*
* @param url URL of the option description file
* @throws MaltChainedException
*/
public void loadOptionDescriptionFile(URL url) throws MaltChainedException {
optionDescriptions.parseOptionDescriptionXMLfile(url);
}
/**
* Returns the option description
*
* @return the option description
*/
public OptionDescriptions getOptionDescriptions() {
return optionDescriptions;
}
/**
* Returns the option value for an option that is specified by the option
* group name and option name. The container name points out the specific
* option container.
*
*
* @param containerIndex The index of the option container (0..n and -1 is
* default values).
* @param optiongroup The name of the option group.
* @param optionname The name of the option.
* @return an object that contains the value of the option, <i>null</i> if
* the option value could not be found.
* @throws OptionException
*/
public Object getOptionValue(int containerIndex, String optiongroup, String optionname) throws MaltChainedException {
Option option = optionDescriptions.getOption(optiongroup, optionname);
if (containerIndex == OptionManager.DEFAULTVALUE) {
return option.getDefaultValueObject();
}
Object value = optionValues.getOptionValue(containerIndex, option);
if (value == null) {
value = option.getDefaultValueObject();
}
return value;
}
public Object getOptionDefaultValue(String optiongroup, String optionname) throws MaltChainedException {
Option option = optionDescriptions.getOption(optiongroup, optionname);
return option.getDefaultValueObject();
}
public Object getOptionValueNoDefault(int containerIndex, String optiongroup, String optionname) throws MaltChainedException {
Option option = optionDescriptions.getOption(optiongroup, optionname);
if (containerIndex == OptionManager.DEFAULTVALUE) {
return option.getDefaultValueObject();
}
return optionValues.getOptionValue(containerIndex, option);
}
/**
* Returns a string representation of the option value for an option that is
* specified by the option group name and the option name. The container
* name points out the specific option container.
*
* @param containerIndex The index of the option container (0..n and -1 is
* default values).
* @param optiongroup The name of the option group.
* @param optionname The name of the option.
* @return a string representation of the option value
* @throws MaltChainedException
*/
public String getOptionValueString(int containerIndex, String optiongroup, String optionname) throws MaltChainedException {
Option option = optionDescriptions.getOption(optiongroup, optionname);
String value = optionValues.getOptionValueString(containerIndex, option);
if (value == null) {
value = option.getDefaultValueString();
}
return value;
}
public String getOptionValueStringNoDefault(int containerIndex, String optiongroup, String optionname) throws MaltChainedException {
return optionValues.getOptionValueString(containerIndex, optionDescriptions.getOption(optiongroup, optionname));
}
/**
* Overloads the option value specified by the container index, the option
* group name, the option name. This method is used to override option that
* have specific dependencies.
*
* @param containerIndex the index of the option container (0..n and -1 is
* default values).
* @param optiongroup the name of the option group.
* @param optionname the name of the option.
* @param value the option value that should replace the current option
* value.
* @throws MaltChainedException
*/
public void overloadOptionValue(int containerIndex, String optiongroup, String optionname, String value) throws MaltChainedException {
Option option = optionDescriptions.getOption(optiongroup, optionname);
if (value == null) {
throw new OptionException("The option value is missing. ");
}
Object ovalue = option.getValueObject(value);
optionValues.addOptionValue(OptionContainer.DEPENDENCIES_RESOLVED, containerIndex, option, ovalue);
}
/**
* Returns the number of option values for a particular option container.
*
* @param containerIndex The index of the option container (0..n).
* @return the number of option values for a particular option container.
*/
public int getNumberOfOptionValues(int containerIndex) {
return optionValues.getNumberOfOptionValues(containerIndex);
}
/**
* Returns a sorted set of container names.
*
* @return a sorted set of container names.
*/
public Set<Integer> getOptionContainerIndices() {
return optionValues.getOptionContainerIndices();
}
/**
* Loads the saved options (options that are marked with
* <code>usage=save</code>).
*
* @param fileName The path to the file where to load the saved options.
* @throws MaltChainedException
*/
public void loadOptions(int containerIndex, String fileName) throws MaltChainedException {
try {
loadOptions(containerIndex, new InputStreamReader(new FileInputStream(fileName), "UTF-8"));
} catch (FileNotFoundException e) {
throw new OptionException("The saved option file '" + fileName + "' cannot be found. ", e);
} catch (UnsupportedEncodingException e) {
throw new OptionException("The charset is unsupported. ", e);
}
}
/**
* Loads the saved options (options that are marked with
* <code>usage=Option.SAVE</code>).
*
* @param isr the input stream reader of the saved options file.
* @throws MaltChainedException
*/
public void loadOptions(int containerIndex, InputStreamReader isr) throws MaltChainedException {
try {
BufferedReader br = new BufferedReader(isr);
String line;
Option option;
Pattern tabPattern = Pattern.compile("\t");
while ((line = br.readLine()) != null) {
String[] items = tabPattern.split(line);
if (items.length < 3 || items.length > 4) {
throw new OptionException("Could not load the saved option. ");
}
option = optionDescriptions.getOption(items[1], items[2]);
Object ovalue;
if (items.length == 3) {
ovalue = "";
} else {
if (option instanceof ClassOption) {
if (items[3].startsWith("class ")) {
Class<?> clazz = null;
if (PluginLoader.instance() != null) {
clazz = PluginLoader.instance().getClass(items[3].substring(6));
}
if (clazz == null) {
clazz = Class.forName(items[3].substring(6));
}
ovalue = option.getValueObject(((ClassOption) option).getLegalValueString(clazz));
} else {
ovalue = option.getValueObject(items[3]);
}
} else {
ovalue = option.getValueObject(items[3]);
}
}
optionValues.addOptionValue(OptionContainer.SAVEDOPTION, containerIndex, option, ovalue);
}
br.close();
} catch (ClassNotFoundException e) {
throw new OptionException("The class cannot be found. ", e);
} catch (NumberFormatException e) {
throw new OptionException("Option container index isn't an integer value. ", e);
} catch (IOException e) {
throw new OptionException("Error when reading the saved options. ", e);
}
}
/**
* Saves all options that are marked as
* <code>usage=Option.SAVE</code>
*
* @param fileName The path to the file where the saveOption should by
* saved.
*/
public void saveOptions(String fileName) throws MaltChainedException {
try {
saveOptions(new OutputStreamWriter(new FileOutputStream(fileName), "UTF-8"));
} catch (FileNotFoundException e) {
throw new OptionException("The file '" + fileName + "' cannot be created. ", e);
} catch (UnsupportedEncodingException e) {
throw new OptionException("The charset 'UTF-8' is unsupported. ", e);
}
}
/**
* Saves all options that are marked as
* <code>usage=Option.SAVE</code>
*
* @param osw the output stream writer of the saved option file
* @throws MaltChainedException
*/
public void saveOptions(OutputStreamWriter osw) throws MaltChainedException {
try {
BufferedWriter bw = new BufferedWriter(osw);
Set<Option> optionToSave = optionDescriptions.getSaveOptionSet();
Object value;
for (Integer index : optionValues.getOptionContainerIndices()) {
for (Option option : optionToSave) {
value = optionValues.getOptionValue(index, option);
if (value == null) {
value = option.getDefaultValueObject();
}
bw.append(index + "\t" + option.getGroup().getName() + "\t" + option.getName() + "\t" + value + "\n");
}
}
bw.flush();
bw.close();
} catch (IOException e) {
throw new OptionException("Error when saving the saved options. ", e);
}
}
/**
* Saves all options that are marked as usage=Option.SAVE for a particular
* option container.
*
* @param containerIndex The index of the option container (0..n).
* @param fileName The path to the file where the saveOption should by
* saved.
*/
public void saveOptions(int containerIndex, String fileName) throws MaltChainedException {
try {
saveOptions(containerIndex, new OutputStreamWriter(new FileOutputStream(fileName), "UTF-8"));
} catch (FileNotFoundException e) {
throw new OptionException("The file '" + fileName + "' cannot be found.", e);
} catch (UnsupportedEncodingException e) {
throw new OptionException("The charset 'UTF-8' is unsupported. ", e);
}
}
/**
* Saves all options that are marked as usage=Option.SAVE for a particular
* option container.
*
* @param containerIndex The index of the option container (0..n).
* @param osw the output stream writer of the saved option file
* @throws MaltChainedException
*/
public void saveOptions(int containerIndex, OutputStreamWriter osw) throws MaltChainedException {
try {
BufferedWriter bw = new BufferedWriter(osw);
Set<Option> optionToSave = optionDescriptions.getSaveOptionSet();
Object value;
for (Option option : optionToSave) {
value = optionValues.getOptionValue(containerIndex, option);
if (value == null) {
value = option.getDefaultValueObject();
}
bw.append(containerIndex + "\t" + option.getGroup().getName() + "\t" + option.getName() + "\t" + value + "\n");
}
bw.flush();
bw.close();
} catch (IOException e) {
throw new OptionException("Error when saving the saved options.", e);
}
}
/**
* Creates several option maps for fast access to individual options.
*
* @throws OptionException
*/
public void generateMaps() throws MaltChainedException {
optionDescriptions.generateMaps();
}
public boolean parseCommandLine(String argString, int containerIndex) throws MaltChainedException {
return parseCommandLine(argString.split(" "), containerIndex);
}
/**
* Parses the command line arguments.
*
* @param args An array of arguments that are supplied when starting the
* application.
* @throws OptionException
*/
public boolean parseCommandLine(String[] args, int containerIndex) throws MaltChainedException {
if (args == null || args.length == 0) {
return false;
}
int i = 0;
HashMap<String, String> oldFlags = new HashMap<String, String>();
oldFlags.put("llo", "lo");
oldFlags.put("lso", "lo");
oldFlags.put("lli", "li");
oldFlags.put("lsi", "li");
oldFlags.put("llx", "lx");
oldFlags.put("lsx", "lx");
oldFlags.put("llv", "lv");
oldFlags.put("lsv", "lv");
while (i < args.length) {
Option option = null;
String value = null;
/*
* Recognizes --optiongroup-optionname=value --optionname=value
* --optiongroup-optionname (unary option) --optionname (unary
* option)
*/
if (args[i].startsWith("--")) {
if (args[i].length() == 2) {
throw new OptionException("The argument contains only '--', please check the user guide to see the correct format. ");
}
String optionstring;
String optiongroup;
String optionname;
int indexEqualSign = args[i].indexOf('=');
if (indexEqualSign != -1) {
value = args[i].substring(indexEqualSign + 1);
optionstring = args[i].substring(2, indexEqualSign);
} else {
value = null;
optionstring = args[i].substring(2);
}
int indexMinusSign = optionstring.indexOf('-');
if (indexMinusSign != -1) {
optionname = optionstring.substring(indexMinusSign + 1);
optiongroup = optionstring.substring(0, indexMinusSign);
} else {
optiongroup = null;
optionname = optionstring;
}
option = optionDescriptions.getOption(optiongroup, optionname);
if (option instanceof UnaryOption) {
value = "used";
}
i++;
} /*
* Recognizes -optionflag value -optionflag (unary option)
*/ else if (args[i].startsWith("-")) {
if (args[i].length() < 2) {
throw new OptionException("Wrong use of option flag '" + args[i] + "', please check the user guide to see the correct format. ");
}
String flag;
if (oldFlags.containsKey(args[i].substring(1))) {
flag = oldFlags.get(args[i].substring(1));
} else {
flag = args[i].substring(1);
}
// Error message if the old flag '-r' (root handling) is used
if (args[i].substring(1).equals("r")) {
throw new OptionException("The flag -r (root_handling) is replaced with two flags -nr (allow_root) and -ne (allow_reduce) since MaltParser 1.7. Read more about these changes in the user guide.");
}
option = optionDescriptions.getOption(flag);
if (option instanceof UnaryOption) {
value = "used";
} else {
i++;
if (args.length > i) {
value = args[i];
} else {
throw new OptionException("Could not find the corresponding value for -" + option.getFlag() + ". ");
}
}
i++;
} else {
throw new OptionException("The option should starts with a minus sign (-), error at argument '" + args[i] + "'");
}
Object optionvalue = option.getValueObject(value);
optionValues.addOptionValue(OptionContainer.COMMANDLINE, containerIndex, option, optionvalue);
}
return true;
}
/**
* Parses the option file for option values.
*
* @param fileName The option file name (must be a xml file).
* @throws OptionException
*/
public void parseOptionInstanceXMLfile(String fileName) throws MaltChainedException {
File file = new File(fileName);
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Element root = db.parse(file).getDocumentElement();
NodeList containers = root.getElementsByTagName("optioncontainer");
Element container;
for (int i = 0; i < containers.getLength(); i++) {
container = (Element) containers.item(i);
parseOptionValues(container, i);
}
} catch (IOException e) {
throw new OptionException("Can't find the file " + fileName + ". ", e);
} catch (OptionException e) {
throw new OptionException("Problem parsing the file " + fileName + ". ", e);
} catch (ParserConfigurationException e) {
throw new OptionException("Problem parsing the file " + fileName + ". ", e);
} catch (SAXException e) {
throw new OptionException("Problem parsing the file " + fileName + ". ", e);
}
}
/**
* Parses an option container for option values.
*
* @param container a reference to an individual option container in the DOM
* tree.
* @param containerName the name of this container.
* @throws OptionException
*/
private void parseOptionValues(Element container, int containerIndex) throws MaltChainedException {
NodeList optiongroups = container.getElementsByTagName("optiongroup");
Element optiongroup;
for (int i = 0; i < optiongroups.getLength(); i++) {
optiongroup = (Element) optiongroups.item(i);
String groupname = optiongroup.getAttribute("groupname").toLowerCase();
if (groupname == null) {
throw new OptionException("The option group name is missing. ");
}
NodeList optionvalues = optiongroup.getElementsByTagName("option");
Element optionvalue;
for (int j = 0; j < optionvalues.getLength(); j++) {
optionvalue = (Element) optionvalues.item(j);
String optionname = optionvalue.getAttribute("name").toLowerCase();
String value = optionvalue.getAttribute("value");
if (optionname == null) {
throw new OptionException("The option name is missing. ");
}
Option option = optionDescriptions.getOption(groupname, optionname);
if (option instanceof UnaryOption) {
value = "used";
}
if (value == null) {
throw new OptionException("The option value is missing. ");
}
Object ovalue = option.getValueObject(value);
optionValues.addOptionValue(OptionContainer.OPTIONFILE, containerIndex, option, ovalue);
}
}
}
/**
* Returns a string representation of all option value, except the options
* in a option group specified by the excludeGroup argument.
*
* @param containerIndex The index of the option container (0..n and -1 is
* default values).
* @param excludeGroups a set of option group names that should by excluded
* in the string representation
* @return a string representation of all option value
* @throws MaltChainedException
*/
public String toStringPrettyValues(int containerIndex, Set<String> excludeGroups) throws MaltChainedException {
int reservedSpaceForOptionName = 30;
OptionGroup.toStringSetting = OptionGroup.WITHGROUPNAME;
StringBuilder sb = new StringBuilder();
if (containerIndex == OptionManager.DEFAULTVALUE) {
for (String groupname : optionDescriptions.getOptionGroupNameSet()) {
if (excludeGroups.contains(groupname)) {
continue;
}
sb.append(groupname).append("\n");
for (Option option : optionDescriptions.getOptionGroupList(groupname)) {
int nSpaces = reservedSpaceForOptionName - option.getName().length();
if (nSpaces <= 1) {
nSpaces = 1;
}
sb.append(new Formatter().format(" %s (%4s)%" + nSpaces + "s %s\n", option.getName(), "-" + option.getFlag(), " ", option.getDefaultValueString()));
}
}
} else {
for (String groupname : optionDescriptions.getOptionGroupNameSet()) {
if (excludeGroups.contains(groupname)) {
continue;
}
sb.append(groupname).append("\n");
for (Option option : optionDescriptions.getOptionGroupList(groupname)) {
String value = optionValues.getOptionValueString(containerIndex, option);
int nSpaces = reservedSpaceForOptionName - option.getName().length();
if (nSpaces <= 1) {
nSpaces = 1;
}
if (value == null) {
sb.append(new Formatter().format(" %s (%4s)%" + nSpaces + "s %s\n", option.getName(), "-" + option.getFlag(), " ", option.getDefaultValueString()));
} else {
sb.append(new Formatter().format(" %s (%4s)%" + nSpaces + "s %s\n", option.getName(), "-" + option.getFlag(), " ", value));
}
}
}
}
return sb.toString();
}
/*
* (non-Javadoc) @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(optionDescriptions).append("\n");
sb.append(optionValues).append("\n");
return sb.toString();
}
}