Add Constroller system; a class that contains 0-N methods with Route's annotation; can have Matcher, Context, Reader or Write, or none of them
This commit is contained in:
parent
b47ffac3b1
commit
2cf4363e25
4 changed files with 122 additions and 61 deletions
|
@ -13,10 +13,12 @@ public class DependencyInjector{
|
|||
private Map<String, Object> map;
|
||||
private List<BiFunction<Constructor<?>, Parameter, Object>> builders;
|
||||
private Object[] injections;
|
||||
private Map<Class<?>, Object> cache;
|
||||
|
||||
public DependencyInjector(){
|
||||
this.map = new HashMap<>();
|
||||
this.builders = new ArrayList<>();
|
||||
this.cache = new HashMap<>();
|
||||
}
|
||||
|
||||
public DependencyInjector of(String name, Object value){
|
||||
|
@ -41,7 +43,7 @@ public class DependencyInjector{
|
|||
return this;
|
||||
}
|
||||
|
||||
Object applyDependency(Constructor<?> constructor, Parameter parameter, Map<Class<?>, Object> cache){
|
||||
Object applyDependency(Constructor<?> constructor, Parameter parameter){
|
||||
Injection annotation = parameter.getAnnotation(Injection.class);
|
||||
if(annotation != null){
|
||||
Object result = this.map.get(annotation.value());
|
||||
|
@ -52,8 +54,8 @@ public class DependencyInjector{
|
|||
Object result = function.apply(constructor, parameter);
|
||||
if(result != null) return result;
|
||||
}
|
||||
if(this.injections == null) return null;
|
||||
Class<?> type = parameter.getType();
|
||||
if(this.injections == null) throw new IllegalArgumentException("No dependency for type "+type+" in constructor "+constructor);
|
||||
Object result = null;
|
||||
for(Object injection : injections){
|
||||
if(type.isAssignableFrom(injection.getClass())){
|
||||
|
@ -65,6 +67,7 @@ public class DependencyInjector{
|
|||
}
|
||||
}
|
||||
}
|
||||
if(result == null) throw new IllegalArgumentException("No dependency for type "+type+" in constructor "+constructor);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -12,73 +12,61 @@ public class RouteMapper<U extends User>{
|
|||
|
||||
private Router<U> router;
|
||||
|
||||
private Response[] responses;
|
||||
private Method[] methods;
|
||||
private Route[] routes;
|
||||
private Pattern[] patterns;
|
||||
private RouteState[] states;
|
||||
private int[] calls;
|
||||
private int dif;
|
||||
|
||||
public RouteMapper(Router<U> router){
|
||||
this.router = router;
|
||||
this.responses = new Response[0];
|
||||
this.methods = new Method[0];
|
||||
this.routes = new Route[0];
|
||||
this.patterns = new Pattern[0];
|
||||
this.states = new RouteState[0];
|
||||
}
|
||||
|
||||
public void register(Response response, Method method, Route route, Pattern pattern){
|
||||
int length = responses.length+1;
|
||||
this.responses = addElement(responses, new Response[length], response);
|
||||
this.methods = addElement(methods, new Method[length], method);
|
||||
this.routes = addElement(routes, new Route[length], route);
|
||||
this.patterns = addElement(patterns, new Pattern[length], pattern);
|
||||
public void register(Object instance, Method method, Route route){
|
||||
int length = states.length+1;
|
||||
this.states = addElement(states, new RouteState[length], new RouteState(instance, method, route));
|
||||
if(this.calls != null) this.calls = new int[length];
|
||||
}
|
||||
|
||||
public void activeReOrdering(){
|
||||
this.calls = new int[responses.length];
|
||||
this.calls = new int[states.length];
|
||||
this.dif = 2;
|
||||
}
|
||||
|
||||
public boolean exec(Context context, HttpReader reader, HttpWriter writer, List<RouteInterceptor> interceptors) throws Exception{
|
||||
Response response = null;
|
||||
Method method = null;
|
||||
RouteState target = null;
|
||||
Matcher matcher = null;
|
||||
|
||||
String path = context.getPath();
|
||||
|
||||
synchronized(responses){
|
||||
for(int i = 0; i < responses.length; i++){
|
||||
Route route = routes[i];
|
||||
Pattern pattern = patterns[i];
|
||||
matcher = pattern.matcher(path);
|
||||
if(matcher.matches()){
|
||||
if(route.websocket()){
|
||||
synchronized(states){
|
||||
for(int i = 0; i < states.length; i++){
|
||||
RouteState state = states[i];
|
||||
matcher = state.match(path);
|
||||
if(matcher != null){
|
||||
if(state.isWebSocket()){
|
||||
switchToWebSocket(reader, writer);
|
||||
reader = new WebSocketReader(reader);
|
||||
writer = new WebSocketWriter(writer);
|
||||
if(route.needLogin()){
|
||||
if(state.needLogin()){
|
||||
String token = reader.<JsonMap>readJson().get("token");
|
||||
context.setUser(this.router.getUser(token));
|
||||
}
|
||||
}
|
||||
if((!context.isLogged()) && route.needLogin()){
|
||||
if((!context.isLogged()) && state.needLogin()){
|
||||
writer.response(401, router.getDefaultHeaders(context.getType()));
|
||||
return true;
|
||||
}
|
||||
response = responses[i];
|
||||
method = methods[i];
|
||||
target = state;
|
||||
order(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(response != null){
|
||||
if(target != null){
|
||||
for(RouteInterceptor interceptor : interceptors){
|
||||
if(!interceptor.intercept(matcher, context, reader, writer, method)) return true;
|
||||
if(!interceptor.intercept(matcher, context, reader, writer, target.getMethod())) return true;
|
||||
}
|
||||
response.exec(matcher, context, reader, writer);
|
||||
target.getMethod().invoke(target.getInstance(), target.bindMethod(matcher, context, reader, writer));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -94,10 +82,7 @@ public class RouteMapper<U extends User>{
|
|||
}
|
||||
if(index < 1) return;
|
||||
if(call > this.calls[index-1]){
|
||||
switchElement(responses, index, index-1);
|
||||
switchElement(methods, index, index-1);
|
||||
switchElement(routes, index, index-1);
|
||||
switchElement(patterns, index, index-1);
|
||||
switchElement(states, index, index-1);
|
||||
|
||||
this.calls[index] = this.calls[index-1];
|
||||
this.calls[index-1] = call;
|
||||
|
|
72
src/dev/peerat/framework/RouteState.java
Normal file
72
src/dev/peerat/framework/RouteState.java
Normal file
|
@ -0,0 +1,72 @@
|
|||
package dev.peerat.framework;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RouteState {
|
||||
|
||||
private Object instance;
|
||||
private Method method;
|
||||
private Route route;
|
||||
private Pattern pattern;
|
||||
private int[] bindMethod;
|
||||
|
||||
public RouteState(Object instance, Method method, Route route){
|
||||
this.instance = instance;
|
||||
this.method = method;
|
||||
this.route = route;
|
||||
this.pattern = Pattern.compile(route.path());
|
||||
|
||||
Class<?>[] parameters = method.getParameterTypes();
|
||||
this.bindMethod = new int[4];
|
||||
this.bindMethod[0] = findIndex(parameters, Matcher.class);
|
||||
this.bindMethod[1] = findIndex(parameters, Context.class);
|
||||
this.bindMethod[2] = findIndex(parameters, HttpReader.class);
|
||||
this.bindMethod[3] = findIndex(parameters, HttpWriter.class);
|
||||
}
|
||||
|
||||
public Matcher match(String path){
|
||||
Matcher matcher = pattern.matcher(path);
|
||||
return matcher.matches() ? matcher : null;
|
||||
}
|
||||
|
||||
public boolean isWebSocket(){
|
||||
return route.websocket();
|
||||
}
|
||||
|
||||
public boolean needLogin(){
|
||||
return route.needLogin();
|
||||
}
|
||||
|
||||
public Method getMethod(){
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public Object getInstance(){
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
public Object[] bindMethod(Matcher matcher, Context context, HttpReader reader, HttpWriter writer){
|
||||
Object[] result = new Object[method.getParameterCount()];
|
||||
setElement(result, bindMethod[0], matcher);
|
||||
setElement(result, bindMethod[1], context);
|
||||
setElement(result, bindMethod[2], reader);
|
||||
setElement(result, bindMethod[3], writer);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void setElement(Object[] array, int position, Object element){
|
||||
if(position < 0) return;
|
||||
array[position] = element;
|
||||
}
|
||||
|
||||
private int findIndex(Class<?>[] array, Class<?> type){
|
||||
for(int i = 0; i < array.length; i++){
|
||||
Class<?> clazz = array[i];
|
||||
if(type.isAssignableFrom(clazz)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -105,13 +105,33 @@ public class Router<U extends User>{
|
|||
Response.class.getDeclaredMethods()[0].getParameterTypes());
|
||||
Route route = method.getAnnotation(Route.class);
|
||||
|
||||
this.mappers[route.type().ordinal()].register(response, method, route, Pattern.compile(route.path()));
|
||||
this.mappers[route.type().ordinal()].register(response, method, route);
|
||||
}catch(Exception e){
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Router<U> registerClass(Class<?> clazz, Object... injections) throws Exception{
|
||||
return registerClass(clazz, new DependencyInjector().of(injections));
|
||||
}
|
||||
|
||||
public Router<U> registerClass(Class<?> clazz, DependencyInjector injector) throws Exception{
|
||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
||||
if(constructors.length != 1) throw new IllegalArgumentException("Class with multiple constructor. Not supported by this framework for the moment.");
|
||||
Object instance = injectDependencies(constructors[0], injector);
|
||||
|
||||
for(Method method : clazz.getDeclaredMethods()){
|
||||
Route route = method.getAnnotation(Route.class);
|
||||
if(route == null) continue;
|
||||
|
||||
this.mappers[route.type().ordinal()].register(instance, method, route);
|
||||
System.out.println("Registered route "+method+" ["+route.type()+" "+route.path()+"]");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Router<U> registerPackages(Object... injections){
|
||||
return registerPackages(new DependencyInjector().of(injections));
|
||||
}
|
||||
|
@ -131,16 +151,10 @@ public class Router<U extends User>{
|
|||
try{
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||
String line;
|
||||
Map<Class<?>, Object> cache = new HashMap<>();
|
||||
while((line = reader.readLine()) != null){
|
||||
if(line.endsWith(".class")){
|
||||
Class<?> clazz = Class.forName(name+"."+line.substring(0, line.lastIndexOf('.')));
|
||||
if(Response.class.isAssignableFrom(clazz)){
|
||||
if(clazz.equals(Response.class)) continue;
|
||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
||||
if(constructors.length != 1) continue;
|
||||
injectDependencies(constructors[0], cache, injector);
|
||||
}
|
||||
registerClass(clazz, injector);
|
||||
}else{
|
||||
registerPackages(name+"."+line, injector);
|
||||
}
|
||||
|
@ -153,24 +167,11 @@ public class Router<U extends User>{
|
|||
return this;
|
||||
}
|
||||
|
||||
private void injectDependencies(Constructor<?> constructor, Map<Class<?>, Object> cache, DependencyInjector injector){
|
||||
private Object injectDependencies(Constructor<?> constructor, DependencyInjector injector) throws Exception{
|
||||
Parameter[] parameters = constructor.getParameters();
|
||||
Object[] injections = new Object[parameters.length];
|
||||
for(int i = 0; i < parameters.length; i++){
|
||||
Parameter parameter = parameters[i];
|
||||
Class<?> type = parameter.getType();
|
||||
Object dependency = cache.get(type);
|
||||
if(dependency != null) injections[i] = dependency;
|
||||
else if((injections[i] = injector.applyDependency(constructor, parameter, cache)) == null) throw new IllegalArgumentException("No dependency for type "+type+" in constructor "+constructor);
|
||||
}
|
||||
try {
|
||||
Response response = (Response) constructor.newInstance(injections);
|
||||
register(response);
|
||||
System.out.println("registerd "+response.getClass());
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for(int i = 0; i < parameters.length; i++) injections[i] = injector.applyDependency(constructor, parameters[i]);
|
||||
return constructor.newInstance(injections);
|
||||
}
|
||||
|
||||
public Router<U> setDefault(Response response){
|
||||
|
|
Loading…
Add table
Reference in a new issue