package cn.bran.play;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer;
import play.data.binding.Unbinder;
import play.exceptions.ActionNotFoundException;
import play.exceptions.NoRouteFoundException;
import play.exceptions.PlayException;
import play.exceptions.UnexpectedException;
import play.mvc.ActionInvoker;
import play.mvc.Router;
import play.mvc.Http.Request;
import play.mvc.Router.ActionDefinition;
/**
* this file is copied from the the the following code is copied from the
* play.templates
* .GroovyTemplate.ExecutableTemplate.ActionBridge.invokeMethod(...); version 1.2 trunk.
*
* since the class is not public.
*
* Please check this with the original source code to find any updates to bring over.
*
* @author Bing Ran<bing_ran@hotmail.com>
*
*/
public class ActionBridge {
boolean absolute = false;
public ActionBridge(boolean absolute) {
this.absolute = absolute;
}
public Object _abs() {
this.absolute = true;
return this;
}
/**
* this is really to to the reverse url lookup
*
* @param actionString
* @param param
* @return
*/
public ActionDefinition invokeMethod(String actionString, Object param) {
try {
String controllerName = Request.current().controller;
// forms: Controller.action, action, package.Controller.action
String action = actionString;
// String methodName = actionString;
if (actionString.indexOf(".") > 0) {
int lastIndexOf = actionString.lastIndexOf('.');
// methodName = actionString.substring(lastIndexOf + 1);
controllerName = actionString.substring(0, lastIndexOf);
// fell spec with controller name
} else {
action = controllerName + "." + actionString;
}
try {
Map<String, Object> r = new HashMap<String, Object>();
Method actionMethod = (Method) ActionInvoker.getActionMethod(action)[1];
String[] names = (String[]) actionMethod
.getDeclaringClass()
.getDeclaredField(
"$" + actionMethod.getName()
+ LocalVariablesNamesTracer.computeMethodHash(actionMethod.getParameterTypes())).get(null);
if (param instanceof Object[]) {
// too many parameters versus action, possibly a developer
// error. we must warn him.
if (names.length < ((Object[]) param).length) {
throw new NoRouteFoundException(action, null);
}
for (int i = 0; i < ((Object[]) param).length; i++) {
if (((Object[]) param)[i] instanceof Router.ActionDefinition && ((Object[]) param)[i] != null) {
Unbinder.unBind(r, ((Object[]) param)[i].toString(), i < names.length ? names[i] : "");
} else if (isSimpleParam(actionMethod.getParameterTypes()[i])) {
if (((Object[]) param)[i] != null) {
Unbinder.unBind(r, ((Object[]) param)[i].toString(), i < names.length ? names[i] : "");
}
} else {
Unbinder.unBind(r, ((Object[]) param)[i], i < names.length ? names[i] : "");
}
}
}
Router.ActionDefinition def = Router.reverse(action, r);
if (absolute) {
def.absolute();
}
// if (template.template.name.endsWith(".html") ||
// template.template.name.endsWith(".xml")) {
def.url = def.url.replace("&", "&");
// }
return def;
} catch (ActionNotFoundException e) {
throw new NoRouteFoundException(action, null);
}
} catch (Exception e) {
if (e instanceof PlayException) {
throw (PlayException) e;
}
throw new UnexpectedException(e);
}
}
static boolean isSimpleParam(Class type) {
return Number.class.isAssignableFrom(type) || type.equals(String.class) || type.isPrimitive();
}
}