Allow limiting max height and/or width when creating a maze.
This commit is contained in:
parent
f370037289
commit
87b16cb24a
4 changed files with 69 additions and 11 deletions
|
@ -22,7 +22,7 @@ public class MazeServer {
|
||||||
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);
|
||||||
final RoutingHandler routingHandler = new RoutingHandler()
|
final RoutingHandler routingHandler = new RoutingHandler()
|
||||||
.get(CreateHandler.PATH_TEMPLATE, new CreateHandler())
|
.get(CreateHandler.PATH_TEMPLATE, new CreateHandler(config.maxMazeHeight(), config.maxMazeWidth()))
|
||||||
.post(RenderV1Handler.PATH_TEMPLATE, new RenderV1Handler())
|
.post(RenderV1Handler.PATH_TEMPLATE, new RenderV1Handler())
|
||||||
.post(RenderV2Handler.PATH_TEMPLATE, new RenderV2Handler());
|
.post(RenderV2Handler.PATH_TEMPLATE, new RenderV2Handler());
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ public class MazeServer {
|
||||||
private void start() {
|
private void start() {
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "listener-stopper"));
|
Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "listener-stopper"));
|
||||||
this.undertow.start();
|
this.undertow.start();
|
||||||
final InetSocketAddress address = (InetSocketAddress) this.undertow.getListenerInfo().get(0).getAddress();
|
final InetSocketAddress address = (InetSocketAddress) this.undertow.getListenerInfo().getFirst().getAddress();
|
||||||
final String hostAddress = address.getAddress().getHostAddress();
|
final String hostAddress = address.getAddress().getHostAddress();
|
||||||
final int port = address.getPort();
|
final int port = address.getPort();
|
||||||
|
|
||||||
|
|
|
@ -8,26 +8,41 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public record ServerConfig(@NotNull InetAddress address, int port) {
|
public record ServerConfig(@NotNull InetAddress address,
|
||||||
|
int port,
|
||||||
|
int maxMazeHeight,
|
||||||
|
int 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_WIDTH = "fritteli.maze.maxwidth";
|
||||||
|
|
||||||
public ServerConfig(@NotNull final InetAddress address, int port) {
|
public ServerConfig(@NotNull final InetAddress address,
|
||||||
|
final int port,
|
||||||
|
final int maxMazeHeight,
|
||||||
|
final int maxMazeWidth) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.port = validatePort(port);
|
this.port = validatePort(port);
|
||||||
|
this.maxMazeHeight = validateDimension(maxMazeHeight, "height");
|
||||||
|
this.maxMazeWidth = validateDimension(maxMazeWidth, "width");
|
||||||
log.debug("host={}, port={}", this.address, this.port);
|
log.debug("host={}, port={}", this.address, this.port);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerConfig(@Nullable final String address, final int port) throws ConfigurationException {
|
public ServerConfig(@Nullable final String address, final int port, final int maxMazeHeight, final int maxMazeWidth)
|
||||||
this(validateAddress(address), port);
|
throws ConfigurationException {
|
||||||
|
this(validateAddress(address), port, maxMazeHeight, maxMazeWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
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);
|
||||||
|
final String maxMazeHeightString = System.getProperty(SYSPROP_MAX_MAZE_HEIGHT);
|
||||||
|
final String maxMazeWidthString = System.getProperty(SYSPROP_MAX_MAZE_WIDTH);
|
||||||
final int port = validatePort(portString);
|
final int port = validatePort(portString);
|
||||||
return new ServerConfig(host, port);
|
final int maxMazeHeight = validateDimension(maxMazeHeightString, "height", SYSPROP_MAX_MAZE_HEIGHT);
|
||||||
|
final int maxMazeWidth = validateDimension(maxMazeWidthString, "width", SYSPROP_MAX_MAZE_WIDTH);
|
||||||
|
return new ServerConfig(host, port, maxMazeHeight, maxMazeWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -57,4 +72,26 @@ public record ServerConfig(@NotNull InetAddress address, int port) {
|
||||||
cause
|
cause
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int validateDimension(final int dimension, @NotNull final String identifier) {
|
||||||
|
if (dimension < 0) {
|
||||||
|
throw new ConfigurationException("Maximum %s is negative : %s".formatted(dimension, identifier));
|
||||||
|
}
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int validateDimension(@Nullable final String dimensionString,
|
||||||
|
@NotNull final String identifier,
|
||||||
|
@NotNull final String syspropName) {
|
||||||
|
if (dimensionString == null) {
|
||||||
|
log.info("No maximum {} configured; using default (unlimited).", identifier);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Try.of(() -> Integer.valueOf(dimensionString))
|
||||||
|
.getOrElseThrow(cause -> new ConfigurationException(
|
||||||
|
"Failed to parse maximum %s specified in system property '%s': %s"
|
||||||
|
.formatted(identifier, syspropName, dimensionString),
|
||||||
|
cause
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,13 @@ 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}";
|
||||||
|
private final int maxHeight;
|
||||||
|
private final int maxWidth;
|
||||||
|
|
||||||
|
public CreateHandler(final int maxHeight, final int maxWidth) {
|
||||||
|
this.maxHeight = maxHeight;
|
||||||
|
this.maxWidth = maxWidth;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handle(@NotNull final HttpServerExchange exchange) {
|
protected void handle(@NotNull final HttpServerExchange exchange) {
|
||||||
|
@ -29,10 +36,11 @@ public class CreateHandler extends AbstractHttpHandler {
|
||||||
log.debug("Handling create request");
|
log.debug("Handling create request");
|
||||||
this.createMazeFromRequestParameters(exchange.getQueryParameters())
|
this.createMazeFromRequestParameters(exchange.getQueryParameters())
|
||||||
.onFailure(e -> {
|
.onFailure(e -> {
|
||||||
log.error("Error creating maze from request", e);
|
|
||||||
if (e instanceof InvalidRequestParameterException) {
|
if (e instanceof InvalidRequestParameterException) {
|
||||||
|
log.debug("Error creating maze from request", e);
|
||||||
exchange.setStatusCode(StatusCodes.BAD_REQUEST);
|
exchange.setStatusCode(StatusCodes.BAD_REQUEST);
|
||||||
} else {
|
} else {
|
||||||
|
log.error("Error creating maze from request", e);
|
||||||
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
|
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
exchange.getResponseSender()
|
exchange.getResponseSender()
|
||||||
|
@ -75,6 +83,6 @@ public class CreateHandler extends AbstractHttpHandler {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
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).createMaze();
|
return new ParametersToMazeExtractor(queryParameters, this.maxHeight, this.maxWidth).createMaze();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ class ParametersToMazeExtractor {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Map<String, Deque<String>> queryParameters;
|
private final Map<String, Deque<String>> queryParameters;
|
||||||
|
private final int maxHeight;
|
||||||
|
private final int maxWidth;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
Try<GeneratedMaze> createMaze() {
|
Try<GeneratedMaze> createMaze() {
|
||||||
|
@ -49,12 +51,23 @@ class ParametersToMazeExtractor {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int desiredHeight = height.get();
|
||||||
|
final int desiredWidth = width.get();
|
||||||
|
|
||||||
|
if (this.maxHeight != 0 && desiredHeight > this.maxHeight) {
|
||||||
|
return Try.failure(new InvalidRequestParameterException("Specified height (%s) is greater than allowed maximum of %s".formatted(desiredHeight, this.maxHeight)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.maxWidth != 0 && desiredWidth > this.maxWidth) {
|
||||||
|
return Try.failure(new InvalidRequestParameterException("Specified width (%s) is greater than allowed maximum of %s".formatted(desiredWidth, this.maxWidth)));
|
||||||
|
}
|
||||||
|
|
||||||
return Try.of(() -> {
|
return Try.of(() -> {
|
||||||
final Maze maze;
|
final Maze maze;
|
||||||
if (start.isDefined() && end.isDefined()) {
|
if (start.isDefined() && end.isDefined()) {
|
||||||
maze = new Maze(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong()), start.get(), end.get());
|
maze = new Maze(desiredWidth, desiredHeight, id.getOrElse(() -> new Random().nextLong()), start.get(), end.get());
|
||||||
} else {
|
} else {
|
||||||
maze = new Maze(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong()));
|
maze = new Maze(desiredWidth, desiredHeight, id.getOrElse(() -> new Random().nextLong()));
|
||||||
}
|
}
|
||||||
new RandomDepthFirst(maze).run();
|
new RandomDepthFirst(maze).run();
|
||||||
return new GeneratedMaze(maze, output.get(), RandomDepthFirst.class.getSimpleName());
|
return new GeneratedMaze(maze, output.get(), RandomDepthFirst.class.getSimpleName());
|
||||||
|
|
Loading…
Reference in a new issue