/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2013 Ausenco Engineering Canada Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaamsim.basicsim;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.jaamsim.events.ProcessTarget;
public class ReflectionTarget extends ProcessTarget {
private final Entity target; // The entity whose method is to be executed
private final Method method; // The method to be executed
private final Object[] arguments; // The arguments passed to the method to be executed
public ReflectionTarget(Entity ent, String methodName, Object... arguments) {
target = ent;
method = findEntityMethod(target.getClass(), methodName, arguments);
this.arguments = arguments;
}
@Override
public void process() {
try {
method.invoke(target, arguments);
}
// Normal exceptions thrown by the method called by invoke are wrapped
catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException)
throw (RuntimeException)cause;
else
throw new ErrorException(cause);
}
catch (IllegalArgumentException e) {
throw e;
}
catch (IllegalAccessException e) {
throw new ErrorException(e);
}
}
@Override
public String getDescription() {
return String.format("%s.%s", target.getName(), method.getName());
}
// Look up the method with the given name for the given entity and argument list.
private Method findEntityMethod(Class<?> targetClass, String methodName, Object... arguments) {
Class<?>[] argClasses = new Class<?>[arguments.length];
// Fill in the class of each argument, if there are any
for (int i = 0; i < arguments.length; i++) {
// The argument itself is null, no class information available
if (arguments[i] == null) {
argClasses[i] = null;
continue;
}
argClasses[i] = arguments[i].getClass();
// We wrap primitive doubles as Double, put back the primitive type
if (argClasses[i] == Double.class) {
argClasses[i] = Double.TYPE;
}
// We wrap primitive integers as Integer, put back the primitive type
if (argClasses[i] == Integer.class) {
argClasses[i] = Integer.TYPE;
}
}
// Attempt to lookup the method using exact type information
try {
return targetClass.getMethod(methodName, argClasses);
}
catch (SecurityException e) {
throw new ErrorException("Security Exception when finding method: %s", methodName);
}
catch (NullPointerException e) {
throw new ErrorException("Name passed to startProcess was NULL");
}
catch (NoSuchMethodException e) {
// Get a list of all our methods
Method[] methods = targetClass.getMethods();
// Loop over all methods looking for a unique method name
int matchIndexHolder = -1;
int numMatches = 0;
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName)) {
numMatches++;
matchIndexHolder = i;
}
}
// If there was only one method found, use it
if (numMatches == 1)
return methods[matchIndexHolder];
else
throw new ErrorException("Method: %s does not exist, could not invoke.", methodName);
}
}
}