diff --git a/src/dev/peerat/framework/DependencyInjector.java b/src/dev/peerat/framework/DependencyInjector.java index 4f64c18..9aa6f5d 100644 --- a/src/dev/peerat/framework/DependencyInjector.java +++ b/src/dev/peerat/framework/DependencyInjector.java @@ -13,10 +13,12 @@ public class DependencyInjector{ private Map map; private List, Parameter, Object>> builders; private Object[] injections; + private Map, 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, 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; } } \ No newline at end of file diff --git a/src/dev/peerat/framework/RouteMapper.java b/src/dev/peerat/framework/RouteMapper.java index 84c526f..9939374 100644 --- a/src/dev/peerat/framework/RouteMapper.java +++ b/src/dev/peerat/framework/RouteMapper.java @@ -12,73 +12,61 @@ public class RouteMapper{ private Router 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 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 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.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{ } 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; diff --git a/src/dev/peerat/framework/RouteState.java b/src/dev/peerat/framework/RouteState.java new file mode 100644 index 0000000..a20e8a5 --- /dev/null +++ b/src/dev/peerat/framework/RouteState.java @@ -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; + } + +} diff --git a/src/dev/peerat/framework/Router.java b/src/dev/peerat/framework/Router.java index 203c9e6..17c65c0 100644 --- a/src/dev/peerat/framework/Router.java +++ b/src/dev/peerat/framework/Router.java @@ -105,13 +105,33 @@ public class Router{ 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 registerClass(Class clazz, Object... injections) throws Exception{ + return registerClass(clazz, new DependencyInjector().of(injections)); + } + + public Router 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 registerPackages(Object... injections){ return registerPackages(new DependencyInjector().of(injections)); } @@ -131,16 +151,10 @@ public class Router{ try{ BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); String line; - Map, 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{ return this; } - private void injectDependencies(Constructor constructor, Map, 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 setDefault(Response response){