package origo.helpers;
import play.Logger;
import play.modules.origo.core.CachedThemeVariant;
import play.mvc.results.Redirect;
import play.utils.Java;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Helper methods for invoking the triggers/origo.listeners/hooks.
*/
public class ReflectionHelper {
/**
* Uses reflection to invoke the annotated method.
*
* @param method a cached annotated method
* @param parameters possible parameters for this invocation
* @return whatever object the listener returns, if any.
*/
public static Object invokeMethod(Method method, Map<Class, Object> parameters) {
if (!Modifier.isStatic(method.getModifiers())) {
throw new RuntimeException("Method \'" + method.getDeclaringClass().getName() + "." + method.getName() + "\' is not static");
}
Class[] parameterTypes = method.getParameterTypes();
Object[] foundParameters;
try {
foundParameters = getInvocationParameters(parameterTypes, parameters);
} catch (UnknownParameterTypeException e) {
throw new RuntimeException("Method \'" + method + "\' has a parameter of type \'" + e.getParameterType() + "\' specified. No parameter of that type exists in the calling parameters");
}
try {
return Java.invokeStatic(method, foundParameters);
} catch (Redirect redirect) {
throw redirect;
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof Redirect) {
throw (Redirect) e.getTargetException();
}
throw new RuntimeException(e.getTargetException().getMessage(), e);
} catch (Exception e) {
Logger.error("Unable to invoke method \'" + method.getDeclaringClass().getName() + "." + method.getName() + "\'");
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* Tries to match up the parameter types to known entities and constructs the array of parameters.
*
* @param parameterTypes an array of types this trigger method takes
* @param parameters possible parameters for this invocation
* @return a list of parameters matching the parameter types
* @throws UnknownParameterTypeException is thrown when there is no matching parameter for a specified parameter type in the method
*/
@SuppressWarnings("unchecked")
public static Object[] getInvocationParameters(Class[] parameterTypes, Map<Class, Object> parameters) throws UnknownParameterTypeException {
List foundParameters = new ArrayList();
for (Class parameterType : parameterTypes) {
Object parameter = findParameter(parameters, parameterType);
if (parameter != null) {
foundParameters.add(parameter);
}
}
return foundParameters.toArray();
}
//TODO: Cache this instead of looking it up every time
private static Object findParameter(Map<Class, Object> parameters, Class parameterType) throws UnknownParameterTypeException {
if (!Object.class.equals(parameterType) && parameterType != null) {
// Check if the parameter map contains the class from parameterType
Object parameter = parameters.get(parameterType);
if (parameter != null) {
return parameter;
} else {
parameter = findParameterOfSuperType(parameters, parameterType);
if (parameter != null) {
return parameter;
}
}
}
throw new UnknownParameterTypeException("No parameter of type \'" + parameterType + "\' was found and it has no super class or interface", parameterType);
}
private static Object findParameterOfSuperType(Map<Class, Object> parameters, Class parameterType) {
if (parameterType != null) {
for (Class cls : parameterType.getInterfaces()) {
Object parameter = parameters.get(cls);
if (parameter != null) {
return parameter;
}
parameter = findParameterOfSuperType(parameters, cls.getSuperclass());
if (parameter != null) {
return parameter;
}
}
}
return null;
}
public static String invokeDecorator(play.modules.origo.core.CachedDecorator decorator, Map<Class, Object> parameters) {
return (String) invokeMethod(decorator.method, parameters);
}
public static String getTemplate(CachedThemeVariant themeVariant) {
try {
return (String) invokeMethod(themeVariant.templateMethod, null);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}