diff --git a/pom.xml b/pom.xml
index 39521da..668a742 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,9 +20,11 @@
17
24.0.1
5.9.2
+ 0.0.3
1.4.6
1.18.26
2.0.7
+ 2.3.5.Final
0.10.4
@@ -46,7 +48,7 @@
ch.fritteli.labyrinth
labyrinth-generator
- 0.0.3
+ ${labyrinth-generator.version}
io.vavr
@@ -73,7 +75,7 @@
io.undertow
undertow-core
- 2.3.5.Final
+ ${undertow.version}
org.junit.jupiter
diff --git a/src/main/java/ch/fritteli/labyrinth/server/Main.java b/src/main/java/ch/fritteli/labyrinth/server/Main.java
index d8c5bfa..9800d8c 100644
--- a/src/main/java/ch/fritteli/labyrinth/server/Main.java
+++ b/src/main/java/ch/fritteli/labyrinth/server/Main.java
@@ -1,9 +1,12 @@
package ch.fritteli.labyrinth.server;
+import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
@Slf4j
+@UtilityClass
public class Main {
+
public static void main(String[] args) {
LabyrinthServer.createAndStartServer()
.onFailure(e -> log.error("Failed to create server. Stopping.", e));
diff --git a/src/main/java/ch/fritteli/labyrinth/server/OutputType.java b/src/main/java/ch/fritteli/labyrinth/server/OutputType.java
index d40f668..4668bdd 100644
--- a/src/main/java/ch/fritteli/labyrinth/server/OutputType.java
+++ b/src/main/java/ch/fritteli/labyrinth/server/OutputType.java
@@ -88,7 +88,7 @@ public enum OutputType {
}
@NonNull
- public byte[] render(@NonNull final Labyrinth labyrinth) throws Exception {
+ public byte[] render(@NonNull final Labyrinth labyrinth) {
return this.render.apply(labyrinth);
}
}
diff --git a/src/main/java/ch/fritteli/labyrinth/server/handler/CreateHandler.java b/src/main/java/ch/fritteli/labyrinth/server/handler/CreateHandler.java
index c5a304a..c1578fd 100644
--- a/src/main/java/ch/fritteli/labyrinth/server/handler/CreateHandler.java
+++ b/src/main/java/ch/fritteli/labyrinth/server/handler/CreateHandler.java
@@ -6,33 +6,20 @@ import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.StatusCodes;
-import io.vavr.Tuple;
import io.vavr.Tuple2;
-import io.vavr.collection.HashMap;
-import io.vavr.collection.HashMultimap;
-import io.vavr.collection.HashSet;
-import io.vavr.collection.List;
-import io.vavr.collection.Multimap;
-import io.vavr.collection.Set;
-import io.vavr.collection.Stream;
-import io.vavr.control.Option;
import io.vavr.control.Try;
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.extern.slf4j.Slf4j;
-import org.jetbrains.annotations.Nullable;
-import org.slf4j.MDC;
-
import java.nio.ByteBuffer;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Deque;
import java.util.Map;
-import java.util.Random;
-import java.util.function.Function;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
@Slf4j
public class CreateHandler extends AbstractHttpHandler {
+
public static final String PATH_TEMPLATE = "/create/{output}";
@Override
@@ -77,89 +64,4 @@ public class CreateHandler extends AbstractHttpHandler {
private Try> createLabyrinthFromRequestParameters(final Map> queryParameters) {
return new ParametersToLabyrinthExtractor(queryParameters).createLabyrinth();
}
-
- private enum RequestParameter {
- WIDTH(p -> Try.of(() -> Integer.parseInt(p)).toOption(), "w", "width"),
- HEIGHT(p -> Try.of(() -> Integer.parseInt(p)).toOption(), "h", "height"),
- ID(p -> Try.of(() -> Long.parseLong(p)).toOption(), "i", "id"),
- OUTPUT(OutputType::ofString, "o", "output");
- @NonNull
- private final Function> extractor;
- @Getter
- @NonNull
- private final Set names;
-
- RequestParameter(@NonNull final String... names) {
- this.extractor = null;
- this.names = HashSet.of(names);
- }
-
- RequestParameter(@NonNull final Function> extractor, @NonNull final String... names) {
- this.extractor = extractor;
- this.names = HashSet.of(names);
- }
-
- static Option parseName(@Nullable final String name) {
- if (name == null) {
- return Option.none();
- }
- return Stream.of(values()).find(param -> param.names.exists(name::equalsIgnoreCase));
- }
-
- @NonNull Option extractParameterValue(@NonNull final String parameter) {
- return (Option) this.extractor.apply(parameter);
- }
- }
-
- private static class ParametersToLabyrinthExtractor {
- @NonNull
- private final Multimap queryParameters;
-
- ParametersToLabyrinthExtractor(@NonNull final Map> queryParameters) {
- this.queryParameters = HashMap.ofAll(queryParameters).foldLeft(HashMultimap.withSet().empty(), (map, tuple) -> {
- final String key = tuple._1();
- return Stream.ofAll(tuple._2()).foldLeft(map, (m, value) -> m.put(key, value));
- });
- }
-
- @NonNull
- Try> createLabyrinth() {
- final Option output = getParameterValue(RequestParameter.OUTPUT);
- final Option width = getParameterValue(RequestParameter.WIDTH);
- final Option height = getParameterValue(RequestParameter.HEIGHT);
- final Option id = getParameterValue(RequestParameter.ID);
-
- if (output.isEmpty()) {
- return Try.failure(new IllegalArgumentException("Path parameter %s is required and must be one of: %s".formatted(
- RequestParameter.OUTPUT.getNames().mkString("'", " / ", "'"),
- Stream.of(OutputType.values())
- .flatMap(OutputType::getNames)
- .mkString(", ")
- )));
- }
- if (width.isEmpty()) {
- return Try.failure(new IllegalArgumentException("Query parameter %s is required and must be a positive integer value".formatted(
- RequestParameter.WIDTH.getNames().mkString("'", " / ", "'")
- )));
- }
- if (height.isEmpty()) {
- return Try.failure(new IllegalArgumentException("Query parameter %s is required and must be a positive integer value".formatted(
- RequestParameter.HEIGHT.getNames().mkString("'", " / ", "'")
- )));
- }
-
- return Try.of(() -> Tuple.of(output.get(), new Labyrinth(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong()))));
- }
-
- @NonNull
- private Option getParameterValue(@NonNull final RequestParameter parameter) {
- return this.getParameterValues(parameter)
- .foldLeft(Option.none(), (type, param) -> type.orElse(() -> parameter.extractParameterValue(param)));
- }
-
- @NonNull
- private Stream getParameterValues(@NonNull final RequestParameter parameter) {
- return parameter.names.toStream().flatMap(name -> Stream.ofAll(this.queryParameters.getOrElse(name, List.empty())));
- }
- }
}
diff --git a/src/main/java/ch/fritteli/labyrinth/server/handler/ParametersToLabyrinthExtractor.java b/src/main/java/ch/fritteli/labyrinth/server/handler/ParametersToLabyrinthExtractor.java
new file mode 100644
index 0000000..b766b77
--- /dev/null
+++ b/src/main/java/ch/fritteli/labyrinth/server/handler/ParametersToLabyrinthExtractor.java
@@ -0,0 +1,111 @@
+package ch.fritteli.labyrinth.server.handler;
+
+import ch.fritteli.labyrinth.generator.model.Labyrinth;
+import ch.fritteli.labyrinth.server.OutputType;
+import io.vavr.Tuple;
+import io.vavr.Tuple2;
+import io.vavr.collection.HashMap;
+import io.vavr.collection.HashMultimap;
+import io.vavr.collection.HashSet;
+import io.vavr.collection.List;
+import io.vavr.collection.Multimap;
+import io.vavr.collection.Set;
+import io.vavr.collection.Stream;
+import io.vavr.control.Option;
+import io.vavr.control.Try;
+import java.util.Deque;
+import java.util.Map;
+import java.util.Random;
+import java.util.function.Function;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.Nullable;
+
+class ParametersToLabyrinthExtractor {
+
+ @NonNull
+ private final Multimap queryParameters;
+
+ ParametersToLabyrinthExtractor(@NonNull final Map> queryParameters) {
+ this.queryParameters = HashMap.ofAll(queryParameters)
+ .foldLeft(
+ HashMultimap.withSet().empty(),
+ (map, tuple) -> RequestParameter.parseName(tuple._1()).map(parameter -> Stream.ofAll(tuple._2())
+ .flatMap(parameter::extractParameterValue)
+ .foldLeft(map, (m, value) -> m.put(parameter, value)))
+ .getOrElse(map)
+ );
+ }
+
+ @NonNull
+ Try> createLabyrinth() {
+ final Option output = getParameterValue(RequestParameter.OUTPUT);
+ final Option width = getParameterValue(RequestParameter.WIDTH);
+ final Option height = getParameterValue(RequestParameter.HEIGHT);
+ final Option id = getParameterValue(RequestParameter.ID);
+
+ if (output.isEmpty()) {
+ return Try.failure(new IllegalArgumentException("Path parameter %s is required and must be one of: %s".formatted(
+ RequestParameter.OUTPUT.getNames().mkString("'", " / ", "'"),
+ Stream.of(OutputType.values())
+ .flatMap(OutputType::getNames)
+ .mkString(", ")
+ )));
+ }
+ if (width.isEmpty()) {
+ return Try.failure(new IllegalArgumentException("Query parameter %s is required and must be a positive integer value".formatted(
+ RequestParameter.WIDTH.getNames().mkString("'", " / ", "'")
+ )));
+ }
+ if (height.isEmpty()) {
+ return Try.failure(new IllegalArgumentException("Query parameter %s is required and must be a positive integer value".formatted(
+ RequestParameter.HEIGHT.getNames().mkString("'", " / ", "'")
+ )));
+ }
+
+ return Try.of(() -> Tuple.of(output.get(), new Labyrinth(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong()))));
+ }
+
+ @NonNull
+ private Option getParameterValue(@NonNull final RequestParameter parameter) {
+ return (Option) this.queryParameters.getOrElse(parameter, List.empty())
+ .headOption();
+ }
+
+ @Slf4j
+ private enum RequestParameter {
+ WIDTH(p -> Try.of(() -> Integer.parseInt(p))
+ .toOption()
+ .onEmpty(() -> log.debug("Unparseable value for parameter 'width': '{}'", p)), "w", "width"),
+ HEIGHT(p -> Try.of(() -> Integer.parseInt(p))
+ .toOption()
+ .onEmpty(() -> log.debug("Unparseable value for parameter 'height': '{}'", p)), "h", "height"),
+ ID(p -> Try.of(() -> Long.parseLong(p))
+ .toOption()
+ .onEmpty(() -> log.debug("Unparseable value for parameter 'id': '{}'", p)), "i", "id"),
+ OUTPUT(p -> OutputType.ofString(p)
+ .onEmpty(() -> log.debug("Unparseable value for parameter 'output': '{}'", p)), "o", "output");
+ @NonNull
+ private final Function> extractor;
+ @Getter
+ @NonNull
+ private final Set names;
+
+ RequestParameter(@NonNull final Function> extractor, @NonNull final String... names) {
+ this.extractor = extractor;
+ this.names = HashSet.of(names);
+ }
+
+ static Option parseName(@Nullable final String name) {
+ if (name == null) {
+ return Option.none();
+ }
+ return Stream.of(values()).find(param -> param.names.exists(name::equalsIgnoreCase));
+ }
+
+ @NonNull Option> extractParameterValue(@NonNull final String parameter) {
+ return this.extractor.apply(parameter);
+ }
+ }
+}