All Downloads are FREE. Search and download functionalities are using the official Maven repository.

loci.common.ReflectedUniverse Maven / Gradle / Ivy

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: *
      *
    1. a variable in the universe
    2. *
    3. a static or instance field (i.e., no nested methods)
    4. *
    5. a string literal (remember to escape the double quotes)
    6. *
    7. an integer literal
    8. *
    9. a long literal (ending in L)
    10. *
    11. a double literal (containing a decimal point)
    12. *
    13. a boolean literal (true or false)
    14. *
    15. the null keyword
    16. *
    *
  • *
* * @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(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy