package net.csdn.modules.http;
import net.csdn.ServiceFramwork;
import net.csdn.annotation.filter.AroundFilter;
import net.csdn.annotation.filter.BeforeFilter;
import net.csdn.common.collect.Tuple;
import net.csdn.common.logging.CSLogger;
import net.csdn.common.logging.Loggers;
import net.csdn.common.path.PathTrie;
import net.csdn.exception.ArgumentErrorException;
import net.csdn.exception.ExceptionHandler;
import net.csdn.exception.RecordNotFoundException;
import net.csdn.filter.FilterHelper;
import net.csdn.reflect.ReflectHelper;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static net.csdn.common.collections.WowCollections.list;
import static net.csdn.common.logging.support.MessageFormat.format;
/**
* BlogInfo: william
* Date: 11-9-5
* Time: 下午4:24
*/
public class RestController {
private CSLogger logger = Loggers.getLogger(getClass());
private final PathTrie<Tuple<Class<ApplicationController>, Method>> getHandlers = new PathTrie<Tuple<Class<ApplicationController>, Method>>();
private final PathTrie<Tuple<Class<ApplicationController>, Method>> postHandlers = new PathTrie<Tuple<Class<ApplicationController>, Method>>();
private final PathTrie<Tuple<Class<ApplicationController>, Method>> putHandlers = new PathTrie<Tuple<Class<ApplicationController>, Method>>();
private final PathTrie<Tuple<Class<ApplicationController>, Method>> deleteHandlers = new PathTrie<Tuple<Class<ApplicationController>, Method>>();
private final PathTrie<Tuple<Class<ApplicationController>, Method>> headHandlers = new PathTrie<Tuple<Class<ApplicationController>, Method>>();
private final PathTrie<Tuple<Class<ApplicationController>, Method>> optionsHandlers = new PathTrie<Tuple<Class<ApplicationController>, Method>>();
public void registerHandler(RestRequest.Method method, String path, Tuple<Class<ApplicationController>, Method> handler) {
switch (method) {
case GET:
getHandlers.insert(path, handler);
break;
case DELETE:
deleteHandlers.insert(path, handler);
break;
case POST:
postHandlers.insert(path, handler);
break;
case PUT:
putHandlers.insert(path, handler);
break;
case OPTIONS:
optionsHandlers.insert(path, handler);
break;
case HEAD:
headHandlers.insert(path, handler);
break;
default:
throw new ArgumentErrorException("Can't handle [" + method + "] for path [" + path + "]");
}
}
public void dispatchRequest(final RestRequest request, RestResponse restResponse) throws Exception {
final Tuple<Class<ApplicationController>, Method> handlerKey = getHandler(request);
if (handlerKey == null) {
throw new RecordNotFoundException(format("你请求的URL地址[{}]不存在", request.rawPath().toString()));
}
ApplicationController applicationController = ServiceFramwork.injector.getInstance(handlerKey.v1());
enhanceApplicationController(applicationController, request, restResponse);
filter(handlerKey, applicationController);
}
private void enhanceApplicationController(ApplicationController applicationController, final RestRequest request, RestResponse restResponse) throws Exception {
ReflectHelper.field(applicationController, "request", request);
ReflectHelper.field(applicationController, "restResponse", restResponse);
}
private List<Method> whoFilterThisMethod(Class clzz, List<Field> filters, Method method) throws Exception {
List<Method> result = list();
for (Field filter : filters) {
filter.setAccessible(true);
Map filterInfo = (Map) filter.get(null);
String filterMethod = filter.getName().substring(1, filter.getName().length());
if (filterInfo.containsKey(FilterHelper.BeforeFilter.only)) {
List<String> actions = (List<String>) filterInfo.get(FilterHelper.BeforeFilter.only);
if (actions.contains(method.getName())) {
result.add(ReflectHelper.findMethodByName(clzz, filterMethod));
}
} else {
if (filterInfo.containsKey(FilterHelper.BeforeFilter.except)) {
List<String> actions = (List<String>) filterInfo.get(FilterHelper.BeforeFilter.except);
if (actions.contains(method.getName())) {
}
} else {
result.add(ReflectHelper.findMethodByName(clzz, filterMethod));
}
}
}
return result;
}
private void filter(Tuple<Class<ApplicationController>, Method> handlerKey, ApplicationController applicationController) throws Exception {
//check beforeFilter
List<Field> globalBeforeFilters = ReflectHelper.fields(handlerKey.v1().getSuperclass(), BeforeFilter.class);
List<Field> globalAroundFilters = ReflectHelper.fields(handlerKey.v1().getSuperclass(), AroundFilter.class);
List<Field> beforeFilters = ReflectHelper.fields(handlerKey.v1(), BeforeFilter.class);
List<Field> aroundFilters = ReflectHelper.fields(handlerKey.v1(), AroundFilter.class);
globalBeforeFilters.addAll(beforeFilters);
globalAroundFilters.addAll(aroundFilters);
beforeFilters.clear();
aroundFilters.clear();
beforeFilters.addAll(globalBeforeFilters);
aroundFilters.addAll(globalAroundFilters);
Method action = handlerKey.v2();
List<Method> beforeFilterFilterThisAction = whoFilterThisMethod(handlerKey.v1(), beforeFilters, action);
List<Method> aroundFilterFilterThisAction = whoFilterThisMethod(handlerKey.v1(), aroundFilters, action);
for (Method filter : beforeFilterFilterThisAction) {
filter.setAccessible(true);
filter.invoke(applicationController);
}
Iterator<Method> iterator = aroundFilterFilterThisAction.iterator();
WowAroundFilter wowAroundFilter = null;
WowAroundFilter first = null;
if (iterator.hasNext()) {
Method currentFilter = iterator.next();
wowAroundFilter = new WowAroundFilter(currentFilter, handlerKey.v2(), applicationController);
first = wowAroundFilter;
}
while (iterator.hasNext()) {
Method currentFilter = iterator.next();
wowAroundFilter.setNext(new WowAroundFilter(currentFilter, handlerKey.v2(), applicationController));
wowAroundFilter = wowAroundFilter.next;
}
if (first != null) {
first.invoke();
} else {
handlerKey.v2().invoke(applicationController);
}
}
public class WowAroundFilter {
private WowAroundFilter next;
private Method currentFilter;
private Method action;
private ApplicationController applicationController;
public WowAroundFilter(Method currentFilter, Method action, ApplicationController applicationController) {
this.currentFilter = currentFilter;
this.action = action;
this.applicationController = applicationController;
}
public boolean shouldInvokeAction() {
if (next == null) return true;
return false;
}
public void invoke() {
try {
WowAroundFilter wowAroundFilter = this.next;
if (wowAroundFilter == null) {
wowAroundFilter = new WowAroundFilter(null, action, applicationController) {
@Override
public void invoke() {
try {
WowAroundFilter.this.action.invoke(applicationController);
} catch (Exception e) {
try {
ExceptionHandler.renderHandle(e);
} catch (Exception e1) {
try {
throw e1;
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
};
}
currentFilter.setAccessible(true);
currentFilter.invoke(applicationController, wowAroundFilter);
} catch (Exception e) {
try {
ExceptionHandler.renderHandle(e);
} catch (Exception e1) {
try {
throw e1;
} catch (Exception e2) {
}
}
}
}
public void setNext(WowAroundFilter next) {
this.next = next;
}
}
private Tuple<Class<ApplicationController>, Method> getHandler(RestRequest request) {
String path = getPath(request);
RestRequest.Method method = request.method();
if (method == RestRequest.Method.GET) {
return getHandlers.retrieve(path, request.params());
} else if (method == RestRequest.Method.POST) {
return postHandlers.retrieve(path, request.params());
} else if (method == RestRequest.Method.PUT) {
return putHandlers.retrieve(path, request.params());
} else if (method == RestRequest.Method.DELETE) {
return deleteHandlers.retrieve(path, request.params());
} else if (method == RestRequest.Method.HEAD) {
return headHandlers.retrieve(path, request.params());
} else if (method == RestRequest.Method.OPTIONS) {
return optionsHandlers.retrieve(path, request.params());
} else {
return null;
}
}
private String getPath(RestRequest request) {
return request.rawPath();
}
}