blob: c66b6b52effad5d0100fe9d8e7ff421cfd0cc9aa [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* more patents listed at http://www.pivotal.io/patents.
*========================================================================
*/
package hydra;
//import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import com.gemstone.gemfire.SystemFailure;
/**
*
* A class specialized for executing (via reflection) the receiver/selector
* pairs found in TestTasks.
*
*/
public class MethExecutor {
// @todo lises add static args method
/**
* Helper method that searches a class (and its superclasses) for a
* method with the given name and parameter types.
*
* @throws NoSuchMethodException
* If the method cannot be found
*/
public static Method getMethod(Class c, String methodName, Class[] paramTypes)
throws NoSuchMethodException {
ArrayList matchingMethods = new ArrayList();
for (Class q = c; q != null; q = q.getSuperclass()) {
Method[] methods = q.getDeclaredMethods();
NEXT_METHOD:
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
if (!m.getName().equals(methodName)) {
continue;
}
Class[] argTypes = m.getParameterTypes();
if (argTypes.length != paramTypes.length) {
continue;
}
for (int j = 0; j < argTypes.length; j++) {
if(paramTypes[j] == null) {
if(argTypes[j].isPrimitive()) {
//this parameter is not ok, the parameter is a primative and the value is null
continue NEXT_METHOD;
} else {
//this parameter is ok, the argument is an object and the value is null
continue;
}
}
if (!argTypes[j].isAssignableFrom(paramTypes[j])) {
Class argType = argTypes[j];
Class paramType = paramTypes[j];
if (argType.isPrimitive()) {
if ((argType.equals(boolean.class) &&
paramType.equals(Boolean.class)) ||
(argType.equals(short.class) &&
paramType.equals(Short.class)) ||
(argType.equals(int.class) &&
paramType.equals(Integer.class)) ||
(argType.equals(long.class) &&
paramType.equals(Long.class)) ||
(argType.equals(float.class) &&
paramType.equals(Float.class)) ||
(argType.equals(double.class) &&
paramType.equals(Double.class)) ||
(argType.equals(char.class) &&
paramType.equals(Character.class)) ||
(argType.equals(byte.class) &&
paramType.equals(Byte.class)) ||
false) {
// This parameter is okay, try the next arg
continue;
}
}
continue NEXT_METHOD;
}
}
matchingMethods.add(m);
}
//We want to check to make sure there aren't two
//ambiguous methods on the same class. But a subclass
//can still override a method on a super class, so we'll stop
//if we found a method on the subclass.
if(matchingMethods.size() > 0) {
break;
}
}
if(matchingMethods.isEmpty()) {
StringBuffer sb = new StringBuffer();
sb.append("Could not find method ");
sb.append(methodName);
sb.append(" with ");
sb.append(paramTypes.length);
sb.append(" parameters [");
for (int i = 0; i < paramTypes.length; i++) {
String name = paramTypes[i] == null ? null : paramTypes[i].getName();
sb.append(name);
if (i < paramTypes.length - 1) {
sb.append(", ");
}
}
sb.append("] in class ");
sb.append(c.getName());
throw new NoSuchMethodException(sb.toString());
}
if(matchingMethods.size() > 1) {
StringBuffer sb = new StringBuffer();
sb.append("Method is ambiguous ");
sb.append(methodName);
sb.append(" with ");
sb.append(paramTypes.length);
sb.append(" parameters [");
for (int i = 0; i < paramTypes.length; i++) {
String name = paramTypes[i] == null ? null : paramTypes[i].getName();
sb.append(name);
if (i < paramTypes.length - 1) {
sb.append(", ");
}
}
sb.append("] in class ");
sb.append(c.getName());
throw new NoSuchMethodException(sb.toString());
}
else return (Method) matchingMethods.get(0);
}
/**
*
* Send the message "selector" to the class named "receiver".
* Return the result, including stack trace (if any).
*
*/
public static MethExecutorResult execute(String receiver, String selector) {
return execute(receiver, selector, null);
}
/**
* Executes the given static method on the given class with the
* given arguments.
*/
public static MethExecutorResult execute(String receiver,
String selector,
Object[] args) {
try {
// get the class
Class receiverClass = Class.forName(receiver);
// invoke the method
Object res = null;
try {
Class[] paramTypes;
if (args == null) {
paramTypes = new Class[0];
} else {
paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
paramTypes[i] = null;
} else {
paramTypes[i] = args[i].getClass();
}
}
}
Method theMethod =
getMethod(receiverClass, selector, paramTypes);
theMethod.setAccessible(true);
res = theMethod.invoke(receiverClass, args);
return new MethExecutorResult( res );
} catch (InvocationTargetException invTargEx) {
Throwable targEx = invTargEx.getTargetException();
if ( targEx == null ) {
return new MethExecutorResult( res );
} else {
return new MethExecutorResult(targEx);
}
}
}
catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
}
catch (Throwable t) {
// String s = "While trying to invoke " + receiver + "." +
// selector;
// t = new HydraConfigException(s, t);
return new MethExecutorResult(t);
}
}
/**
*
* Send the message "selector" to the object "target".
* Return the result, including stack trace (if any).
*
*/
public static MethExecutorResult executeObject(Object target, String selector) {
return executeObject(target, selector, null);
}
/**
* Executes the given instance method on the given object with the
* given arguments.
*/
public static MethExecutorResult executeObject(Object target,
String selector,
Object[] args) {
try {
// get the class
Class receiverClass = Class.forName(target.getClass().getName());
// invoke the method
Object res = null;
try {
Class[] paramTypes;
if (args == null) {
paramTypes = new Class[0];
} else {
paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
paramTypes[i] = Object.class;
} else {
paramTypes[i] = args[i].getClass();
}
}
}
Method theMethod =
getMethod(receiverClass, selector, paramTypes);
theMethod.setAccessible(true);
res = theMethod.invoke(target, args);
return new MethExecutorResult( res );
} catch (InvocationTargetException invTargEx) {
Throwable targEx = invTargEx.getTargetException();
if ( targEx == null ) {
return new MethExecutorResult( res );
} else {
return new MethExecutorResult(targEx);
}
}
}
catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
}
catch (Throwable t) {
return new MethExecutorResult(t);
}
}
/**
*
* Send the message "selector" to an instance of the class named "receiver".
* Return the result, including stack trace (if any).
*
*/
public static MethExecutorResult executeInstance( String receiver, String selector ) {
try {
// get the class
Class receiverClass = Class.forName(receiver);
Object target = receiverClass.newInstance();
// invoke the method
Object res = null;
try {
Method theMethod =
getMethod(receiverClass, selector, new Class[0]);
res = theMethod.invoke(target, new Object[0] );
return new MethExecutorResult( res );
} catch (InvocationTargetException invTargEx) {
Throwable targEx = invTargEx.getTargetException();
if ( targEx == null ) {
return new MethExecutorResult( res );
} else {
return new MethExecutorResult(targEx);
}
}
}
catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
}
catch (Throwable t) {
return new MethExecutorResult(t);
}
}
/**
*
* Send the message "selector" to an instance of the class named "receiver".
* Return the result, including stack trace (if any).
*
*/
public static MethExecutorResult executeInstance( String receiver, String selector,
Class[] types, Object[] args ) {
try {
// get the class
Class receiverClass = Class.forName(receiver);
Constructor init =
receiverClass.getDeclaredConstructor(new Class[0]);
init.setAccessible(true);
Object target = init.newInstance(new Object[0]);
// invoke the method
Object res = null;
try {
Method theMethod = getMethod(receiverClass, selector, types);
res = theMethod.invoke(target, args );
return new MethExecutorResult( res );
} catch (InvocationTargetException invTargEx) {
Throwable targEx = invTargEx.getTargetException();
if ( targEx == null ) {
return new MethExecutorResult( res );
} else {
return new MethExecutorResult(targEx);
}
}
}
catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
}
catch (Throwable t) {
return new MethExecutorResult(t);
}
}
/**
*
* A small program for testing this class.
*
*/
public static String testMethod1() {
return "The result is: " + System.currentTimeMillis();
}
public static String testMethod2() {
throw new ArrayIndexOutOfBoundsException("frip");
}
public static void main(String[] args) {
MethExecutorResult result = null;
result = MethExecutor.execute( "hydra.MethExecutor", "testMethod1" );
System.out.println(result.toString());
result = MethExecutor.execute( "hydra.MethExecutor", "testMethod2" );
System.out.println(result.toString());
}
}