package com.github.aesteve.vertx.nubes.reflections.visitors;
import com.github.aesteve.vertx.nubes.Config;
import com.github.aesteve.vertx.nubes.annotations.Controller;
import com.github.aesteve.vertx.nubes.annotations.filters.AfterFilter;
import com.github.aesteve.vertx.nubes.annotations.filters.BeforeFilter;
import com.github.aesteve.vertx.nubes.handlers.AnnotationProcessor;
import com.github.aesteve.vertx.nubes.handlers.Processor;
import com.github.aesteve.vertx.nubes.reflections.Filter;
import com.github.aesteve.vertx.nubes.reflections.RouteRegistry;
import com.github.aesteve.vertx.nubes.reflections.factories.AuthenticationFactory;
import com.github.aesteve.vertx.nubes.routing.MVCRoute;
import io.vertx.core.VertxException;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.BiConsumer;
public class ControllerVisitor<T> extends BaseVisitor<T> {
private final Method[] methods;
final String basePath;
final AuthenticationFactory authFactory;
final RouteRegistry routeRegistry;
final Map<Class<? extends Annotation>, BiConsumer<RoutingContext, ?>> returnHandlers;
final Set<Processor> processors;
private final Set<Filter> beforeFilters;
private final Set<Filter> afterFilters;
public ControllerVisitor(Class<T> controllerClass, Config config, Router router, AuthenticationFactory authFactory, RouteRegistry routeRegistry, Map<Class<? extends Annotation>, BiConsumer<RoutingContext, ?>> returnHandlers) {
super(controllerClass, config, router);
this.routeRegistry = routeRegistry;
this.returnHandlers = returnHandlers;
methods = controllerClass.getDeclaredMethods();
Controller base = clazz.getAnnotation(Controller.class);
basePath = base.value();
this.authFactory = authFactory;
processors = new LinkedHashSet<>();
beforeFilters = new TreeSet<>();
afterFilters = new TreeSet<>();
}
public List<MVCRoute> visit() throws IllegalAccessException, InstantiationException {
instance = clazz.newInstance();
List<MVCRoute> routes = new ArrayList<>();
try {
injectServices();
} catch (IllegalAccessException iae) {
throw new VertxException(iae);
}
extractFilters();
for (Method method : methods) {
MethodVisitor<T> visitor = new MethodVisitor<>(this, method);
routes.addAll(visitor.visit());
}
for (MVCRoute route : routes) {
route.addProcessorsFirst(processors);
route.addBeforeFilters(beforeFilters);
route.addAfterFilters(afterFilters);
}
return routes;
}
private void extractFilters() {
if (hasSuperClass()) {
ControllerVisitor<?> superClass = new ControllerVisitor<>(clazz.getSuperclass(), config, router, authFactory, routeRegistry, returnHandlers);
superClass.extractFilters();
beforeFilters.addAll(superClass.beforeFilters);
afterFilters.addAll(superClass.afterFilters);
processors.addAll(superClass.processors);
}
for (Method method : methods) {
BeforeFilter beforeAnnot = method.getAnnotation(BeforeFilter.class);
AfterFilter afterAnnot = method.getAnnotation(AfterFilter.class);
if (beforeAnnot != null) {
beforeFilters.add(new Filter(method, beforeAnnot));
} else if (afterAnnot != null) {
afterFilters.add(new Filter(method, afterAnnot));
}
}
for (Annotation annotation : clazz.getDeclaredAnnotations()) {
AnnotationProcessor<?> controllerProcessor = config.getAnnotationProcessor(annotation);
if (controllerProcessor != null) {
processors.add(controllerProcessor);
}
}
}
private boolean hasSuperClass() {
return clazz.getSuperclass() != null && !clazz.getSuperclass().equals(Object.class);
}
}