peer-at-code-framework/src/dev/peerat/framework/Router.java

234 lines
No EOL
7.1 KiB
Java

package dev.peerat.framework;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import dev.peerat.framework.auth.Authenticator;
public class Router<U extends User>{
public static void main(String[] args) throws Exception{}
private Locker<Context> logger;
private Locker<Throwable> exceptions;
private RouteMapper<U>[] mappers;
private List<RouteInterceptor> interceptors;
private Response noFileFound;
private Authenticator<U> auth;
private String[][] headers;
private ServerSocket serverSocket;
public Router(){
this.logger = new Locker<>();
this.exceptions = new Locker<>();
int types = RequestType.values().length;
this.mappers = new RouteMapper[types];
this.interceptors = new ArrayList<>();
for(RequestType type : RequestType.values()) this.mappers[type.ordinal()] = new RouteMapper<>(this);
this.headers = new String[types][0];
}
public Router<U> setAuthenticator(Authenticator<U> auth){
this.auth = auth;
return this;
}
public Router<U> addDefaultHeaders(RequestType type, String... headers){
String[] origin = this.headers[type.ordinal()];
String[] copy = new String[origin.length+headers.length];
System.arraycopy(origin, 0, copy, 0, origin.length);
System.arraycopy(headers, 0, copy, origin.length, headers.length);
this.headers[type.ordinal()] = copy;
return this;
}
public Router<U> register(Response response){
try{
Method method = response.getClass().getDeclaredMethod("exec",
Response.class.getDeclaredMethods()[0].getParameterTypes());
Route route = method.getAnnotation(Route.class);
this.mappers[route.type().ordinal()].register(response, method, route);
System.out.println("Registered route "+method+" ["+route.type()+" "+route.path()+"]");
}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{
Object instance = null;
for(Method method : clazz.getDeclaredMethods()){
Route route = method.getAnnotation(Route.class);
if(route == null) continue;
if(instance == null){
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
if(constructors.length != 1) throw new IllegalArgumentException("Class with multiple constructor. Not supported by this framework for the moment.");
instance = constructors[0].newInstance(injector.apply(constructors[0]));
}
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));
}
public Router<U> registerPackages(DependencyInjector injector){
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
if(clazz.startsWith("dev.peerat.framework")) clazz = Thread.currentThread().getStackTrace()[3].getClassName();
String pack = clazz.substring(0, clazz.lastIndexOf('.'));
return registerPackages(pack, injector);
}
public Router<U> registerPackages(String name, Object... injections){
return registerPackages(name, new DependencyInjector().of(injections));
}
public Router<U> registerPackages(String name, DependencyInjector injector){
InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream(name.replace(".", "/"));
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
while((line = reader.readLine()) != null){
if(line.endsWith(".class")){
Class<?> clazz = Class.forName(name+"."+line.substring(0, line.length()-6));
registerClass(clazz, injector);
continue;
}
if(!line.contains(".")) registerPackages(name+"."+line, injector);
}
reader.close();
}catch(Exception e){
System.err.println("Failed to read "+name);
e.printStackTrace();
}
return this;
}
public Router<U> setDefault(Response response){
this.noFileFound = response;
return this;
}
public Router<U> addInterceptor(RouteInterceptor interceptor){
this.interceptors.add(interceptor);
return this;
}
public Router<U> bind(RouteFilter filter, Class<?>... types){
for(RouteMapper<U> mapper : this.mappers) mapper.bind(filter, types);
return this;
}
private void bindAll(){
for(RouteMapper<U> mapper : this.mappers) mapper.bindAll();
}
public Router<U> activeReOrdering(){
for(RouteMapper<?> mapper : this.mappers) mapper.activeReOrdering();
return this;
}
String[] getDefaultHeaders(RequestType type){
return this.headers[type.ordinal()];
}
public Authenticator<U> getAuthenticator(){
return this.auth;
}
void exec(Context context, HttpReader reader, HttpWriter writer) throws Exception{
if(this.mappers[context.getType().ordinal()].exec(context, reader, writer, this.interceptors)) return;
if(noFileFound != null) noFileFound.exec(null, context, reader, writer);
}
public Router<U> configureSSL(String keyStore, String keyStorePassword){
System.setProperty("javax.net.ssl.keyStore", keyStore);
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);
return this;
}
public U getUser(RequestType type, HttpReader reader) throws Exception{
return this.auth != null ? this.auth.getUser(type, reader) : null;
}
public U getUser(String data) throws Exception{
return this.auth != null ? this.auth.getUser(data) : null;
}
public String createAuthUser(U user) throws Exception{
return this.auth.createAuthUser(user);
}
public Locker<Context> getLogger(){
return this.logger;
}
public Locker<Throwable> getExceptionLogger(){
return this.exceptions;
}
public void listen(int port, boolean ssl) throws Exception{
bindAll();
if (ssl) { // Not needed with the use of a proxy
try {
SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
serverSocket = (SSLServerSocket) ssf.createServerSocket(port);
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
Client<U> client = new Client<>(socket, this);
client.start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stop();
}
} else {
try{
serverSocket = new ServerSocket(port);
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
Client<U> client = new Client<>(socket, this);
client.start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stop();
}
}
}
public void stop(){
if(serverSocket == null) return;
try {
serverSocket.close();
serverSocket = null;
}catch(Exception e){
e.printStackTrace();
}
}
}