From: Kai Moritz Date: Fri, 18 Aug 2023 12:09:02 +0000 (+0200) Subject: fix: GREEN - Fixed NPE in `ShardedChatHome.getChatRoom()` for foreign shard X-Git-Tag: rebase--2023-08-18-abends~21 X-Git-Url: http://juplo.de/gitweb/?a=commitdiff_plain;h=8d8ad4fbe742d49c498993e127f7a4ab72b20020;p=demos%2Fkafka%2Fchat fix: GREEN - Fixed NPE in `ShardedChatHome.getChatRoom()` for foreign shard * `ShardedChatHome.getChatRoom(UUID)` know checks, if a `ChatHome` exists for the selected shard. * If no `ChatHome` exists, a `ShardNotOwnedException` is thrown. * The `ChatBackendControllerAdvice` translates the exception to an error of type 404 - NOT FOUND, to fullfill the defined expectations. --- diff --git a/src/main/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerAdvice.java b/src/main/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerAdvice.java index 55350f17..ad90c4b6 100644 --- a/src/main/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerAdvice.java +++ b/src/main/java/de/juplo/kafka/chat/backend/api/ChatBackendControllerAdvice.java @@ -2,6 +2,7 @@ package de.juplo.kafka.chat.backend.api; import de.juplo.kafka.chat.backend.domain.InvalidUsernameException; import de.juplo.kafka.chat.backend.domain.MessageMutationException; +import de.juplo.kafka.chat.backend.domain.ShardNotOwnedException; import de.juplo.kafka.chat.backend.domain.UnknownChatroomException; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; @@ -50,6 +51,36 @@ public class ChatBackendControllerAdvice return problem; } + @ExceptionHandler(ShardNotOwnedException.class) + public final ProblemDetail handleException( + ShardNotOwnedException e, + ServerWebExchange exchange, + UriComponentsBuilder uriComponentsBuilder) + { + final HttpStatus status = HttpStatus.NOT_FOUND; + ProblemDetail problem = ProblemDetail.forStatus(status); + + problem.setProperty("timestamp", new Date()); + + problem.setProperty("requestId", exchange.getRequest().getId()); + + problem.setType(uriComponentsBuilder.replacePath(contextPath).path("/problem/shard-not-owned").build().toUri()); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(status.getReasonPhrase()); + stringBuilder.append(" - "); + stringBuilder.append(e.getMessage()); + problem.setTitle(stringBuilder.toString()); + + stringBuilder.setLength(0); + stringBuilder.append("Shard not owned: "); + stringBuilder.append(e.getShard()); + problem.setDetail(stringBuilder.toString()); + + problem.setProperty("shard", e.getShard()); + + return problem; + } + @ExceptionHandler(MessageMutationException.class) public final ProblemDetail handleException( MessageMutationException e, diff --git a/src/main/java/de/juplo/kafka/chat/backend/domain/ShardNotOwnedException.java b/src/main/java/de/juplo/kafka/chat/backend/domain/ShardNotOwnedException.java new file mode 100644 index 00000000..3b638331 --- /dev/null +++ b/src/main/java/de/juplo/kafka/chat/backend/domain/ShardNotOwnedException.java @@ -0,0 +1,17 @@ +package de.juplo.kafka.chat.backend.domain; + +import lombok.Getter; + + +public class ShardNotOwnedException extends IllegalStateException +{ + @Getter + private final int shard; + + + public ShardNotOwnedException(int shard) + { + super("This instance does not own the shard " + shard); + this.shard = shard; + } +} diff --git a/src/main/java/de/juplo/kafka/chat/backend/domain/ShardedChatHome.java b/src/main/java/de/juplo/kafka/chat/backend/domain/ShardedChatHome.java index 4b8c7f16..6d2f0794 100644 --- a/src/main/java/de/juplo/kafka/chat/backend/domain/ShardedChatHome.java +++ b/src/main/java/de/juplo/kafka/chat/backend/domain/ShardedChatHome.java @@ -40,7 +40,10 @@ public class ShardedChatHome implements ChatHome @Override public Mono getChatRoom(UUID id) { - return chatHomes[selectShard(id)].getChatRoom(id); + int shard = selectShard(id); + if (chatHomes[shard] == null) + throw new ShardNotOwnedException(shard); + return chatHomes[shard].getChatRoom(id); } @Override