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…
	
	Add table
		Add a link
		
	
		Reference in a new issue