REST resolve
~4.5h work
This commit is contained in:
parent
765af93728
commit
2444a071ac
@ -1,3 +1,5 @@
|
||||
import at.nanopenguin.mtcg.application.TestService;
|
||||
import at.nanopenguin.mtcg.http.HttpMethod;
|
||||
import at.nanopenguin.mtcg.http.Router;
|
||||
import at.nanopenguin.mtcg.http.Server;
|
||||
|
||||
@ -5,8 +7,10 @@ import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("Hello world!");
|
||||
Server server = new Server(10001, 10, new Router());
|
||||
Router router = new Router();
|
||||
router.addRoute(HttpMethod.GET, "/test/{var}/service", new TestService(), 1);
|
||||
|
||||
Server server = new Server(10001, 10, router);
|
||||
server.start();
|
||||
}
|
||||
}
|
||||
11
src/at/nanopenguin/mtcg/application/Service.java
Normal file
11
src/at/nanopenguin/mtcg/application/Service.java
Normal file
@ -0,0 +1,11 @@
|
||||
package at.nanopenguin.mtcg.application;
|
||||
|
||||
import at.nanopenguin.mtcg.http.Response;
|
||||
|
||||
public interface Service {
|
||||
String pathVariable = null;
|
||||
|
||||
void setPathVariable(String var);
|
||||
|
||||
Response handleRequest(String request);
|
||||
}
|
||||
18
src/at/nanopenguin/mtcg/application/TestService.java
Normal file
18
src/at/nanopenguin/mtcg/application/TestService.java
Normal file
@ -0,0 +1,18 @@
|
||||
package at.nanopenguin.mtcg.application;
|
||||
|
||||
import at.nanopenguin.mtcg.http.HttpStatus;
|
||||
import at.nanopenguin.mtcg.http.Response;
|
||||
|
||||
public class TestService implements Service {
|
||||
private String pathVariable = null;
|
||||
|
||||
@Override
|
||||
public void setPathVariable(String var) {
|
||||
this.pathVariable = var;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response handleRequest(String request) {
|
||||
return new Response(HttpStatus.OK, "application/json", "{\"var\":\"" + this.pathVariable + "\"]");
|
||||
}
|
||||
}
|
||||
18
src/at/nanopenguin/mtcg/http/HttpMethod.java
Normal file
18
src/at/nanopenguin/mtcg/http/HttpMethod.java
Normal file
@ -0,0 +1,18 @@
|
||||
package at.nanopenguin.mtcg.http;
|
||||
|
||||
public enum HttpMethod {
|
||||
GET,
|
||||
POST,
|
||||
DELETE,
|
||||
PUT;
|
||||
|
||||
public static HttpMethod strToMethod(String methodStr) {
|
||||
return switch (methodStr) {
|
||||
case "GET" -> HttpMethod.GET;
|
||||
case "POST" -> HttpMethod.POST;
|
||||
case "DELETE" -> HttpMethod.DELETE;
|
||||
case "PUT" -> HttpMethod.PUT;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
59
src/at/nanopenguin/mtcg/http/HttpRequest.java
Normal file
59
src/at/nanopenguin/mtcg/http/HttpRequest.java
Normal file
@ -0,0 +1,59 @@
|
||||
package at.nanopenguin.mtcg.http;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpRequest {
|
||||
private final HttpMethod method;
|
||||
private final String path;
|
||||
private final String version;
|
||||
private Map<String, String> httpHeaders = new HashMap<String, String>();
|
||||
private final String body;
|
||||
|
||||
public HttpRequest(BufferedReader br) throws IOException {
|
||||
String line = br.readLine();
|
||||
|
||||
if (line != null) {
|
||||
String[] requestLine = line.split(" ");
|
||||
this.method = HttpMethod.strToMethod(requestLine[0]);
|
||||
this.path = requestLine[1];
|
||||
this.version = requestLine[2];
|
||||
|
||||
for (line = br.readLine(); !line.isEmpty(); line = br.readLine()) {
|
||||
String[] headerEntry = line.split(": ", 2);
|
||||
this.httpHeaders.put(headerEntry[0], headerEntry[1]);
|
||||
}
|
||||
|
||||
this.body = this.httpHeaders.containsKey("Content-Length") ? new String(new char[Integer.parseInt(this.httpHeaders.get("Content-Length"))]) : null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.method = null;
|
||||
this.path = null;
|
||||
this.version = null;
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
public HttpMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getHttpHeader(String header) {
|
||||
return httpHeaders.get(header);
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
@ -1,15 +1,16 @@
|
||||
package at.nanopenguin.mtcg.http;
|
||||
|
||||
import at.nanopenguin.mtcg.application.Service;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
public class RequestHandler implements Runnable {
|
||||
private final Socket serviceSocket;
|
||||
private final Router router;
|
||||
private BufferedReader br;
|
||||
private OutputStream out;
|
||||
|
||||
public RequestHandler(Socket serviceSocket, Router router) {
|
||||
this.serviceSocket = serviceSocket;
|
||||
@ -19,11 +20,36 @@ public class RequestHandler implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Response response = new Response(HttpStatus.OK, "application/json", "[]");
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(serviceSocket.getInputStream()));
|
||||
|
||||
this.out = this.serviceSocket.getOutputStream();
|
||||
System.out.println("creating httpRequest");
|
||||
HttpRequest httpRequest = new HttpRequest(br);
|
||||
|
||||
Response response;
|
||||
responseBuilder: {
|
||||
if (httpRequest.getMethod() == null) {
|
||||
System.out.println("generic error");
|
||||
response = new Response(HttpStatus.INTERNAL, "text/plain", "");
|
||||
break responseBuilder;
|
||||
}
|
||||
|
||||
System.out.println("getting service");
|
||||
Service service = router.resolveRoute(httpRequest.getMethod(), httpRequest.getPath());
|
||||
|
||||
if (service == null) {
|
||||
System.out.println("service does not exist");
|
||||
response = new Response(HttpStatus.NOT_IMPLEMENTED, "text/plain", "");
|
||||
break responseBuilder;
|
||||
}
|
||||
System.out.println("creating response");
|
||||
response = service.handleRequest(httpRequest.getBody());
|
||||
}
|
||||
|
||||
OutputStream out = this.serviceSocket.getOutputStream();
|
||||
out.write(response.get().getBytes());
|
||||
out.flush();
|
||||
|
||||
System.out.println("request done");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
13
src/at/nanopenguin/mtcg/http/Route.java
Normal file
13
src/at/nanopenguin/mtcg/http/Route.java
Normal file
@ -0,0 +1,13 @@
|
||||
package at.nanopenguin.mtcg.http;
|
||||
|
||||
import at.nanopenguin.mtcg.application.Service;
|
||||
|
||||
public class Route {
|
||||
public final Service service;
|
||||
public final boolean hasPathVariable;
|
||||
|
||||
public Route(Service service, boolean hasPathVariable) {
|
||||
this.service = service;
|
||||
this.hasPathVariable = hasPathVariable;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,56 @@
|
||||
package at.nanopenguin.mtcg.http;
|
||||
|
||||
import at.nanopenguin.mtcg.application.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Router {
|
||||
private Map<HttpMethod, Map<String, Route>> routeMap = new HashMap<>();
|
||||
|
||||
public void addRoute(final HttpMethod method, final String route, final Service service, final int pathVarPos) {
|
||||
Map<String, Route> map = this.routeMap.get(method);
|
||||
if (method != null && map == null) {
|
||||
this.routeMap.put(method, (map = new HashMap<>()));
|
||||
}
|
||||
|
||||
List<String> routeComponents = new ArrayList<String>(Arrays.asList(route.split("/")));
|
||||
routeComponents.remove(0);
|
||||
routeComponents.set(pathVarPos, "{var}");
|
||||
|
||||
for (int i = 0; i < routeComponents.size(); i++) {
|
||||
Route routeComponent = new Route(i == routeComponents.size() - 1 ? service : null, i == pathVarPos - 1);
|
||||
String path = String.join("/", routeComponents.subList(0, i+1));
|
||||
map.put(path, routeComponent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Service resolveRoute(final HttpMethod method, final String route) {
|
||||
System.out.println("resolving route " + route);
|
||||
String[] routeComponents = route.split("/");
|
||||
Route component = this.routeMap.get(method).get(routeComponents[1]);
|
||||
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String pathVariable = null;
|
||||
|
||||
int i = 1;
|
||||
System.out.println(routeComponents[i]);
|
||||
for (String search = routeComponents[i]; component.service == null; component = this.routeMap.get(method).get(search = String.join("/", search, routeComponents[++i]))) {
|
||||
System.out.println(String.join("/", search, routeComponents[i+1]));
|
||||
if (component.hasPathVariable) {
|
||||
pathVariable = routeComponents[++i];
|
||||
search = String.join("/", search, "{var}");
|
||||
System.out.println(search + " - " + routeComponents[i+1]);
|
||||
System.out.println(this.routeMap.get(HttpMethod.GET).containsKey("test/{var}"));
|
||||
}
|
||||
}
|
||||
|
||||
component.service.setPathVariable(pathVariable);
|
||||
return component.service;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ public class Server {
|
||||
final Socket serviceSocket = listener.accept();
|
||||
final RequestHandler requestHandler = new RequestHandler(serviceSocket, this.router);
|
||||
|
||||
System.out.println("received request");
|
||||
executorService.submit(requestHandler);
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user