loci.common.ReflectedUniverse Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ome-common Show documentation
Show all versions of ome-common Show documentation
Contains common I/O, date parsing, and XML processing classes.
The newest version!
/*
* #%L
* Common package for I/O and related utilities
* %%
* Copyright (C) 2005 - 2016 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package loci.common;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A general purpose reflection wrapper class.
*/
@Deprecated
public class ReflectedUniverse {
// -- Constants --
private static final Logger LOGGER =
LoggerFactory.getLogger(ReflectedUniverse.class);
// -- Fields --
/** Hashtable containing all variables present in the universe. */
protected HashMap variables;
/** Class loader for imported classes. */
protected ClassLoader loader;
/** Whether to force our way past restrictive access modifiers. */
protected boolean force;
// -- Constructors --
/** Constructs a new reflected universe. */
public ReflectedUniverse() {
this((ClassLoader) null);
}
/**
* Constructs a new reflected universe, with the given URLs
* representing additional search paths for imported classes
* (in addition to the CLASSPATH).
*
* @param urls array of URLs to search for additional classes.
* Each URL is typically a JAR file that is not on
* the CLASSPATH.
*/
public ReflectedUniverse(URL[] urls) {
this(urls == null ? null : new URLClassLoader(urls));
}
/**
* Constructs a new reflected universe that uses the given class loader.
*
* @param loader the ClassLoader to use in this universe.
* If null, the default ClassLoader for the ReflectedUniverse
* class will be used.
*/
public ReflectedUniverse(ClassLoader loader) {
variables = new HashMap();
this.loader = loader == null ? getClass().getClassLoader() : loader;
}
// -- Utility methods --
/**
* Returns whether the given object is compatible with the
* specified class for the purposes of reflection.
*
* @param c the base class
* @param o the object that needs type checking
* @return true if the object is an instance of the base class
*/
public static boolean isInstance(Class> c, Object o) {
return (o == null || c.isInstance(o) ||
(c == byte.class && o instanceof Byte) ||
(c == short.class && o instanceof Short) ||
(c == int.class && o instanceof Integer) ||
(c == long.class && o instanceof Long) ||
(c == float.class && o instanceof Float) ||
(c == double.class && o instanceof Double) ||
(c == boolean.class && o instanceof Boolean) ||
(c == char.class && o instanceof Character));
}
// -- ReflectedUniverse API methods --
/**
* Executes a command in the universe. The following syntaxes are valid:
*
* - import fully.qualified.package.ClassName
* - var = new ClassName(param1, ..., paramN)
* - var.method(param1, ..., paramN)
* - var2 = var.method(param1, ..., paramN)
* - ClassName.method(param1, ..., paramN)
* - var2 = ClassName.method(param1, ..., paramN)
* - var2 = var
*
* Important guidelines:
*
* - Any referenced class must be imported first using "import".
* - Variables can be exported from the universe with getVar().
* - Variables can be imported to the universe with setVar().
* - Each parameter must be either:
*
* - a variable in the universe
* - a static or instance field (i.e., no nested methods)
* - a string literal (remember to escape the double quotes)
* - an integer literal
* - a long literal (ending in L)
* - a double literal (containing a decimal point)
* - a boolean literal (true or false)
* - the null keyword
*
*
*
*
* @param command the command to be executed (see examples above)
* @return the result of executing the command. For import statements,
* the return value is null. Otherwise, the return value of
* the invoked method or the value assigned to a variable
* is returned (depending upon the command).
* @throws ReflectException if the command is invalid or fails to execute
*/
public Object exec(String command) throws ReflectException {
command = command.trim();
if (command.startsWith("import ")) {
// command is an import statement
command = command.substring(7).trim();
int dot = command.lastIndexOf(".");
String varName = dot < 0 ? command : command.substring(dot + 1);
Class> c;
try {
c = Class.forName(command, true, loader);
}
catch (NoClassDefFoundError err) {
LOGGER.debug("No such class: {}", command, err);
throw new ReflectException("No such class: " + command, err);
}
catch (ClassNotFoundException exc) {
LOGGER.debug("No such class: {}", command, exc);
throw new ReflectException("No such class: " + command, exc);
}
catch (RuntimeException exc) {
// HACK: workaround for bug in Apache Axis2
String msg = exc.getMessage();
if (msg != null && msg.indexOf("ClassNotFound") < 0) throw exc;
LOGGER.debug("No such class: {}", command, exc);
throw new ReflectException("No such class: " + command, exc);
}
setVar(varName, c);
return null;
}
// get variable where results of command should be stored
int eqIndex = command.indexOf('=');
String target = null;
if (eqIndex >= 0) {
target = command.substring(0, eqIndex).trim();
command = command.substring(eqIndex + 1).trim();
}
Object result = null;
// parse parentheses
int leftParen = command.indexOf('(');
if (leftParen < 0) {
// command is a simple assignment
result = getVar(command);
if (target != null) setVar(target, result);
return result;
}
else if (leftParen != command.lastIndexOf("(") ||
command.indexOf(')') != command.length() - 1)
{
throw new ReflectException("Invalid parentheses");
}
// parse arguments
String arglist = command.substring(leftParen + 1);
StringTokenizer st = new StringTokenizer(arglist, "(,)");
int len = st.countTokens();
Object[] args = new Object[len];
for (int i=0; i)) {
throw new ReflectException("Not a class: " + className);
}
Class> cl = (Class>) var;
// Search for a constructor that matches the arguments. Unfortunately,
// calling cl.getConstructor(argClasses) does not work, because
// getConstructor() is not flexible enough to detect when the arguments
// are subclasses of the constructor argument classes, making a brute
// force search through all public constructors necessary.
Constructor> constructor = null;
Constructor>[] c = cl.getConstructors();
for (int i=0; i[] params = c[i].getParameterTypes();
if (params.length == args.length) {
boolean match = true;
for (int j=0; j varClass = var instanceof Class> ?
(Class>) var : var.getClass();
// Search for a method that matches the arguments. Unfortunately,
// calling varClass.getMethod(methodName, argClasses) does not work,
// because getMethod() is not flexible enough to detect when the
// arguments are subclasses of the method argument classes, making a
// brute force search through all public methods necessary.
Method method = null;
Method[] m = varClass.getMethods();
for (int i=0; i[] params = m[i].getParameterTypes();
if (params.length == args.length) {
boolean match = true;
for (int j=0; j= 0) {
// get field value of variable
String className = varName.substring(0, dot).trim();
Object var = variables.get(className);
if (var == null) {
throw new ReflectException("No such class: " + className);
}
Class> varClass = var instanceof Class> ?
(Class>) var : var.getClass();
String fieldName = varName.substring(dot + 1).trim();
Field field;
try {
field = varClass.getField(fieldName);
if (force) field.setAccessible(true);
}
catch (NoSuchFieldException exc) {
LOGGER.debug("No such field: {}", varName, exc);
throw new ReflectException("No such field: " + varName, exc);
}
Object fieldVal;
try { fieldVal = field.get(var); }
catch (IllegalAccessException exc) {
LOGGER.debug("Cannot get field value: {}", varName, exc);
throw new ReflectException("Cannot get field value: " + varName, exc);
}
return fieldVal;
}
// get variable
Object var = variables.get(varName);
return var;
}
/**
* Sets whether access modifiers (protected, private, etc.) are ignored.
*
* @param ignore true if access modifiers should be ignored
*/
public void setAccessibilityIgnored(boolean ignore) {
force = ignore;
}
/**
* Gets whether access modifiers (protected, private, etc.) are ignored.
*
* @return true if access modifiers are currently ignored
*/
public boolean isAccessibilityIgnored() {
return force;
}
// -- Main method --
/**
* Allows exploration of a reflected universe in an interactive environment.
*
* @param args if non-empty, access modifiers will be ignored
* @throws IOException if there is an error reading from stdin
*/
public static void main(String[] args) throws IOException {
ReflectedUniverse r = new ReflectedUniverse();
System.out.println("Reflected universe test environment. " +
"Type commands, or press ^D to quit.");
if (args.length > 0) {
r.setAccessibilityIgnored(true);
System.out.println("Ignoring accessibility modifiers.");
}
BufferedReader in =
new BufferedReader(new InputStreamReader(System.in, Constants.ENCODING));
while (true) {
System.out.print("> ");
String line = in.readLine();
if (line == null) break;
try { r.exec(line); }
catch (ReflectException exc) {
LOGGER.debug("Could not execute '{}'", line, exc);
}
}
System.out.println();
}
}