package org.theonefx.wcframework.mvc.wcweb;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.theonefx.wcframework.core.ClassWrapper;
import org.theonefx.wcframework.core.exception.InpossibleException;
import org.theonefx.wcframework.core.exception.UnFinishException;
import org.theonefx.wcframework.mvc.MVCConfig;
import org.theonefx.wcframework.mvc.annotation.Action;
import org.theonefx.wcframework.mvc.annotation.Controller;
import org.theonefx.wcframework.mvc.annotation.PathMatchType;
import org.theonefx.wcframework.mvc.annotation.Result;
import org.theonefx.wcframework.mvc.exception.ActionInvocationException;
import org.theonefx.wcframework.mvc.exception.MVCException;
import org.theonefx.wcframework.mvc.wcweb.view.BasicAuthoView;
import org.theonefx.wcframework.mvc.wcweb.view.ForwardView;
import org.theonefx.wcframework.mvc.wcweb.view.JSONView;
import org.theonefx.wcframework.mvc.wcweb.view.NULLView;
import org.theonefx.wcframework.mvc.wcweb.view.RedirectActionView;
import org.theonefx.wcframework.mvc.wcweb.view.RedirectView;
import org.theonefx.wcframework.utils.StringUtils;
/**
* @File : ControllerRegister.java
* @ClassName : ControllerRegister
* @Author : 陈曦
* @Date : 2012-4-1 下午02:31:21
* @Version : v1.0
* @Description : 控制器注册器。控制器可以是一个Action,也可以是过滤器。二者都可以返回一个View对象
*/
public class ControllerRegister {
private final Log log = LogFactory.getLog(getClass());
private final List<ActionInvoker> actions = new ArrayList<ActionInvoker>();
private final List<FilterInvoker> filters = new ArrayList<FilterInvoker>();
@SuppressWarnings("unused")
private ServletContext servletContext;
public ControllerRegister(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void registAction(Method method, Action action, ClassWrapper<?> wrapper, String beanId, Controller controller) {
PathMatchType matchType = action.matchType();
String path = action.path();
// 没有指明path就是用方法名的小写
if (StringUtils.isBlank(path)) {
path = method.getName().toLowerCase();
}
// 检查namespace
// 如果namespace不存在,那么就是跟,即:"/"
String namespace = "/";
if (controller != null) {
namespace = StringUtils.isBlank(controller.namespace()) ? "/" : controller.namespace();
}
// 首先检查path是否是"/"开头
// 如果是"/"开头则忽略namespace
// 否则添加namespace信息,如果namespace没有"/"开头,则给namespace增加"/"开头
// 但是如果没有"/"开头,也没有namespace则默认添加"/"开头
if (!path.startsWith("/") && StringUtils.isNotBlank(namespace)) {
if (!namespace.endsWith("/")) {
namespace = namespace + "/";
}
if (!namespace.startsWith("/")) {
namespace = "/" + namespace;
}
path = namespace + path;
} else if (!path.startsWith("/") && StringUtils.isBlank(namespace)) {
path = "/" + path;
} else {
// 这个else都是以/开头的情况了,直接忽略namespace
}
PathMatcher matcher = null;
switch (matchType) {
case ABSOLUTE:
matcher = new AbsolutePathMatcher(path);
break;
case SIMPLE:
matcher = new SimplePathMatcher(path);
break;
case PATTERN:
matcher = new PatternPathMatcher(path);
break;
case SMART:
matcher = new SmartPathMatcher(path);
break;
}
ActionInvoker invoker = new ActionInvoker(matcher);
invoker.setBeanId(beanId);
// 设置编码参数
if (!org.theonefx.wcframework.mvc.annotation.Action.DefaultEncoding.equals(action.encoding())) {
invoker.setEncoding(action.encoding());
}
invoker.setMethod(method);
invoker.setNameSpace(namespace);
invoker.setClassWrapper(wrapper);
// 局部Result
Result[] results = action.result();
// 全局Result
Result[] globalResults = {};
if (controller != null && controller.result() != null) {
globalResults = controller.result();
}
ArrayList<View> viewsArray = new ArrayList<View>();
Set<String> registedResultNames = new HashSet<String>();
for (int i = 0; i < (results.length + globalResults.length); i++) {
Result result = null;
if (i < results.length) {
result = results[i];
} else {
result = globalResults[i - results.length];
}
// 不能重复的名称,因为会先取局部后取全局,所以会用子的覆盖全局的
if (registedResultNames.contains(result.name())) {
continue;
}
View view = getView(result);
String encoding = result.encoding();
if (!Result.DefaultEncoding.equals(encoding)) {
if (encoding == null) {
encoding = MVCConfig.defaultEncoding;
}
view.setEncoding(encoding);
}
view.setIgnoreEl(result.ignoreEl());
registedResultNames.add(result.name());
viewsArray.add(view);
}
if (viewsArray.size() == 0) {
throw new MVCException("Action[" + method.getDeclaringClass().getName() + "." + method.getName() + "]没有对应的视图(局部的和全局的都没有)");
}
invoker.setViews(viewsArray.toArray(new View[viewsArray.size()]));
addAction(invoker);
// TODO FilteBy还没搞完
}
private void addAction(ActionInvoker invoker) {
for (ActionInvoker in : actions) {
if (in.getMatcher().sameAs(invoker.getMatcher())) {
throw new MVCException("定义了两个一样的Action于相同的Matcher");
}
}
try {
invoker.initialize();
} catch (Exception e) {
throw new ActionInvocationException("创建ActionInvoker出错:Class=", e);
}
if (log.isDebugEnabled()) {
log.debug("注册Action,Path=" + invoker.getMatcher().getExpression() + " Method=" + invoker.getMethod().getDeclaringClass().getName() + "."
+ invoker.getMethod().getName());
}
actions.add(invoker);
}
private void addFilter(FilterInvoker invoker) {
for (FilterInvoker in : filters) {
if (in.getPathMatcher().sameAs(invoker.getPathMatcher()) && StringUtils.equal(in.getBeanId(), invoker.getBeanId())) {
throw new MVCException("定义了两个一样的Filter于相同的path");
}
}
try {
invoker.initialize();
} catch (Exception e) {
throw new ActionInvocationException("创建FilterInvoker出错:Class=", e);
}
filters.add(invoker);
}
public void registFilter(org.theonefx.wcframework.mvc.annotation.Filter filter, ClassWrapper<?> wrapper, String beanId) {
FilterInvoker invoker = new FilterInvoker();
switch (filter.matchType()) {
case ABSOLUTE:
invoker.setPathMatcher(new AbsolutePathMatcher(filter.match()));
break;
case PATTERN:
invoker.setPathMatcher(new PatternPathMatcher(filter.match()));
break;
case SIMPLE:
invoker.setPathMatcher(new SimplePathMatcher(filter.match()));
break;
default:
throw new InpossibleException("怎么可能");
}
invoker.setBeanId(beanId);
Result[] results = filter.result();
View[] views = new View[results.length];
for (int i = 0; i < results.length; i++) {
Result result = results[i];
views[i] = getView(result);
}
invoker.setLevel(filter.level());
invoker.setViews(views);
addFilter(invoker);
}
private View getView(Result result){
View view = null;
switch (result.type()) {
case FORWARD:
view = new ForwardView(result.name(), result.value(), result.contextType());
break;
case REDIRECT:
view = new RedirectView(result.name(), result.value(), result.contextType());
break;
case REDIRECTACTION:
view = new RedirectActionView(result.name(), result.value(), result.contextType());
break;
case JSON:
view = new JSONView(result.name(), result.contextType());
break;
case NULL:
view = new NULLView(result.name(), result.contextType());
break;
case BASICAUTHO:
view = new BasicAuthoView(result.name(), result.contextType());
break;
default:
// 其实都实现了,不过这里不改了,出这个异常也不可能的。。。。
throw new UnFinishException();
}
return view;
}
public List<FilterInvoker> getFilters() {
return filters;
}
public List<ActionInvoker> getActions() {
return actions;
}
public void refresh() {
synchronized (actions) {
Collections.sort(actions);
}
}
}