More logging, some simplification. BUT unsafe typecast. Needs thought.
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		
							parent
							
								
									6af1558b99
								
							
						
					
					
						commit
						87fba97672
					
				
					 2 changed files with 65 additions and 23 deletions
				
			
		|  | @ -56,6 +56,7 @@ public enum OutputType { | ||||||
|     private final Function<Labyrinth, byte[]> render; |     private final Function<Labyrinth, byte[]> render; | ||||||
|     @Getter |     @Getter | ||||||
|     private final boolean attachment; |     private final boolean attachment; | ||||||
|  |     @Getter | ||||||
|     @NonNull |     @NonNull | ||||||
|     private final List<String> names; |     private final List<String> names; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,9 +17,11 @@ import io.vavr.collection.Set; | ||||||
| import io.vavr.collection.Stream; | 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.Getter; | ||||||
| import lombok.NonNull; | import lombok.NonNull; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  | import org.slf4j.MDC; | ||||||
| 
 | 
 | ||||||
| import java.nio.ByteBuffer; | import java.nio.ByteBuffer; | ||||||
| import java.time.Instant; | import java.time.Instant; | ||||||
|  | @ -27,6 +29,7 @@ import java.time.temporal.ChronoUnit; | ||||||
| import java.util.Deque; | import java.util.Deque; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Random; | import java.util.Random; | ||||||
|  | import java.util.function.Function; | ||||||
| 
 | 
 | ||||||
| @Slf4j | @Slf4j | ||||||
| public class CreateHandler extends AbstractHttpHandler { | public class CreateHandler extends AbstractHttpHandler { | ||||||
|  | @ -39,8 +42,10 @@ public class CreateHandler extends AbstractHttpHandler { | ||||||
|         this.createLabyrinthFromRequestParameters(exchange.getQueryParameters()) |         this.createLabyrinthFromRequestParameters(exchange.getQueryParameters()) | ||||||
|                 .onFailure(e -> { |                 .onFailure(e -> { | ||||||
|                     log.error("Error creating Labyrinth from request", e); |                     log.error("Error creating Labyrinth from request", e); | ||||||
|                     exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); |                     exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR) | ||||||
|                     exchange.setReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR_STRING); |                             .setReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR_STRING) | ||||||
|  |                             .getResponseSender() | ||||||
|  |                             .send(e.getMessage()); | ||||||
|                 }) |                 }) | ||||||
|                 .forEach(tuple -> { |                 .forEach(tuple -> { | ||||||
|                     final OutputType outputType = tuple._1(); |                     final OutputType outputType = tuple._1(); | ||||||
|  | @ -50,30 +55,47 @@ public class CreateHandler extends AbstractHttpHandler { | ||||||
|                         bytes = outputType.render(labyrinth); |                         bytes = outputType.render(labyrinth); | ||||||
|                     } catch (@NonNull final Exception e) { |                     } catch (@NonNull final Exception e) { | ||||||
|                         log.error("Error rendering Labyrinth", e); |                         log.error("Error rendering Labyrinth", e); | ||||||
|                         exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); |                         exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR) | ||||||
|                         exchange.setReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR_STRING); |                                 .setReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR_STRING) | ||||||
|  |                                 .getResponseSender() | ||||||
|  |                                 .send("Error creating the Labyrinth. Please contact the administrator. Request id=%s".formatted(MDC.get("correlationId"))); | ||||||
|                         return; |                         return; | ||||||
|                     } |                     } | ||||||
|  |                     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("X-Labyrinth-ID"), String.valueOf(labyrinth.getRandomSeed())) |                             .put(HttpString.tryFromString("X-Labyrinth-ID"), String.valueOf(labyrinth.getRandomSeed())) | ||||||
|                             .put(HttpString.tryFromString("X-Labyrinth-Width"), String.valueOf(labyrinth.getWidth())) |                             .put(HttpString.tryFromString("X-Labyrinth-Width"), String.valueOf(labyrinth.getWidth())) | ||||||
|                             .put(HttpString.tryFromString("X-Labyrinth-Height"), String.valueOf(labyrinth.getHeight())) |                             .put(HttpString.tryFromString("X-Labyrinth-Height"), String.valueOf(labyrinth.getHeight())) | ||||||
|                             .put(HttpString.tryFromString("X-Labyrinth-Generation-Duration-millis"), String.valueOf(start.until(Instant.now(), ChronoUnit.MILLIS))); |                             .put(HttpString.tryFromString("X-Labyrinth-Generation-Duration-millis"), String.valueOf(durationMillis)); | ||||||
|                     exchange.getResponseSender().send(ByteBuffer.wrap(bytes)); |                     exchange.getResponseSender().send(ByteBuffer.wrap(bytes)); | ||||||
|                     log.debug("Create request handled."); |                     log.debug("Create request handled in {}ms.", durationMillis); | ||||||
|                 }); |                 }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private @NonNull Try<Tuple2<OutputType, Labyrinth>> createLabyrinthFromRequestParameters(final Map<String, Deque<String>> queryParameters) { |     @NonNull | ||||||
|  |     private Try<Tuple2<OutputType, Labyrinth>> createLabyrinthFromRequestParameters(final Map<String, Deque<String>> queryParameters) { | ||||||
|         return new ParametersToLabyrinthExtractor(queryParameters).createLabyrinth(); |         return new ParametersToLabyrinthExtractor(queryParameters).createLabyrinth(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private enum RequestParameter { |     private enum RequestParameter { | ||||||
|         WIDTH("w", "width"), HEIGHT("h", "height"), ID("i", "id"), OUTPUT("o", "output"); |         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<String, Option<?>> extractor; | ||||||
|  |         @Getter | ||||||
|  |         @NonNull | ||||||
|         private final Set<String> names; |         private final Set<String> names; | ||||||
| 
 | 
 | ||||||
|         RequestParameter(@NonNull final String... names) { |         RequestParameter(@NonNull final String... names) { | ||||||
|  |             this.extractor = null; | ||||||
|  |             this.names = HashSet.of(names); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         RequestParameter(@NonNull final Function<String, Option<?>> extractor, @NonNull final String... names) { | ||||||
|  |             this.extractor = extractor; | ||||||
|             this.names = HashSet.of(names); |             this.names = HashSet.of(names); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -83,6 +105,10 @@ public class CreateHandler extends AbstractHttpHandler { | ||||||
|             } |             } | ||||||
|             return Stream.of(values()).find(param -> param.names.exists(name::equalsIgnoreCase)); |             return Stream.of(values()).find(param -> param.names.exists(name::equalsIgnoreCase)); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         @NonNull <T> Option<T> extractParameterValue(@NonNull final String parameter) { | ||||||
|  |             return (Option<T>) this.extractor.apply(parameter); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static class ParametersToLabyrinthExtractor { |     private static class ParametersToLabyrinthExtractor { | ||||||
|  | @ -98,22 +124,37 @@ public class CreateHandler extends AbstractHttpHandler { | ||||||
| 
 | 
 | ||||||
|         @NonNull |         @NonNull | ||||||
|         Try<Tuple2<OutputType, Labyrinth>> createLabyrinth() { |         Try<Tuple2<OutputType, Labyrinth>> createLabyrinth() { | ||||||
|             final Option<OutputType> output = getParameterValues(RequestParameter.OUTPUT) |             final Option<OutputType> output = getParameterValue(RequestParameter.OUTPUT); | ||||||
|                     .foldLeft(Option.none(), (type, param) -> type.orElse(() -> OutputType.ofString(param))); |             final Option<Integer> width = getParameterValue(RequestParameter.WIDTH); | ||||||
|             final Option<Integer> width = getParameterValues(RequestParameter.WIDTH) |             final Option<Integer> height = getParameterValue(RequestParameter.HEIGHT); | ||||||
|                     .foldLeft(Option.none(), (value, param) -> value.orElse(() -> Try.of(() -> Integer.parseInt(param)).toOption())); |             final Option<Long> id = getParameterValue(RequestParameter.ID); | ||||||
|             final Option<Integer> height = getParameterValues(RequestParameter.HEIGHT) |  | ||||||
|                     .foldLeft(Option.none(), (value, param) -> value.orElse(() -> Try.of(() -> Integer.parseInt(param)).toOption())); |  | ||||||
|             final Option<Long> id = getParameterValues(RequestParameter.ID) |  | ||||||
|                     .foldLeft(Option.none(), (value, param) -> value.orElse(() -> Try.of(() -> Long.parseLong(param)).toOption())); |  | ||||||
| 
 | 
 | ||||||
|             return Try.of(() -> { |             if (output.isEmpty()) { | ||||||
|                 final OutputType t1 = output.get(); |                 return Try.failure(new IllegalArgumentException("Path parameter %s is required and must be one of: %s".formatted( | ||||||
|                 final Integer width1 = width.get(); |                         RequestParameter.OUTPUT.getNames().mkString("'", " / ", "'"), | ||||||
|                 final Integer height1 = height.get(); |                         Stream.of(OutputType.values()) | ||||||
|                 final Long orElse = id.getOrElse(() -> new Random().nextLong()); |                                 .flatMap(OutputType::getNames) | ||||||
|                 return Tuple.of(t1, new Labyrinth(width1, height1, orElse)); |                                 .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 <T> Option<T> getParameterValue(@NonNull final RequestParameter parameter) { | ||||||
|  |             return this.getParameterValues(parameter) | ||||||
|  |                     .foldLeft(Option.none(), (type, param) -> type.orElse(() -> parameter.extractParameterValue(param))); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @NonNull |         @NonNull | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue