edu.stanford.nlp.util.ArgumentParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stanford-corenlp Show documentation
Show all versions of stanford-corenlp Show documentation
Stanford CoreNLP provides a set of natural language analysis tools which can take raw English language text input and give the base forms of words, their parts of speech, whether they are names of companies, people, etc., normalize dates, times, and numeric quantities, mark up the structure of sentences in terms of phrases and word dependencies, and indicate which noun phrases refer to the same entities. It provides the foundational building blocks for higher level text understanding applications.
package edu.stanford.nlp.util;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.annotation.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.InetAddress;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import edu.stanford.nlp.pipeline.Annotator;
import static edu.stanford.nlp.util.logging.Redwood.Util.*;
/**
* A class to set command line options. To use, create a static class into which you'd like
* to put your properties. Then, for each field, set the annotation:
*
*
* import edu.stanford.nlp.util.ArgumentParser.Option
*
* class Props {
* @Option(name="anIntOption", required=false, gloss="This is an int")
* public static int anIntOption = 7; // default value is 7
* @Option(name="anotherOption", required=false)
* public static File aCastableOption = new File("/foo");
* }
*
*
*
* You can then set options with {@link ArgumentParser#fillOptions(String...)},
* or with {@link ArgumentParser#fillOptions(java.util.Properties)}.
*
*
*
* If your default classpath has many classes in it, you can select a subset of them
* by using {@link ArgumentParser#fillOptions(Class[], java.util.Properties)}, or some variant.
*
*
*
* A complete toy example looks like this:
*
*
*
* import java.util.Properties;
*
* import edu.stanford.nlp.util.ArgumentParser;
* import edu.stanford.nlp.util.StringUtils;
*
* public class Foo {
*
* @ArgumentParser.Option(name="bar", gloss="This is a string option.", required=true)
* private static String BAR = null;
*
* public static void main(String[] args) {
* // Parse the arguments
* Properties props = StringUtils.argsToProperties(args);
* ArgumentParser.fillOptions(new Class[]{ Foo.class, ArgumentParser.class }, props);
*
* log.info(INPUT);
* }
* }
*
*
* @author Gabor Angeli
*/
@SuppressWarnings("HtmlTagCanBeJavadocTag")
public class ArgumentParser {
private ArgumentParser() {} // static class
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Option {
String name() default "";
String gloss() default "";
boolean required() default false;
String alt() default "";
}
@SuppressWarnings("MismatchedReadAndWriteOfArray")
private static final String[] IGNORED_JARS = {
};
private static final Class[] BOOTSTRAP_CLASSES = {
ArgumentParser.class,
};
@Option(name = "option_classes", gloss = "Fill options from these classes")
public static Class[] optionClasses = null;
@Option(name = "threads", gloss = "Number of threads on machine")
public static int threads = Runtime.getRuntime().availableProcessors();
@Option(name = "host", gloss = "Name of computer we are running on")
public static String host = "(unknown)";
@SuppressWarnings("FieldCanBeLocal")
@Option(name = "strict", gloss = "If true, make sure that all options passed in are used somewhere")
private static boolean strict = false;
@SuppressWarnings("FieldCanBeLocal")
@Option(name = "exec.verbose", gloss = "If true, print options as they are set.")
private static boolean verbose = false;
static {
try {
host = InetAddress.getLocalHost().getHostName();
} catch (Exception ignored) {
}
}
/**
* A lazy iterator over files, not loading all of them into memory at once.
*/
public static class LazyFileIterator implements Iterator {
private FilenameFilter filter;
private File[] dir;
private Stack parents = new Stack<>();
private Stack indices = new Stack<>();
private int toReturn = -1;
public LazyFileIterator(File path, final String filter) {
this(path, (file, name) -> {
String filePath = (file.getPath() + "/" + name);
return new File(filePath).isDirectory() || filePath.matches(filter);
});
}
public LazyFileIterator(File dir, FilenameFilter filter) {
if (!dir.exists()) throw new IllegalArgumentException("Could not find directory: " + dir.getPath());
if (!dir.isDirectory()) throw new IllegalArgumentException("Not a directory: " + dir.getPath());
this.filter = filter;
this.dir = dir.listFiles(filter);
enqueue();
}
private void enqueue() {
toReturn += 1;
boolean good = (toReturn < dir.length && !dir[toReturn].isDirectory());
while (!good) {
if (toReturn >= dir.length) {
//(case: pop)
if (parents.isEmpty()) {
toReturn = -1;
return; //this is where we exit
} else {
dir = parents.pop();
toReturn = indices.pop();
}
} else if (dir[toReturn].isDirectory()) {
//(case: push)
parents.push(dir);
indices.push(toReturn + 1);
dir = dir[toReturn].listFiles(filter);
toReturn = 0;
} else {
throw new IllegalStateException("File is invalid, but in range and not a directory: " + dir[toReturn]);
}
//(check if good)
good = (toReturn < dir.length && !dir[toReturn].isDirectory());
}
// if we reach here we found something
}
@Override
public boolean hasNext() {
return toReturn >= 0;
}
@Override
public File next() {
if (toReturn >= dir.length || toReturn < 0) {
throw new NoSuchElementException("No more elements!");
}
File rtn = dir[toReturn];
enqueue();
return rtn;
}
@Override
public void remove() {
throw new IllegalArgumentException("NOT IMPLEMENTED");
}
}
/*
* ----------
* OPTIONS
* ----------
*/
private static void fillField(Object instance, Field f, String value) {
//--Verbose
if (verbose) {
Option opt = f.getAnnotation(Option.class);
StringBuilder b = new StringBuilder("setting ").append(f.getDeclaringClass().getName()).append("#").append(f.getName()).append(" ");
if (opt != null) {
b.append("[").append(opt.name()).append("] ");
}
b.append("to: ").append(value);
log(b.toString());
}
try {
//--Permissions
boolean accessState = true;
if (Modifier.isFinal(f.getModifiers())) {
runtimeException("Option cannot be final: " + f);
}
if (!f.isAccessible()) {
accessState = false;
f.setAccessible(true);
}
//--Set Value
Object objVal = MetaClass.cast(value, f.getGenericType());
if (objVal != null) {
if (objVal.getClass().isArray()) {
//(case: array)
Object[] array = (Object[]) objVal;
// error check
if (!f.getType().isArray()) {
runtimeException("Setting an array to a non-array field. field: " + f + " value: " + Arrays.toString(array) + " src: " + value);
}
// create specific array
Object toSet = Array.newInstance(f.getType().getComponentType(), array.length);
for (int i = 0; i < array.length; i++) {
Array.set(toSet, i, array[i]);
}
// set value
f.set(instance, toSet);
} else {
//case: not array
f.set(instance, objVal);
}
} else {
runtimeException("Cannot assign option field: " + f + " value: " + value + "; invalid type");
}
//--Permissions
if (!accessState) {
f.setAccessible(false);
}
} catch (IllegalArgumentException e) {
err(e);
runtimeException("Cannot assign option field: " + f.getDeclaringClass().getCanonicalName() + "." + f.getName() + " value: " + value + " cause: " + e.getMessage());
} catch (IllegalAccessException e) {
err(e);
runtimeException("Cannot access option field: " + f.getDeclaringClass().getCanonicalName() + "." + f.getName());
} catch (Exception e) {
err(e);
runtimeException("Cannot assign option field: " + f.getDeclaringClass().getCanonicalName() + "." + f.getName() + " value: " + value + " cause: " + e.getMessage());
}
}
@SuppressWarnings("rawtypes")
private static Class filePathToClass(String cpEntry, String path) {
if (path.length() <= cpEntry.length()) {
throw new IllegalArgumentException("Illegal path: cp=" + cpEntry
+ " path=" + path);
}
if (path.charAt(cpEntry.length()) != '/') {
throw new IllegalArgumentException("Illegal path: cp=" + cpEntry
+ " path=" + path);
}
path = path.substring(cpEntry.length() + 1);
path = path.replaceAll("/", ".").substring(0, path.length() - 6);
try {
return Class.forName(path,
false,
ClassLoader.getSystemClassLoader());
} catch (ClassNotFoundException e) {
throw fail("Could not load class at path: " + path);
} catch (NoClassDefFoundError ex) {
warn("Class at path " + path + " is unloadable");
return null;
}
}
private static boolean isIgnored(String path) {
for (String ignore : IGNORED_JARS) {
if (path.endsWith(ignore)) {
return true;
}
}
return false;
}
private static Class[] getVisibleClasses() {
//--Variables
List> classes = new ArrayList<>();
// (get classpath)
String pathSep = System.getProperty("path.separator");
String[] cp = System.getProperties().getProperty("java.class.path",
null).split(pathSep);
// --Fill Options
// (get classes)
for (String entry : cp) {
log("Checking cp " + entry);
//(should skip?)
if (entry.equals(".") || entry.trim().length() == 0) {
continue;
}
//(no, don't skip)
File f = new File(entry);
if (f.isDirectory()) {
// --Case: Files
LazyFileIterator iter = new LazyFileIterator(f, ".*class$");
while (iter.hasNext()) {
//(get the associated class)
Class clazz = filePathToClass(entry, iter.next().getPath());
if (clazz != null) {
//(add the class if it's valid)
classes.add(clazz);
}
}
} else //noinspection StatementWithEmptyBody
if (!isIgnored(entry)) {
// --Case: Jar
try {
JarFile jar = new JarFile(f);
Enumeration e = jar.entries();
while (e.hasMoreElements()) {
//(for each jar file element)
JarEntry jarEntry = e.nextElement();
String clazz = jarEntry.getName();
if (clazz.matches(".*class$")) {
//(if it's a class)
clazz = clazz.substring(0, clazz.length() - 6)
.replaceAll("/", ".");
//(add it)
try {
classes.add(
Class.forName(clazz,
false,
ClassLoader.getSystemClassLoader()));
} catch (ClassNotFoundException ex) {
warn("Could not load class in jar: " + f + " at path: " + clazz);
} catch (NoClassDefFoundError ex) {
debug("Could not scan class: " + clazz + " (in jar: " + f + ")");
}
}
}
} catch (IOException e) {
warn("Could not open jar file: " + f + "(are you sure the file exists?)");
}
} else {
//case: ignored jar
}
}
return classes.toArray(new Class[classes.size()]);
}
/**
* Get all the declared fields of this class and all super classes.
*/
private static Field[] scrapeFields(Class clazz) throws Exception {
List fields = new ArrayList<>();
while (clazz != null && !clazz.equals(Object.class)) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass();
}
return fields.toArray(new Field[fields.size()]);
}
private static String threadRootClass() {
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
int i = trace.length - 1;
while(i > 0 &&
(trace[i].getClassName().startsWith("com.intellij") ||
trace[i].getClassName().startsWith("java.") ||
trace[i].getClassName().startsWith("sun.")
) ) {
i -= 1;
}
StackTraceElement elem = trace[i];
return elem.getClassName();
}
private static String bufferString(String raw, int minLength) {
StringBuilder b = new StringBuilder(raw);
for (int i = raw.length(); i < minLength; ++i) {
b.append(" ");
}
return b.toString();
}
@SuppressWarnings("rawtypes")
private static Map fillOptionsImpl(
Object[] instances,
Class[] classes,
Properties options,
boolean ensureAllOptions,
boolean isBootstrap) {
// Print usage, if applicable
if (!isBootstrap) {
if ("true".equalsIgnoreCase(options.getProperty("usage", "false")) ||
"true".equalsIgnoreCase(options.getProperty("help", "false"))
) {
Set> allClasses = new HashSet<>();
Collections.addAll(allClasses, classes);
if (instances != null) {
for (Object o : instances) {
allClasses.add(o.getClass());
}
}
System.err.println(usage(allClasses.stream().toArray(Class[]::new)));
System.exit(0);
}
}
//--Create Class->Object Mapping
Map class2object = new HashMap<>();
if (instances != null) {
for (int i = 0; i < classes.length; ++i) {
assert instances[i].getClass() == classes[i];
class2object.put(classes[i], instances[i]);
Class mySuper = instances[i].getClass().getSuperclass();
while (mySuper != null && !mySuper.equals(Object.class)) {
if (!class2object.containsKey(mySuper)) {
class2object.put(mySuper, instances[i]);
}
mySuper = mySuper.getSuperclass();
}
}
}
//--Get Fillable Options
Map canFill = new HashMap<>();
Map> required = new HashMap<>(); /* */
Map interner = new HashMap<>();
for (Class c : classes) {
Field[] fields;
try {
fields = scrapeFields(c);
} catch (Throwable e) {
debug("Could not check fields for class: " + c.getName() + " (caused by " + e.getClass() + ": " + e.getMessage() + ")");
continue;
}
boolean someOptionFilled = false;
boolean someOptionFound = false;
for (Field f : fields) {
Option o = f.getAnnotation(Option.class);
if (o != null) {
someOptionFound = true;
//(check if field is static)
if ((f.getModifiers() & Modifier.STATIC) == 0 && instances == null) {
continue;
}
someOptionFilled = true;
//(required marker)
Pair mark = Pair.makePair(false, false);
if (o.required()) {
mark = Pair.makePair(true, false);
}
//(add main name)
String name = o.name().toLowerCase();
if (name.equals("")) {
name = f.getName().toLowerCase();
}
if (canFill.containsKey(name)) {
String name1 = canFill.get(name).getDeclaringClass().getCanonicalName() + "." + canFill.get(name).getName();
String name2 = f.getDeclaringClass().getCanonicalName() + "." + f.getName();
if (!name1.equals(name2)) {
runtimeException("Multiple declarations of option " + name + ": " + name1 + " and " + name2);
} else {
err("Class is in classpath multiple times: " + canFill.get(name).getDeclaringClass().getCanonicalName());
}
}
canFill.put(name, f);
required.put(name, mark);
interner.put(name, name);
//(add alternate names)
if (!o.alt().equals("")) {
for (String alt : o.alt().split(" *, *")) {
alt = alt.toLowerCase();
if (canFill.containsKey(alt) && !alt.equals(name))
throw new IllegalArgumentException("Multiple declarations of option " + alt + ": " + canFill.get(alt) + " and " + f);
canFill.put(alt, f);
if (mark.first) required.put(alt, mark);
interner.put(alt, name);
}
}
}
}
//(check to ensure that something got filled, if any @Option annotation was found)
if (someOptionFound && !someOptionFilled) {
warn("found @Option annotations in class " + c + ", but didn't set any of them (all options were instance variables and no instance given?)");
}
}
//--Fill Options
for (Map.Entry