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 Map<String, Object> map;
|
||||||
private List<BiFunction<Constructor<?>, Parameter, Object>> builders;
|
private List<BiFunction<Constructor<?>, Parameter, Object>> builders;
|
||||||
private Object[] injections;
|
private Object[] injections;
|
||||||
|
private Map<Class<?>, Object> cache;
|
||||||
|
|
||||||
public DependencyInjector(){
|
public DependencyInjector(){
|
||||||
this.map = new HashMap<>();
|
this.map = new HashMap<>();
|
||||||
this.builders = new ArrayList<>();
|
this.builders = new ArrayList<>();
|
||||||
|
this.cache = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DependencyInjector of(String name, Object value){
|
public DependencyInjector of(String name, Object value){
|
||||||
|
@ -41,7 +43,7 @@ public class DependencyInjector{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object applyDependency(Constructor<?> constructor, Parameter parameter, Map<Class<?>, Object> cache){
|
Object applyDependency(Constructor<?> constructor, Parameter parameter){
|
||||||
Injection annotation = parameter.getAnnotation(Injection.class);
|
Injection annotation = parameter.getAnnotation(Injection.class);
|
||||||
if(annotation != null){
|
if(annotation != null){
|
||||||
Object result = this.map.get(annotation.value());
|
Object result = this.map.get(annotation.value());
|
||||||
|
@ -52,8 +54,8 @@ public class DependencyInjector{
|
||||||
Object result = function.apply(constructor, parameter);
|
Object result = function.apply(constructor, parameter);
|
||||||
if(result != null) return result;
|
if(result != null) return result;
|
||||||
}
|
}
|
||||||
if(this.injections == null) return null;
|
|
||||||
Class<?> type = parameter.getType();
|
Class<?> type = parameter.getType();
|
||||||
|
if(this.injections == null) throw new IllegalArgumentException("No dependency for type "+type+" in constructor "+constructor);
|
||||||
Object result = null;
|
Object result = null;
|
||||||
for(Object injection : injections){
|
for(Object injection : injections){
|
||||||
if(type.isAssignableFrom(injection.getClass())){
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,73 +12,61 @@ public class RouteMapper<U extends User>{
|
||||||
|
|
||||||
private Router<U> router;
|
private Router<U> router;
|
||||||
|
|
||||||
private Response[] responses;
|
private RouteState[] states;
|
||||||
private Method[] methods;
|
|
||||||
private Route[] routes;
|
|
||||||
private Pattern[] patterns;
|
|
||||||
private int[] calls;
|
private int[] calls;
|
||||||
private int dif;
|
private int dif;
|
||||||
|
|
||||||
public RouteMapper(Router<U> router){
|
public RouteMapper(Router<U> router){
|
||||||
this.router = router;
|
this.router = router;
|
||||||
this.responses = new Response[0];
|
this.states = new RouteState[0];
|
||||||
this.methods = new Method[0];
|
|
||||||
this.routes = new Route[0];
|
|
||||||
this.patterns = new Pattern[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(Response response, Method method, Route route, Pattern pattern){
|
public void register(Object instance, Method method, Route route){
|
||||||
int length = responses.length+1;
|
int length = states.length+1;
|
||||||
this.responses = addElement(responses, new Response[length], response);
|
this.states = addElement(states, new RouteState[length], new RouteState(instance, method, route));
|
||||||
this.methods = addElement(methods, new Method[length], method);
|
|
||||||
this.routes = addElement(routes, new Route[length], route);
|
|
||||||
this.patterns = addElement(patterns, new Pattern[length], pattern);
|
|
||||||
if(this.calls != null) this.calls = new int[length];
|
if(this.calls != null) this.calls = new int[length];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void activeReOrdering(){
|
public void activeReOrdering(){
|
||||||
this.calls = new int[responses.length];
|
this.calls = new int[states.length];
|
||||||
this.dif = 2;
|
this.dif = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean exec(Context context, HttpReader reader, HttpWriter writer, List<RouteInterceptor> interceptors) throws Exception{
|
public boolean exec(Context context, HttpReader reader, HttpWriter writer, List<RouteInterceptor> interceptors) throws Exception{
|
||||||
Response response = null;
|
RouteState target = null;
|
||||||
Method method = null;
|
|
||||||
Matcher matcher = null;
|
Matcher matcher = null;
|
||||||
|
|
||||||
String path = context.getPath();
|
String path = context.getPath();
|
||||||
|
|
||||||
synchronized(responses){
|
synchronized(states){
|
||||||
for(int i = 0; i < responses.length; i++){
|
for(int i = 0; i < states.length; i++){
|
||||||
Route route = routes[i];
|
RouteState state = states[i];
|
||||||
Pattern pattern = patterns[i];
|
matcher = state.match(path);
|
||||||
matcher = pattern.matcher(path);
|
if(matcher != null){
|
||||||
if(matcher.matches()){
|
if(state.isWebSocket()){
|
||||||
if(route.websocket()){
|
|
||||||
switchToWebSocket(reader, writer);
|
switchToWebSocket(reader, writer);
|
||||||
reader = new WebSocketReader(reader);
|
reader = new WebSocketReader(reader);
|
||||||
writer = new WebSocketWriter(writer);
|
writer = new WebSocketWriter(writer);
|
||||||
if(route.needLogin()){
|
if(state.needLogin()){
|
||||||
String token = reader.<JsonMap>readJson().get("token");
|
String token = reader.<JsonMap>readJson().get("token");
|
||||||
context.setUser(this.router.getUser(token));
|
context.setUser(this.router.getUser(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if((!context.isLogged()) && route.needLogin()){
|
if((!context.isLogged()) && state.needLogin()){
|
||||||
writer.response(401, router.getDefaultHeaders(context.getType()));
|
writer.response(401, router.getDefaultHeaders(context.getType()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
response = responses[i];
|
target = state;
|
||||||
method = methods[i];
|
|
||||||
order(i);
|
order(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(response != null){
|
if(target != null){
|
||||||
for(RouteInterceptor interceptor : interceptors){
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -94,10 +82,7 @@ public class RouteMapper<U extends User>{
|
||||||
}
|
}
|
||||||
if(index < 1) return;
|
if(index < 1) return;
|
||||||
if(call > this.calls[index-1]){
|
if(call > this.calls[index-1]){
|
||||||
switchElement(responses, index, index-1);
|
switchElement(states, index, index-1);
|
||||||
switchElement(methods, index, index-1);
|
|
||||||
switchElement(routes, index, index-1);
|
|
||||||
switchElement(patterns, index, index-1);
|
|
||||||
|
|
||||||
this.calls[index] = this.calls[index-1];
|
this.calls[index] = this.calls[index-1];
|
||||||
this.calls[index-1] = call;
|
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());
|
Response.class.getDeclaredMethods()[0].getParameterTypes());
|
||||||
Route route = method.getAnnotation(Route.class);
|
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){
|
}catch(Exception e){
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
return this;
|
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){
|
public Router<U> registerPackages(Object... injections){
|
||||||
return registerPackages(new DependencyInjector().of(injections));
|
return registerPackages(new DependencyInjector().of(injections));
|
||||||
}
|
}
|
||||||
|
@ -131,16 +151,10 @@ public class Router<U extends User>{
|
||||||
try{
|
try{
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||||
String line;
|
String line;
|
||||||
Map<Class<?>, Object> cache = new HashMap<>();
|
|
||||||
while((line = reader.readLine()) != null){
|
while((line = reader.readLine()) != null){
|
||||||
if(line.endsWith(".class")){
|
if(line.endsWith(".class")){
|
||||||
Class<?> clazz = Class.forName(name+"."+line.substring(0, line.lastIndexOf('.')));
|
Class<?> clazz = Class.forName(name+"."+line.substring(0, line.lastIndexOf('.')));
|
||||||
if(Response.class.isAssignableFrom(clazz)){
|
registerClass(clazz, injector);
|
||||||
if(clazz.equals(Response.class)) continue;
|
|
||||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
|
||||||
if(constructors.length != 1) continue;
|
|
||||||
injectDependencies(constructors[0], cache, injector);
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
registerPackages(name+"."+line, injector);
|
registerPackages(name+"."+line, injector);
|
||||||
}
|
}
|
||||||
|
@ -153,24 +167,11 @@ public class Router<U extends User>{
|
||||||
return this;
|
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();
|
Parameter[] parameters = constructor.getParameters();
|
||||||
Object[] injections = new Object[parameters.length];
|
Object[] injections = new Object[parameters.length];
|
||||||
for(int i = 0; i < parameters.length; i++){
|
for(int i = 0; i < parameters.length; i++) injections[i] = injector.applyDependency(constructor, parameters[i]);
|
||||||
Parameter parameter = parameters[i];
|
return constructor.newInstance(injections);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Router<U> setDefault(Response response){
|
public Router<U> setDefault(Response response){
|
||||||
|
|
Loading…
Add table
Reference in a new issue