/*
* Open Source Physics software is free software as described near the bottom of this code file.
*
* For additional information and documentation on Open Source Physics please see:
* <http://www.opensourcephysics.org/>
*/
package org.opensourcephysics.ejs.control;
import java.lang.reflect.Method;
import org.opensourcephysics.ejs.control.value.BooleanValue;
import org.opensourcephysics.ejs.control.value.DoubleValue;
import org.opensourcephysics.ejs.control.value.IntegerValue;
import org.opensourcephysics.ejs.control.value.StringValue;
import org.opensourcephysics.ejs.control.value.Value;
/**
* A class to store and invoke methods using reflection.
*/
public class MethodWithOneParameter {
private String methodName;
private int methodType;
private Object targetObject = null;
private Object[] parameterList = {};
private Method methodToCall;
private MethodWithOneParameter secondMethod = null;
private Value returnValue = null; // AMAVP (See Note in ControlElement)
/**
* Equivalent to MethodWithOneParameter (_type, _target, _name, null);
*/
// MethodWithOneParameter (int _type, Object _target, String _name) {
// this(_type, _target, _name, null);
// }
/**
* Creates a new method from the input parameters.
* @param int _type An integer type to help create families of actions
* @param Object _target The object that implements the method
* @param String _name The description of the method.
* 1.- If the method's parameter list is void, then you can specify either
* 'method()' or just 'method'
* 2.- If the method accepts a boolean, you can specify either 'method(true)'
* or 'method(false)'
* 3.- If the method accepts a double, you can specify something like 'method(1.0)'
* 4.- If the method accepts an integer, you can specify something like 'method(1)'
* 5.- If the method accepts a String, you can specify something like 'method("my string")'
* In all cases, the first version is the recommended one.
* @param MethodWithOneParameter _secondMethod A second action that will be invoked
* following this one. This is useful when you want to call more than one methods at once
* @param _anObject and object for the very special case of method("#CONTROL#"); //Added on Jan 31st 2004
*/
MethodWithOneParameter(int _type, Object _target, String _name, String _returnType, MethodWithOneParameter _secondMethod, Object _anObject) {
Class<?>[] classList = {};
Object parameter = null;
Class<?> parameterClass = null;
methodName = _name;
methodType = _type;
targetObject = _target;
secondMethod = _secondMethod;
String parts[] = splitMethodName(_name.trim());
if(parts[2].equals("#CONTROL#")&&(_anObject!=null)) { //$NON-NLS-1$
parameter = _anObject;
parameterClass = _anObject.getClass();
// System.out.println ("Class of OBJECT is "+parameterClass);
} else {
Value value = Value.parseConstant(parts[2], false); // NO silent mode
if(value instanceof StringValue) { // method ("String")
parameter = value.getString();
parameterClass = _name.getClass(); // String
} else if(value instanceof BooleanValue) { // method (boolean)
parameter = new Boolean(value.getBoolean());
parameterClass = Boolean.TYPE;
} else if(value instanceof DoubleValue) { // method (double)
parameter = new Double(value.getDouble());
parameterClass = Double.TYPE;
} else if(value instanceof IntegerValue) { // method (int)
parameter = new Integer(value.getInteger());
parameterClass = Integer.TYPE;
}
}
if(parameter!=null) { // method(parameter);
classList = new Class[1];
classList[0] = parameterClass; // parameter
parameterList = new Object[1];
parameterList[0] = parameter;
}
methodToCall = resolveMethod(targetObject, parts[1], classList);
if(methodToCall==null) {
System.err.println(getClass().getName()+" : Error! Unable to find a suitable method "+methodName+" in class "+targetObject.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$
}
if(_returnType==null) {
returnValue = null; // AMAVP
} else {
_returnType = _returnType.trim().toLowerCase();
if(_returnType.equals("double")) { //$NON-NLS-1$
returnValue = new DoubleValue(0.0);
// else if (_returnType.equals("byte")) returnValue = new IntegerValue(0);
} else if(_returnType.equals("int")) { //$NON-NLS-1$
returnValue = new IntegerValue(0);
} else if(_returnType.equals("string")) { //$NON-NLS-1$
returnValue = new StringValue(""); //$NON-NLS-1$
} else if(_returnType.equals("boolean")) { //$NON-NLS-1$
returnValue = new BooleanValue(false);
} else {
returnValue = null; // return type is void
}
}
}
public Value invoke(int _type, Object _callingObject) { // Modified for AMAVP
if(methodType!=_type) {
return null;
}
// System.out.println ("Invoking method "+this.methodName+" with Value "+parameterList);
try {
if(returnValue==null) { // void return type
methodToCall.invoke(targetObject, parameterList);
} else if(returnValue instanceof DoubleValue) {
((DoubleValue) returnValue).value = ((Double) methodToCall.invoke(targetObject, parameterList)).doubleValue();
} else if(returnValue instanceof IntegerValue) {
((IntegerValue) returnValue).value = ((Integer) methodToCall.invoke(targetObject, parameterList)).intValue();
} else if(returnValue instanceof BooleanValue) {
((BooleanValue) returnValue).value = ((Boolean) methodToCall.invoke(targetObject, parameterList)).booleanValue();
} else if(returnValue instanceof StringValue) {
((StringValue) returnValue).value = methodToCall.invoke(targetObject, parameterList).toString();
}
if(secondMethod!=null) {
secondMethod.invoke(_type, _callingObject);
}
} catch(Exception exc) {
exc.printStackTrace(System.err);
return null;
}
return returnValue;
}
public boolean equals(int _type, Object _target, String _name) {
if(methodType!=_type) {
return false;
}
if(targetObject!=_target) {
return false;
}
return methodName.equals(_name);
}
public String toString() {
return methodName;
}
static public Method resolveMethod(Object _target, String _name, Class<?>[] _classList) {
java.lang.reflect.Method[] allMethods = _target.getClass().getMethods();
for(int i = 0; i<allMethods.length; i++) {
if(!allMethods[i].getName().equals(_name)) {
continue;
}
Class<?>[] parameters = allMethods[i].getParameterTypes();
if(parameters.length!=_classList.length) {
continue;
}
boolean fits = true;
for(int j = 0; j<parameters.length; j++) {
if(!parameters[j].isAssignableFrom(_classList[j])) {
fits = false;
break;
}
}
if(fits) {
return allMethods[i];
}
}
return null;
}
static public String[] splitMethodName(String _inputName) {
String part[] = new String[3];
String restOfIt = _inputName;
int index1 = _inputName.indexOf('.');
int index2 = _inputName.indexOf('(');
if((index1>0)&&((index2<0)||(index2>index1))) {
part[0] = _inputName.substring(0, index1); // target
restOfIt = _inputName.substring(index1+1); // rest of it
} else {
part[0] = null; // No target
}
index1 = restOfIt.indexOf("("); //$NON-NLS-1$
if(index1<=0) { // format 'method'
part[1] = restOfIt;
part[2] = null;
} else {
// format 'method()' or 'method(parameter)'
part[1] = restOfIt.substring(0, index1).trim();
restOfIt = restOfIt.substring(index1);
index2 = restOfIt.lastIndexOf(')');
if(index2<0) {
System.err.println(" : Error! Incorrect method description "+_inputName); //$NON-NLS-1$
return null;
}
part[2] = restOfIt.substring(1, index2).trim();
}
// for (int i=0; i<part.length; i++) System.out.println ("Part["+i+"] = "+part[i]);
return part;
}
} // End of class
/*
* Open Source Physics software is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public License (GPL) as
* published by the Free Software Foundation; either version 2 of the License,
* or(at your option) any later version.
* Code that uses any portion of the code in the org.opensourcephysics package
* or any subpackage (subdirectory) of this package must must also be be released
* under the GNU GPL license.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
* or view the license online at http://www.gnu.org/copyleft/gpl.html
*
* Copyright (c) 2007 The Open Source Physics project
* http://www.opensourcephysics.org
*/