234 lines
No EOL
7.1 KiB
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();
|
|
}
|
|
}
|
|
|
|
} |