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.Router;
|
||||||
import at.nanopenguin.mtcg.http.Server;
|
import at.nanopenguin.mtcg.http.Server;
|
||||||
|
|
||||||
@ -5,8 +7,10 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
System.out.println("Hello world!");
|
Router router = new Router();
|
||||||
Server server = new Server(10001, 10, new Router());
|
router.addRoute(HttpMethod.GET, "/test/{var}/service", new TestService(), 1);
|
||||||
|
|
||||||
|
Server server = new Server(10001, 10, router);
|
||||||
server.start();
|
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;
|
package at.nanopenguin.mtcg.http;
|
||||||
|
|
||||||
|
import at.nanopenguin.mtcg.application.Service;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
public class RequestHandler implements Runnable {
|
public class RequestHandler implements Runnable {
|
||||||
private final Socket serviceSocket;
|
private final Socket serviceSocket;
|
||||||
private final Router router;
|
private final Router router;
|
||||||
private BufferedReader br;
|
|
||||||
private OutputStream out;
|
|
||||||
|
|
||||||
public RequestHandler(Socket serviceSocket, Router router) {
|
public RequestHandler(Socket serviceSocket, Router router) {
|
||||||
this.serviceSocket = serviceSocket;
|
this.serviceSocket = serviceSocket;
|
||||||
@ -19,11 +20,36 @@ public class RequestHandler implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
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.write(response.get().getBytes());
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
||||||
|
System.out.println("request done");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(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;
|
package at.nanopenguin.mtcg.http;
|
||||||
|
|
||||||
|
import at.nanopenguin.mtcg.application.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public class Router {
|
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 Socket serviceSocket = listener.accept();
|
||||||
final RequestHandler requestHandler = new RequestHandler(serviceSocket, this.router);
|
final RequestHandler requestHandler = new RequestHandler(serviceSocket, this.router);
|
||||||
|
|
||||||
|
System.out.println("received request");
|
||||||
executorService.submit(requestHandler);
|
executorService.submit(requestHandler);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user