Compare commits

..

13 commits
master ... main

Author SHA1 Message Date
4e1ccfeead
[maven-release-plugin] prepare for next development iteration
Some checks failed
continuous-integration/drone/push Build is failing
2026-01-24 04:43:41 +01:00
a115fae3ab
[maven-release-plugin] prepare release v0.3.0
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/tag Build is passing
2026-01-24 04:43:37 +01:00
e5823a9408
PDF output: Always generate an A4 page.
Some checks failed
continuous-integration/drone/push Build is failing
2026-01-24 04:42:51 +01:00
123ff8ec9f
use tag "latest-snapshot" for dev builds (docker image)
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-24 01:45:49 +01:00
2cdf51e996
[maven-release-plugin] prepare for next development iteration
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-24 01:43:03 +01:00
6fcdc62d9e
[maven-release-plugin] prepare release v0.2.1
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
2026-01-24 01:43:00 +01:00
1ee2b68471
Make copying resources to the doecker image more robust.
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-24 01:40:07 +01:00
287b70513a
Merge branch 'feature/fiddle-with-docker'
Some checks failed
continuous-integration/drone/push Build is failing
2026-01-24 01:34:41 +01:00
707acbefd9
Plural ...
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-24 01:34:00 +01:00
18a68cae2e
Conditions?
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-24 01:32:31 +01:00
9b0c25fb8f
Try and fix docker build
Some checks failed
continuous-integration/drone/push Build is failing
2026-01-24 01:29:22 +01:00
e945a12a6e
Switch to main branch and use Java25 as build image; also use Java25b as base docker image.
Some checks failed
continuous-integration/drone/push Build is failing
2026-01-24 00:13:36 +01:00
100e2aec8c
Update tons of dependencies.
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-23 23:59:15 +01:00
18 changed files with 131 additions and 131 deletions

View file

@ -3,39 +3,39 @@ type: docker
name: default name: default
steps: steps:
- name: build - name: build
image: maven:3.9-eclipse-temurin-21 image: maven:3.9-eclipse-temurin-25
commands: commands:
- mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true -B -V - mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
when: when:
ref: ref:
include: include:
- refs/head/master - refs/heads/main
- refs/head/feature/** - refs/heads/feature/**
- refs/tags/** - refs/tags/**
- name: test - name: test
image: maven:3.9-eclipse-temurin-21 image: maven:3.9-eclipse-temurin-25
commands: commands:
- mvn test -B - mvn test -B
when: when:
branch: branch:
include: include:
- master - main
- feature/* - feature/*
- name: deploy # - name: deploy
image: maven:3.9-eclipse-temurin-21 # image: maven:3.9-eclipse-temurin-25
environment: # environment:
REPO_TOKEN: # REPO_TOKEN:
from_secret: repo-token # from_secret: repo-token
REPO_TOKEN_OSSRH: # REPO_TOKEN_OSSRH:
from_secret: repo-token-ossrh # from_secret: repo-token-ossrh
commands: # commands:
- mvn -s maven-settings.xml deploy -DskipTests=true # - mvn -s maven-settings.xml deploy -DskipTests=true
when: # when:
branch: # branch:
- master # - main
event: # event:
exclude: # exclude:
- pull_request # - pull_request
- name: build_docker_image - name: build_docker_image
image: plugins/docker image: plugins/docker
settings: settings:
@ -45,11 +45,11 @@ steps:
from_secret: docker-token from_secret: docker-token
repo: gittr.ch/java/a-maze-r repo: gittr.ch/java/a-maze-r
tags: tags:
- latest - latest-snapshot
dockerfile: docker/Dockerfile dockerfile: docker/Dockerfile
when: when:
branch: branch:
- master - main
event: event:
exclude: exclude:
- pull_request - pull_request

View file

@ -1,8 +1,6 @@
FROM eclipse-temurin:21-jre FROM eclipse-temurin:25-jre-alpine
COPY target/maze-server-*.jar /app/ COPY target/maze-server-shaded.jar /app/app.jar
RUN rm /app/*-sources.jar
RUN mv /app/*.jar /app/app.jar
CMD java \ CMD java \
-Dfritteli.maze.server.host=0.0.0.0 \ -Dfritteli.maze.server.host=0.0.0.0 \

17
pom.xml
View file

@ -5,13 +5,14 @@
<parent> <parent>
<groupId>ch.fritteli</groupId> <groupId>ch.fritteli</groupId>
<artifactId>fritteli-build-parent</artifactId> <artifactId>fritteli-build-parent</artifactId>
<version>5.1.0</version> <version>6.1.0</version>
</parent> </parent>
<groupId>ch.fritteli.a-maze-r</groupId> <groupId>ch.fritteli.a-maze-r</groupId>
<artifactId>maze-server</artifactId> <artifactId>maze-server</artifactId>
<version>0.2.1-SNAPSHOT</version> <version>0.3.1-SNAPSHOT</version>
<name>A-Maze-R Server</name>
<description>The A-Maze-R server, offering a REST endpoint to access the Maze Generator.</description> <description>The A-Maze-R server, offering a REST endpoint to access the Maze Generator.</description>
<url>https://manuel.friedli.info/maze.html</url> <url>https://manuel.friedli.info/maze.html</url>
<inceptionYear>2022</inceptionYear> <inceptionYear>2022</inceptionYear>
@ -55,9 +56,9 @@
</distributionManagement> </distributionManagement>
<properties> <properties>
<maze-generator.version>0.3.0</maze-generator.version> <maze-generator.version>0.5.0</maze-generator.version>
<maven-site-plugin.version>4.0.0-M8</maven-site-plugin.version> <maven-site-plugin.version>4.0.0-M16</maven-site-plugin.version>
<undertow.version>2.3.18.Final</undertow.version> <undertow.version>2.3.22.Final</undertow.version>
</properties> </properties>
<dependencies> <dependencies>
@ -75,8 +76,8 @@
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jetbrains</groupId> <groupId>org.jspecify</groupId>
<artifactId>annotations</artifactId> <artifactId>jspecify</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
@ -98,7 +99,6 @@
<dependency> <dependency>
<groupId>org.assertj</groupId> <groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId> <artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -121,6 +121,7 @@
</excludes> </excludes>
</filter> </filter>
</filters> </filters>
<finalName>maze-server-shaded</finalName>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>

View file

@ -8,8 +8,8 @@ import io.vavr.collection.List;
import io.vavr.collection.Stream; import io.vavr.collection.Stream;
import io.vavr.control.Option; import io.vavr.control.Option;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.function.Function; import java.util.function.Function;
@ -17,20 +17,20 @@ public enum Algorithm {
RANDOM_DEPTH_FIRST(RandomDepthFirst::new, "random", "random-depth-first"), RANDOM_DEPTH_FIRST(RandomDepthFirst::new, "random", "random-depth-first"),
WILSON(Wilson::new, "wilson"); WILSON(Wilson::new, "wilson");
@NotNull @NonNull
private final Function<Maze, MazeGeneratorAlgorithm> creator; private final Function<Maze, MazeGeneratorAlgorithm> creator;
@Getter @Getter
@NotNull @NonNull
private final List<String> names; private final List<String> names;
Algorithm(@NotNull final Function<Maze, MazeGeneratorAlgorithm> creator, Algorithm(@NonNull final Function<Maze, MazeGeneratorAlgorithm> creator,
@NotNull final String... names) { @NonNull final String... names) {
this.creator = creator; this.creator = creator;
this.names = List.of(names); this.names = List.of(names);
} }
@NotNull @NonNull
public static Option<Algorithm> ofString(@Nullable final String name) { public static Option<Algorithm> ofString(@Nullable final String name) {
return Option.of(name) return Option.of(name)
.map(String::toLowerCase) .map(String::toLowerCase)
@ -38,8 +38,8 @@ public enum Algorithm {
.find(algorithm -> algorithm.getNames().contains(nameLC))); .find(algorithm -> algorithm.getNames().contains(nameLC)));
} }
@NotNull @NonNull
public MazeGeneratorAlgorithm createAlgorithm(@NotNull final Maze maze) { public MazeGeneratorAlgorithm createAlgorithm(@NonNull final Maze maze) {
return this.creator.apply(maze); return this.creator.apply(maze);
} }
} }

View file

@ -1,6 +1,6 @@
package ch.fritteli.maze.server; package ch.fritteli.maze.server;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
public class ConfigurationException extends RuntimeException { public class ConfigurationException extends RuntimeException {
public ConfigurationException(@Nullable final String message) { public ConfigurationException(@Nullable final String message) {

View file

@ -1,9 +1,9 @@
package ch.fritteli.maze.server; package ch.fritteli.maze.server;
import org.wildfly.common.annotation.NotNull; import org.jspecify.annotations.NonNull;
public class InvalidRequestParameterException extends RuntimeException { public class InvalidRequestParameterException extends RuntimeException {
public InvalidRequestParameterException(@NotNull final String s) { public InvalidRequestParameterException(@NonNull final String s) {
super(s); super(s);
} }
} }

View file

@ -7,7 +7,7 @@ import lombok.extern.slf4j.Slf4j;
@UtilityClass @UtilityClass
public class Main { public class Main {
public static void main(String[] args) { static void main() {
MazeServer.createAndStartServer() MazeServer.createAndStartServer()
.onFailure(e -> log.error("Failed to create server. Stopping.", e)); .onFailure(e -> log.error("Failed to create server. Stopping.", e));
} }

View file

@ -9,17 +9,17 @@ import io.undertow.Undertow;
import io.undertow.server.RoutingHandler; import io.undertow.server.RoutingHandler;
import io.vavr.control.Try; import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.wildfly.common.annotation.NotNull; import org.jspecify.annotations.NonNull;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@Slf4j @Slf4j
public class MazeServer { public class MazeServer {
@NotNull @NonNull
private final Undertow undertow; private final Undertow undertow;
private MazeServer(@NotNull final ServerConfig config) { private MazeServer(@NonNull final ServerConfig config) {
final String hostAddress = config.address().getHostAddress(); final String hostAddress = config.address().getHostAddress();
final int port = config.port(); final int port = config.port();
log.info("Starting Server at http://{}:{}/", hostAddress, port); log.info("Starting Server at http://{}:{}/", hostAddress, port);
@ -36,14 +36,14 @@ public class MazeServer {
.build(); .build();
} }
@NotNull @NonNull
public static Try<MazeServer> createAndStartServer() { public static Try<MazeServer> createAndStartServer() {
return Try.of(ServerConfig::init) return Try.of(ServerConfig::init)
.flatMapTry(MazeServer::createAndStartServer); .flatMapTry(MazeServer::createAndStartServer);
} }
@NotNull @NonNull
public static Try<MazeServer> createAndStartServer(@NotNull final ServerConfig config) { public static Try<MazeServer> createAndStartServer(@NonNull final ServerConfig config) {
return Try.of(() -> new MazeServer(config)) return Try.of(() -> new MazeServer(config))
.peek(MazeServer::start); .peek(MazeServer::start);
} }

View file

@ -12,8 +12,8 @@ import io.vavr.collection.List;
import io.vavr.collection.Stream; import io.vavr.collection.Stream;
import io.vavr.control.Option; import io.vavr.control.Option;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.function.Function; import java.util.function.Function;
@ -75,24 +75,24 @@ public enum OutputType {
"3", "3",
"binaryv3"); "binaryv3");
@Getter @Getter
@NotNull @NonNull
private final String contentType; private final String contentType;
@Getter @Getter
@NotNull @NonNull
private final String fileExtension; private final String fileExtension;
@NotNull @NonNull
private final Function<Maze, byte[]> render; private final Function<@NonNull Maze, byte @NonNull []> render;
@Getter @Getter
private final boolean attachment; private final boolean attachment;
@Getter @Getter
@NotNull @NonNull
private final List<String> names; private final List<String> names;
OutputType(@NotNull final String contentType, OutputType(@NonNull final String contentType,
@NotNull final String fileExtension, @NonNull final String fileExtension,
@NotNull final Function<Maze, byte[]> render, @NonNull final Function<Maze, byte[]> render,
final boolean attachment, final boolean attachment,
@NotNull final String... names) { @NonNull final String... names) {
this.contentType = contentType; this.contentType = contentType;
this.render = render; this.render = render;
this.fileExtension = fileExtension; this.fileExtension = fileExtension;
@ -100,7 +100,7 @@ public enum OutputType {
this.names = List.of(names); this.names = List.of(names);
} }
@NotNull @NonNull
public static Option<OutputType> ofString(@Nullable final String name) { public static Option<OutputType> ofString(@Nullable final String name) {
return Option.of(name) return Option.of(name)
.map(String::toLowerCase) .map(String::toLowerCase)
@ -109,14 +109,14 @@ public enum OutputType {
} }
@NotNull @NonNull
@Override @Override
public String toString() { public String toString() {
return this.names.last(); return this.names.last();
} }
@NotNull @NonNull
public byte[] render(@NotNull final Maze maze) { public byte[] render(@NonNull final Maze maze) {
return this.render.apply(maze); return this.render.apply(maze);
} }
} }

View file

@ -3,25 +3,25 @@ package ch.fritteli.maze.server;
import io.vavr.control.Option; import io.vavr.control.Option;
import io.vavr.control.Try; import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.net.InetAddress; import java.net.InetAddress;
@Slf4j @Slf4j
public record ServerConfig(@NotNull InetAddress address, public record ServerConfig(@NonNull InetAddress address,
int port, int port,
@NotNull Option<Integer> maxMazeHeight, @NonNull Option<Integer> maxMazeHeight,
@NotNull Option<Integer> maxMazeWidth) { @NonNull Option<Integer> maxMazeWidth) {
public static final String SYSPROP_HOST = "fritteli.maze.server.host"; public static final String SYSPROP_HOST = "fritteli.maze.server.host";
public static final String SYSPROP_PORT = "fritteli.maze.server.port"; public static final String SYSPROP_PORT = "fritteli.maze.server.port";
public static final String SYSPROP_MAX_MAZE_HEIGHT = "fritteli.maze.maxheight"; public static final String SYSPROP_MAX_MAZE_HEIGHT = "fritteli.maze.maxheight";
public static final String SYSPROP_MAX_MAZE_WIDTH = "fritteli.maze.maxwidth"; public static final String SYSPROP_MAX_MAZE_WIDTH = "fritteli.maze.maxwidth";
public ServerConfig(@NotNull final InetAddress address, public ServerConfig(@NonNull final InetAddress address,
final int port, final int port,
@NotNull final Option<Integer> maxMazeHeight, @NonNull final Option<Integer> maxMazeHeight,
@NotNull final Option<Integer> maxMazeWidth) { @NonNull final Option<Integer> maxMazeWidth) {
this.address = address; this.address = address;
this.port = validatePort(port); this.port = validatePort(port);
this.maxMazeHeight = validateDimension(maxMazeHeight, "height"); this.maxMazeHeight = validateDimension(maxMazeHeight, "height");
@ -31,13 +31,13 @@ public record ServerConfig(@NotNull InetAddress address,
public ServerConfig(@Nullable final String address, public ServerConfig(@Nullable final String address,
final int port, final int port,
@NotNull final Option<Integer> maxMazeHeight, @NonNull final Option<Integer> maxMazeHeight,
@NotNull final Option<Integer> maxMazeWidth) @NonNull final Option<Integer> maxMazeWidth)
throws ConfigurationException { throws ConfigurationException {
this(validateAddress(address), port, maxMazeHeight, maxMazeWidth); this(validateAddress(address), port, maxMazeHeight, maxMazeWidth);
} }
@NotNull @NonNull
public static ServerConfig init() throws ConfigurationException { public static ServerConfig init() throws ConfigurationException {
final String host = System.getProperty(SYSPROP_HOST); final String host = System.getProperty(SYSPROP_HOST);
final String portString = System.getProperty(SYSPROP_PORT); final String portString = System.getProperty(SYSPROP_PORT);
@ -49,7 +49,7 @@ public record ServerConfig(@NotNull InetAddress address,
return new ServerConfig(host, port, maxMazeHeight, maxMazeWidth); return new ServerConfig(host, port, maxMazeHeight, maxMazeWidth);
} }
@NotNull @NonNull
private static InetAddress validateAddress(@Nullable final String address) throws ConfigurationException { private static InetAddress validateAddress(@Nullable final String address) throws ConfigurationException {
return Try.of(() -> InetAddress.getByName(address)) return Try.of(() -> InetAddress.getByName(address))
.getOrElseThrow(cause -> new ConfigurationException( .getOrElseThrow(cause -> new ConfigurationException(
@ -77,9 +77,9 @@ public record ServerConfig(@NotNull InetAddress address,
)); ));
} }
@NotNull @NonNull
private static Option<Integer> validateDimension(@NotNull final Option<Integer> dimension, private static Option<Integer> validateDimension(@NonNull final Option<Integer> dimension,
@NotNull final String identifier) { @NonNull final String identifier) {
if (dimension.exists(d -> d <= 1)) { if (dimension.exists(d -> d <= 1)) {
throw new ConfigurationException("Maximum %s must be greater than 1: %s" throw new ConfigurationException("Maximum %s must be greater than 1: %s"
.formatted(identifier, dimension.get())); .formatted(identifier, dimension.get()));
@ -88,8 +88,8 @@ public record ServerConfig(@NotNull InetAddress address,
} }
private static Option<Integer> validateDimension(@Nullable final String dimensionString, private static Option<Integer> validateDimension(@Nullable final String dimensionString,
@NotNull final String identifier, @NonNull final String identifier,
@NotNull final String syspropName) { @NonNull final String syspropName) {
if (dimensionString == null) { if (dimensionString == null) {
log.info("No maximum {} configured; using default (unlimited).", identifier); log.info("No maximum {} configured; using default (unlimited).", identifier);
return Option.none(); return Option.none();

View file

@ -4,7 +4,7 @@ import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import io.undertow.util.StatusCodes; import io.undertow.util.StatusCodes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.slf4j.MDC; import org.slf4j.MDC;
import java.time.Instant; import java.time.Instant;
@ -14,9 +14,9 @@ import java.util.UUID;
@Slf4j @Slf4j
public abstract class AbstractHttpHandler implements HttpHandler { public abstract class AbstractHttpHandler implements HttpHandler {
@Override @Override
public final void handleRequest(@NotNull final HttpServerExchange exchange) { public final void handleRequest(@NonNull final HttpServerExchange exchange) {
final Instant start = Instant.now(); final Instant start = Instant.now();
try (final MDC.MDCCloseable closeable = MDC.putCloseable("correlationId", UUID.randomUUID().toString())) { try (final MDC.MDCCloseable _ = MDC.putCloseable("correlationId", UUID.randomUUID().toString())) {
if (exchange.isInIoThread()) { if (exchange.isInIoThread()) {
log.debug("Dispatching request"); log.debug("Dispatching request");
@ -35,5 +35,5 @@ public abstract class AbstractHttpHandler implements HttpHandler {
} }
} }
protected abstract void handle(@NotNull final HttpServerExchange exchange) throws Exception; protected abstract void handle(@NonNull final HttpServerExchange exchange) throws Exception;
} }

View file

@ -10,7 +10,7 @@ import io.undertow.util.StatusCodes;
import io.vavr.control.Option; import io.vavr.control.Option;
import io.vavr.control.Try; import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.slf4j.MDC; import org.slf4j.MDC;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -23,18 +23,18 @@ import java.util.Map;
public class CreateHandler extends AbstractHttpHandler { public class CreateHandler extends AbstractHttpHandler {
public static final String PATH_TEMPLATE = "/create/{output}"; public static final String PATH_TEMPLATE = "/create/{output}";
@NotNull @NonNull
private final Option<Integer> maxHeight; private final Option<Integer> maxHeight;
@NotNull @NonNull
private final Option<Integer> maxWidth; private final Option<Integer> maxWidth;
public CreateHandler(@NotNull final Option<Integer> maxHeight, @NotNull final Option<Integer> maxWidth) { public CreateHandler(@NonNull final Option<Integer> maxHeight, @NonNull final Option<Integer> maxWidth) {
this.maxHeight = maxHeight; this.maxHeight = maxHeight;
this.maxWidth = maxWidth; this.maxWidth = maxWidth;
} }
@Override @Override
protected void handle(@NotNull final HttpServerExchange exchange) { protected void handle(@NonNull final HttpServerExchange exchange) {
final Instant start = Instant.now(); final Instant start = Instant.now();
log.debug("Handling create request"); log.debug("Handling create request");
this.createMazeFromRequestParameters(exchange.getQueryParameters()) this.createMazeFromRequestParameters(exchange.getQueryParameters())
@ -65,6 +65,7 @@ public class CreateHandler extends AbstractHttpHandler {
final long durationMillis = start.until(Instant.now(), ChronoUnit.MILLIS); final long durationMillis = start.until(Instant.now(), ChronoUnit.MILLIS);
exchange.getResponseHeaders() exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, outputType.getContentType()) .put(Headers.CONTENT_TYPE, outputType.getContentType())
.put(HttpString.tryFromString("Access-Control-Allow-Origin"), "*")
.put(HttpString.tryFromString("X-Maze-ID"), String.valueOf(maze.getRandomSeed())) .put(HttpString.tryFromString("X-Maze-ID"), String.valueOf(maze.getRandomSeed()))
.put(HttpString.tryFromString("X-Maze-Width"), String.valueOf(maze.getWidth())) .put(HttpString.tryFromString("X-Maze-Width"), String.valueOf(maze.getWidth()))
.put(HttpString.tryFromString("X-Maze-Height"), String.valueOf(maze.getHeight())) .put(HttpString.tryFromString("X-Maze-Height"), String.valueOf(maze.getHeight()))
@ -84,7 +85,7 @@ public class CreateHandler extends AbstractHttpHandler {
}); });
} }
@NotNull @NonNull
private Try<ParametersToMazeExtractor.GeneratedMaze> createMazeFromRequestParameters(final Map<String, Deque<String>> queryParameters) { private Try<ParametersToMazeExtractor.GeneratedMaze> createMazeFromRequestParameters(final Map<String, Deque<String>> queryParameters) {
return new ParametersToMazeExtractor(queryParameters, this.maxHeight, this.maxWidth).createMaze(); return new ParametersToMazeExtractor(queryParameters, this.maxHeight, this.maxWidth).createMaze();
} }

View file

@ -10,7 +10,7 @@ import io.vavr.collection.Stream;
import io.vavr.control.Option; import io.vavr.control.Option;
import io.vavr.control.Try; import io.vavr.control.Try;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import java.util.Deque; import java.util.Deque;
import java.util.Map; import java.util.Map;
@ -19,14 +19,14 @@ import java.util.Random;
@RequiredArgsConstructor @RequiredArgsConstructor
class ParametersToMazeExtractor { class ParametersToMazeExtractor {
@NotNull @NonNull
private final Map<String, Deque<String>> queryParameters; private final Map<String, Deque<String>> queryParameters;
@NotNull @NonNull
private final Option<Integer> maxHeight; private final Option<Integer> maxHeight;
@NotNull @NonNull
private final Option<Integer> maxWidth; private final Option<Integer> maxWidth;
@NotNull @NonNull
Try<GeneratedMaze> createMaze() { Try<GeneratedMaze> createMaze() {
final Option<OutputType> output = getParameterValue(RequestParameter.OUTPUT); final Option<OutputType> output = getParameterValue(RequestParameter.OUTPUT);
final Option<Integer> width = getParameterValue(RequestParameter.WIDTH); final Option<Integer> width = getParameterValue(RequestParameter.WIDTH);
@ -87,11 +87,11 @@ class ParametersToMazeExtractor {
}); });
} }
@NotNull @NonNull
private <T> Option<T> getParameterValue(@NotNull final RequestParameter parameter) { private <T> Option<T> getParameterValue(@NonNull final RequestParameter parameter) {
return parameter.getParameterValue(this.queryParameters); return parameter.getParameterValue(this.queryParameters);
} }
public record GeneratedMaze(@NotNull Maze maze, @NotNull OutputType outputType) { public record GeneratedMaze(@NonNull Maze maze, @NonNull OutputType outputType) {
} }
} }

View file

@ -8,7 +8,7 @@ import io.undertow.util.HeaderValues;
import io.undertow.util.Headers; import io.undertow.util.Headers;
import io.undertow.util.StatusCodes; import io.undertow.util.StatusCodes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -18,7 +18,7 @@ public class RenderV1Handler extends AbstractHttpHandler {
public static final String PATH_TEMPLATE = "/render/v1/{output}"; public static final String PATH_TEMPLATE = "/render/v1/{output}";
@Override @Override
public void handle(@NotNull final HttpServerExchange exchange) { public void handle(@NonNull final HttpServerExchange exchange) {
log.debug("Handling render request"); log.debug("Handling render request");
if (exchange.isInIoThread()) { if (exchange.isInIoThread()) {
@ -47,8 +47,8 @@ public class RenderV1Handler extends AbstractHttpHandler {
}); });
} }
@NotNull @NonNull
private OutputType getOutputType(@NotNull final HttpServerExchange httpServerExchange) { private OutputType getOutputType(@NonNull final HttpServerExchange httpServerExchange) {
return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters()) return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters())
.getOrElse(() -> { .getOrElse(() -> {
final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT); final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT);

View file

@ -8,7 +8,7 @@ import io.undertow.util.HeaderValues;
import io.undertow.util.Headers; import io.undertow.util.Headers;
import io.undertow.util.StatusCodes; import io.undertow.util.StatusCodes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -18,7 +18,7 @@ public class RenderV2Handler extends AbstractHttpHandler {
public static final String PATH_TEMPLATE = "/render/v2/{output}"; public static final String PATH_TEMPLATE = "/render/v2/{output}";
@Override @Override
public void handle(@NotNull final HttpServerExchange exchange) { public void handle(@NonNull final HttpServerExchange exchange) {
log.debug("Handling render request"); log.debug("Handling render request");
if (exchange.isInIoThread()) { if (exchange.isInIoThread()) {
@ -47,8 +47,8 @@ public class RenderV2Handler extends AbstractHttpHandler {
}); });
} }
@NotNull @NonNull
private OutputType getOutputType(@NotNull final HttpServerExchange httpServerExchange) { private OutputType getOutputType(@NonNull final HttpServerExchange httpServerExchange) {
return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters()) return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters())
.getOrElse(() -> { .getOrElse(() -> {
final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT); final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT);

View file

@ -8,7 +8,7 @@ import io.undertow.util.HeaderValues;
import io.undertow.util.Headers; import io.undertow.util.Headers;
import io.undertow.util.StatusCodes; import io.undertow.util.StatusCodes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -18,7 +18,7 @@ public class RenderV3Handler extends AbstractHttpHandler {
public static final String PATH_TEMPLATE = "/render/v3/{output}"; public static final String PATH_TEMPLATE = "/render/v3/{output}";
@Override @Override
public void handle(@NotNull final HttpServerExchange exchange) { public void handle(@NonNull final HttpServerExchange exchange) {
log.debug("Handling render request"); log.debug("Handling render request");
if (exchange.isInIoThread()) { if (exchange.isInIoThread()) {
@ -47,8 +47,8 @@ public class RenderV3Handler extends AbstractHttpHandler {
}); });
} }
@NotNull @NonNull
private OutputType getOutputType(@NotNull final HttpServerExchange httpServerExchange) { private OutputType getOutputType(@NonNull final HttpServerExchange httpServerExchange) {
return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters()) return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters())
.getOrElse(() -> { .getOrElse(() -> {
final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT); final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT);

View file

@ -12,7 +12,7 @@ import io.undertow.util.HeaderValues;
import io.undertow.util.Headers; import io.undertow.util.Headers;
import io.undertow.util.StatusCodes; import io.undertow.util.StatusCodes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -21,7 +21,7 @@ public class RenderVxHandler implements HttpHandler {
public static final String PATH_TEMPLATE = "/render/dyn/{output}"; public static final String PATH_TEMPLATE = "/render/dyn/{output}";
@Override @Override
public void handleRequest(@NotNull final HttpServerExchange exchange) { public void handleRequest(@NonNull final HttpServerExchange exchange) {
log.debug("Handling render request"); log.debug("Handling render request");
if (exchange.isInIoThread()) { if (exchange.isInIoThread()) {
@ -55,8 +55,8 @@ public class RenderVxHandler implements HttpHandler {
}); });
} }
@NotNull @NonNull
private Version getVersion(@NotNull final byte[] bytes) throws IllegalArgumentException { private Version getVersion(final byte @NonNull [] bytes) throws IllegalArgumentException {
if (bytes.length < 3) { if (bytes.length < 3) {
throw new IllegalArgumentException("Invalid input: too short"); throw new IllegalArgumentException("Invalid input: too short");
} }
@ -73,8 +73,8 @@ public class RenderVxHandler implements HttpHandler {
} }
} }
@NotNull @NonNull
private OutputType getOutputType(@NotNull final HttpServerExchange httpServerExchange) { private OutputType getOutputType(@NonNull final HttpServerExchange httpServerExchange) {
return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters()) return RequestParameter.OUTPUT.<OutputType>getParameterValue(httpServerExchange.getQueryParameters())
.getOrElse(() -> { .getOrElse(() -> {
final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT); final HeaderValues accept = httpServerExchange.getRequestHeaders().get(Headers.ACCEPT);
@ -86,6 +86,6 @@ public class RenderVxHandler implements HttpHandler {
} }
private enum Version { private enum Version {
V1, V2, V3; V1, V2, V3
} }
} }

View file

@ -11,7 +11,7 @@ import io.vavr.control.Option;
import io.vavr.control.Try; import io.vavr.control.Try;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import java.util.Deque; import java.util.Deque;
import java.util.Map; import java.util.Map;
@ -25,7 +25,7 @@ enum RequestParameter {
HEIGHT(p -> Try.of(() -> Integer.parseInt(p)) HEIGHT(p -> Try.of(() -> Integer.parseInt(p))
.toOption() .toOption()
.onEmpty(() -> log.debug("Unparseable value for parameter 'height': '{}'", p)), "h", "height"), .onEmpty(() -> log.debug("Unparseable value for parameter 'height': '{}'", p)), "h", "height"),
ID(p -> Try.of(() -> Long.parseLong(p)) ID(p -> Try.of(() -> Long.parseUnsignedLong(p, 16))
.toOption() .toOption()
.onEmpty(() -> log.debug("Unparseable value for parameter 'id': '{}'", p)), "i", "id"), .onEmpty(() -> log.debug("Unparseable value for parameter 'id': '{}'", p)), "i", "id"),
OUTPUT(p -> OutputType.ofString(p) OUTPUT(p -> OutputType.ofString(p)
@ -48,24 +48,24 @@ enum RequestParameter {
.onEmpty(() -> log.debug("Unparseable value for parameter 'end': '{}'", p)), "e", "end"), .onEmpty(() -> log.debug("Unparseable value for parameter 'end': '{}'", p)), "e", "end"),
ALGORITHM(p -> Algorithm.ofString(p) ALGORITHM(p -> Algorithm.ofString(p)
.onEmpty(() -> log.debug("Unparseable value for parameter 'algorithm': '{}'", p)), "a", "algorithm"); .onEmpty(() -> log.debug("Unparseable value for parameter 'algorithm': '{}'", p)), "a", "algorithm");
@NotNull @NonNull
private final Function<String, Option<?>> extractor; private final Function<String, Option<?>> extractor;
@Getter @Getter
@NotNull @NonNull
private final Set<String> names; private final Set<String> names;
RequestParameter(@NotNull final Function<String, Option<?>> extractor, @NotNull final String... names) { RequestParameter(@NonNull final Function<String, Option<?>> extractor, @NonNull final String... names) {
this.extractor = extractor; this.extractor = extractor;
this.names = HashSet.of(names); this.names = HashSet.of(names);
} }
@NotNull @NonNull
Option<?> extractParameterValue(@NotNull final String parameter) { Option<?> extractParameterValue(@NonNull final String parameter) {
return this.extractor.apply(parameter); return this.extractor.apply(parameter);
} }
@NotNull @NonNull
public <T> Option<T> getParameterValue(@NotNull final Map<String, Deque<String>> queryParameters) { public <T> Option<T> getParameterValue(@NonNull final Map<String, Deque<String>> queryParameters) {
return (Option<T>) HashMap.ofAll(queryParameters) return (Option<T>) HashMap.ofAll(queryParameters)
.filterKeys(this.names::contains) .filterKeys(this.names::contains)
.flatMap(Tuple2::_2) .flatMap(Tuple2::_2)