package org.theonefx.wcframework.mvc.wcweb;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpSession;
import org.theonefx.wcframework.core.ClassWrapper;
import org.theonefx.wcframework.core.InitializableBean;
import org.theonefx.wcframework.ioc.val.GenericTypeResolver;
import org.theonefx.wcframework.ioc.val.MethodParameter;
import org.theonefx.wcframework.mvc.MVCConfig;
import org.theonefx.wcframework.mvc.annotation.BodyType;
import org.theonefx.wcframework.mvc.annotation.Param;
import org.theonefx.wcframework.mvc.annotation.ParamSource;
import org.theonefx.wcframework.mvc.annotation.ParamType;
import org.theonefx.wcframework.mvc.annotation.ResponseBody;
import org.theonefx.wcframework.mvc.exception.CannotEnsureTranslateException;
import org.theonefx.wcframework.mvc.exception.ParamTranslateException;
import org.theonefx.wcframework.mvc.wcweb.translate.ArgsTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.ArrayParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.BeanParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.CollectionParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.DefaultParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.EnumParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.FileTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.JavaBeanParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.MapParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.ParamTranslatSupport;
import org.theonefx.wcframework.mvc.wcweb.translate.ParamTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.RequestTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.ResponseTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.ServletContextTranslater;
import org.theonefx.wcframework.mvc.wcweb.translate.SessionTranslater;
import org.theonefx.wcframework.utils.StringUtils;
/**
* @File : ActionInvoker.java
* @ClassName : ActionInvoker
* @Author : TheoneFx
* @Date : 2012-4-21 下午09:21:58
* @Version : v1.0
* @Description : Action调用器,用于调用action,返回view
*/
public class ActionInvoker implements Comparable<ActionInvoker>, InitializableBean, Action {
private String nameSpace;
private PathMatcher matcher;
private String beanId;
private Method method;
private View[] views;
private String encoding = null;
private String name;
private ParamTranslater[] translaters;
private BodyType bodyType;
/**
* Action类的包装器
*/
private ClassWrapper<?> classWrapper;
public String getBeanId() {
return beanId;
}
public void setBeanId(String beanId) {
this.beanId = beanId;
}
public Method getMethod() {
return method;
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public void setMethod(Method method) {
this.method = method;
}
public View[] getViews() {
return views;
}
public void setViews(View[] views) {
this.views = views;
}
public ActionInvoker(PathMatcher matcher) {
this.matcher = matcher;
}
public PathMatcher getMatcher() {
return matcher;
}
public void setNameSpace(String namespace) {
this.nameSpace = namespace;
}
@Override
public String getNamespace() {
return nameSpace;
}
@Override
public String getName() {
return name;
}
@Override
public int compareTo(ActionInvoker o) {
return matcher.getLevel() - o.getMatcher().getLevel();
}
@Override
public BodyType getBodyType() {
return bodyType;
}
public void setBodyType(BodyType bodyType) {
this.bodyType = bodyType;
}
@Override
public Object execute(ActionInvocationContext ctx) throws Exception {
// 获得action的bean对象
Object bean = ctx.getWebApplicationContext().getBean(beanId);
if (StringUtils.isBlank(encoding)) {
encoding = MVCConfig.defaultEncoding;
}
// action方法调用的返回值
Object ret = null;
if (translaters == null || translaters.length == 0) {
ret = method.invoke(bean);
} else {
// 自动转换params
Object[] params = new Object[translaters.length];
for (int i = 0; i < params.length; i++) {
ParamTranslater translater = translaters[i];
params[i] = translater.translate(ctx);
}
ret = method.invoke(bean, params);
}
return ret;
}
@Override
public void initialize() throws Exception {
ResponseBody responseBody = method.getAnnotation(ResponseBody.class);
if (responseBody != null) {
BodyType type = responseBody.type();
if (type != null) {
bodyType = type;
}
}
// 生成参数转换器
Annotation[][] annoss = method.getParameterAnnotations();
Class<?>[] types = method.getParameterTypes();
if (types.length == 0) {
// 没有参数
} else if (types.length == 1 && annoss.length == 0) {
// 唯一参数,无注解
translaters = new ParamTranslater[1];
MethodParameter methodParam = new MethodParameter(method, 0);
Class<?> type = GenericTypeResolver.resolveParameterType(methodParam, classWrapper.getWrapperedClass());
ParamTranslatSupport paramTranslat = getTranslaterFromType(type);
paramTranslat.setSources(new ParamSource[] { ParamSource.REQUEST });
paramTranslat.setAction(this);
translaters[0] = paramTranslat;
try {
translaters[0].initialize();
} catch (Exception e) {
throw new ParamTranslateException("创建转换器出错:Method=" + method.getName() + " paramType=" + type.getName() + " paramName=" + name);
}
} else {
// 有参数情况下的处理
// 创建转换器数组,大小和参数数量一致
translaters = new ParamTranslater[types.length];
// 循环处理每一个参数
for (int i = 0; i < annoss.length; i++) {
ParamTranslatSupport translater = null;
// 这是参数的真实类型
MethodParameter methodParam = new MethodParameter(method, i);
Class<?> type = GenericTypeResolver.resolveParameterType(methodParam, classWrapper.getWrapperedClass());
// 这是某个参数的注解数组
Annotation[] annos = annoss[i];
// 属性名
String name = null;
boolean xss = false;
ParamSource[] sources = null;
// 循环查找某个参数的注解,看看有没有@Param注解,如果找不到就在下面的if中处理了
for (Annotation anno : annos) {
ParamType paramType = null;
if (anno instanceof Param) {
Param p = (Param) anno;
paramType = p.type();
name = p.value();
xss = p.XSS();
sources = p.source();
} else {
continue;
}
switch (paramType) {
case AUTO:
translater = getTranslaterFromType(type);
break;
case GENERIC:
translater = new DefaultParamTranslater();
break;
case BEAN:
translater = new JavaBeanParamTranslater();
break;
case REF:
translater = new BeanParamTranslater();
break;
case FILE:
if (!UploadFile.class.isAssignableFrom(type)) {
throw new CannotEnsureTranslateException("FILE型的参数必须是一个org.theonefx.wcframework.mvc.wcweb.UploadFile");
}
translater = new FileTranslater();
break;
default:
throw new CannotEnsureTranslateException("怎么可能?没有指定的参数转换器?我把整个枚举都检查了啊。。。。");
}
// 找到一个合适的就退出annotation的遍历
break;
}
if(sources == null){
sources = new ParamSource[] { ParamSource.REQUEST };
}
// 如果没有找到对应的@Param注解,那么就看是不是
if (translater == null) {
translater = getTranslaterFromType(type);
}
translater.setXss(xss);
translater.setSources(sources);
translater.setName(name);
translater.setParamType(type);
translater.setMethodParam(methodParam);
translater.setAction(this);
translaters[i] = translater;
try {
translaters[i].initialize();
} catch (Exception e) {
throw new ParamTranslateException("创建转换器出错:Method=" + method.getName() + " paramType=" + type.getName() + " paramName=" + name);
}
}
}
}
public ParamTranslatSupport getTranslaterFromType(Class<?> type) {
ParamTranslatSupport translater = null;
if (type.isPrimitive() || type == String.class || type == Integer.class || type == Short.class || type == Byte.class || type == Long.class
|| type == Boolean.class || type == Character.class || type == Float.class || type == Double.class) {
translater = new DefaultParamTranslater();
} else if (Collection.class.isAssignableFrom(type)) {
translater = new CollectionParamTranslater();
} else if (Map.class.isAssignableFrom(type)) {
translater = new MapParamTranslater();
} else if (type.isEnum()) {
translater = new EnumParamTranslater();
} else if (ServletRequest.class.isAssignableFrom(type)) {
translater = new RequestTranslater();
} else if (HttpSession.class.isAssignableFrom(type)) {
translater = new SessionTranslater();
} else if (ServletResponse.class.isAssignableFrom(type)) {
translater = new ResponseTranslater();
} else if (ServletContext.class.isAssignableFrom(type)) {
translater = new ServletContextTranslater();
} else if (ArgsHolder.class.isAssignableFrom(type)) {
translater = new ArgsTranslater();
} else if (UploadFile.class.isAssignableFrom(type) || (type.isArray() && UploadFile.class.isAssignableFrom(type.getComponentType()))) {
translater = new FileTranslater();
} else if (type.isArray()) {
translater = new ArrayParamTranslater();
} else {
translater = new JavaBeanParamTranslater();
}
return translater;
}
public void setClassWrapper(ClassWrapper<?> wrapper) {
this.classWrapper = wrapper;
}
}