Skip to content

Commit

Permalink
supply JsonValue for validating message input/output lazily
Browse files Browse the repository at this point in the history
* in order to check if validation is even enabled for a given message before making sure it is in JSON
  • Loading branch information
thjaeckle committed Jan 21, 2025
1 parent 251034b commit 69c7f34
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import java.util.function.Supplier;

import javax.annotation.Nullable;

Expand Down Expand Up @@ -577,31 +578,30 @@ private CompletionStage<Boolean> doesThingExist() {
((MessageCommand<JsonValue, ?>) messageCommand)
.getMessage();

if (message.getPayload().isPresent() && !isJsonMessageContent(message)) {
return CompletableFuture.failedFuture(
WotThingModelPayloadValidationException
// lazily only supply JsonValue if validation is enabled for the message:
final Supplier<JsonValue> messageCommandPayloadSupplier = () -> {
if (message.getPayload().isPresent() && !isJsonMessageContent(message)) {
throw WotThingModelPayloadValidationException
.newBuilder("Could not validate non-JSON message content type <" +
message.getContentType().orElse("?") + "> for message subject " +
"<" + message.getSubject() + ">"
)
.dittoHeaders(messageCommand.getDittoHeaders())
.build()
);
}
.build();
}

final MessageDirection messageDirection = message.getDirection();
final JsonValue messageCommandPayload = message
.getPayload()
.orElse(null);
return message.getPayload().orElse(null);
};

final MessageDirection messageDirection = message.getDirection();
if (messageCommand instanceof SendThingMessage<?> sendThingMessage) {
return performWotBasedThingMessageValidation(messageCommand, sendThingMessage, messageDirection,
messageCommandPayload
messageCommandPayloadSupplier
).thenApply(aVoid -> messageCommand);
} else if (messageCommand instanceof SendFeatureMessage<?> sendFeatureMessage) {
final String featureId = sendFeatureMessage.getFeatureId();
return performWotBasedFeatureMessageValidation(messageCommand, sendFeatureMessage, featureId,
messageDirection, messageCommandPayload
messageDirection, messageCommandPayloadSupplier
).thenApply(aVoid -> messageCommand);

} else {
Expand All @@ -612,23 +612,23 @@ private CompletionStage<Boolean> doesThingExist() {
private CompletionStage<Void> performWotBasedThingMessageValidation(final MessageCommand<?, ?> messageCommand,
final SendThingMessage<?> sendThingMessage,
final MessageDirection messageDirection,
@Nullable final JsonValue messageCommandPayload
final Supplier<JsonValue> messageCommandPayloadSupplier
) {
return resolveThingDefinition()
.thenCompose(optThingDefinition -> {
if (messageDirection == MessageDirection.TO) {
return thingModelValidator.validateThingActionInput(
optThingDefinition.orElse(null),
sendThingMessage.getMessage().getSubject(),
messageCommandPayload,
messageCommandPayloadSupplier,
sendThingMessage.getResourcePath(),
sendThingMessage.getDittoHeaders()
);
} else if (messageDirection == MessageDirection.FROM) {
return thingModelValidator.validateThingEventData(
optThingDefinition.orElse(null),
sendThingMessage.getMessage().getSubject(),
messageCommandPayload,
messageCommandPayloadSupplier,
sendThingMessage.getResourcePath(),
sendThingMessage.getDittoHeaders()
);
Expand All @@ -646,7 +646,7 @@ private CompletionStage<Void> performWotBasedFeatureMessageValidation(final Mess
final SendFeatureMessage<?> sendFeatureMessage,
final String featureId,
final MessageDirection messageDirection,
@Nullable final JsonValue messageCommandPayload
final Supplier<JsonValue> messageCommandPayloadSupplier
) {
return resolveThingAndFeatureDefinition(featureId)
.thenCompose(optDefinitionPair -> {
Expand All @@ -656,7 +656,7 @@ private CompletionStage<Void> performWotBasedFeatureMessageValidation(final Mess
optDefinitionPair.second().orElse(null),
featureId,
sendFeatureMessage.getMessage().getSubject(),
messageCommandPayload,
messageCommandPayloadSupplier,
sendFeatureMessage.getResourcePath(),
sendFeatureMessage.getDittoHeaders()
);
Expand All @@ -666,7 +666,7 @@ private CompletionStage<Void> performWotBasedFeatureMessageValidation(final Mess
optDefinitionPair.second().orElse(null),
featureId,
sendFeatureMessage.getMessage().getSubject(),
messageCommandPayload,
messageCommandPayloadSupplier,
sendFeatureMessage.getResourcePath(),
sendFeatureMessage.getDittoHeaders()
);
Expand Down Expand Up @@ -699,18 +699,29 @@ private CompletionStage<Void> performWotBasedFeatureMessageValidation(final Mess
);
}

final MessageDirection messageDirection = message.getDirection();
final JsonValue messageCommandPayload = message
.getPayload()
.orElse(null);
// lazily only supply JsonValue if validation is enabled for the message:
final Supplier<JsonValue> messageCommandPayloadSupplier = () -> {
if (message.getPayload().isPresent() && !isJsonMessageContent(message)) {
throw WotThingModelPayloadValidationException
.newBuilder("Could not validate non-JSON message content type <" +
message.getContentType().orElse("?") + "> for message response subject " +
"<" + message.getSubject() + ">"
)
.dittoHeaders(messageCommandResponse.getDittoHeaders())
.build();
}

return message.getPayload().orElse(null);
};

final MessageDirection messageDirection = message.getDirection();
if (messageDirection == MessageDirection.TO &&
messageCommandResponse instanceof SendThingMessageResponse<?> sendThingMessageResponse) {
return resolveThingDefinition()
.thenCompose(optThingDefinition -> thingModelValidator.validateThingActionOutput(
optThingDefinition.orElse(null),
sendThingMessageResponse.getMessage().getSubject(),
messageCommandPayload,
messageCommandPayloadSupplier,
sendThingMessageResponse.getResourcePath(),
sendThingMessageResponse.getDittoHeaders()
))
Expand All @@ -724,7 +735,7 @@ private CompletionStage<Void> performWotBasedFeatureMessageValidation(final Mess
optDefinitionPair.second().orElse(null),
featureId,
sendFeatureMessageResponse.getMessage().getSubject(),
messageCommandPayload,
messageCommandPayloadSupplier,
sendFeatureMessageResponse.getResourcePath(),
sendFeatureMessageResponse.getDittoHeaders()
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ public void correlationIdDifferentInCaseOfConflict() {

supervisor.tell(message, getRef());

expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);
expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);

final var firstPublishRead = expectPubsubMessagePublish(message.getEntityId());
Expand All @@ -315,6 +316,7 @@ public void correlationIdDifferentInCaseOfConflict() {

supervisor.tell(message, getRef());

expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);
expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);

final var secondPublishRead = expectPubsubMessagePublish(message.getEntityId());
Expand Down Expand Up @@ -351,6 +353,7 @@ public void acceptMessageCommandByPolicy() {
final MessageCommand<?, ?> msgCommand = thingMessageCommand("abc");
supervisor.tell(msgCommand, getRef());

expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);
expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);

expectPubsubMessagePublish(msgCommand.getEntityId());
Expand Down Expand Up @@ -378,6 +381,7 @@ public void acceptFeatureMessageCommandByPolicy() {
final MessageCommand<?, ?> msgCommand = featureMessageCommand();
supervisor.tell(msgCommand, getRef());

expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);
expectAndAnswerSudoRetrieveThing(sudoRetrieveThingResponse);

expectPubsubMessagePublish(msgCommand.getEntityId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -231,7 +232,7 @@ public CompletionStage<Void> validateThingScopedDeletion(@Nullable final ThingDe
@Override
public CompletionStage<Void> validateThingActionInput(@Nullable final ThingDefinition thingDefinition,
final String messageSubject,
@Nullable final JsonValue inputPayload,
final Supplier<JsonValue> inputPayloadSupplier,
final JsonPointer resourcePath,
final DittoHeaders dittoHeaders
) {
Expand All @@ -240,7 +241,7 @@ public CompletionStage<Void> validateThingActionInput(@Nullable final ThingDefin
.map(validationConfig -> fetchResolveAndValidateWith(thingDefinition, dittoHeaders, thingModel ->
selectValidation(validationConfig)
.validateThingActionInput(thingModel,
messageSubject, inputPayload, resourcePath, context
messageSubject, inputPayloadSupplier.get(), resourcePath, context
).handle(applyLogingErrorOnlyStrategy(validationConfig, context, "validateThingActionInput"))
))
.orElseGet(DefaultWotThingModelValidator::success);
Expand All @@ -249,7 +250,7 @@ public CompletionStage<Void> validateThingActionInput(@Nullable final ThingDefin
@Override
public CompletionStage<Void> validateThingActionOutput(@Nullable final ThingDefinition thingDefinition,
final String messageSubject,
@Nullable final JsonValue outputPayload,
final Supplier<JsonValue> outputPayloadSupplier,
final JsonPointer resourcePath,
final DittoHeaders dittoHeaders
) {
Expand All @@ -258,7 +259,7 @@ public CompletionStage<Void> validateThingActionOutput(@Nullable final ThingDefi
.map(validationConfig -> fetchResolveAndValidateWith(thingDefinition, dittoHeaders, thingModel ->
selectValidation(validationConfig)
.validateThingActionOutput(thingModel,
messageSubject, outputPayload, resourcePath, context
messageSubject, outputPayloadSupplier.get(), resourcePath, context
).handle(applyLogingErrorOnlyStrategy(validationConfig, context, "validateThingActionOutput"))
))
.orElseGet(DefaultWotThingModelValidator::success);
Expand All @@ -267,7 +268,7 @@ public CompletionStage<Void> validateThingActionOutput(@Nullable final ThingDefi
@Override
public CompletionStage<Void> validateThingEventData(@Nullable final ThingDefinition thingDefinition,
final String messageSubject,
@Nullable final JsonValue dataPayload,
final Supplier<JsonValue> dataPayloadSupplier,
final JsonPointer resourcePath,
final DittoHeaders dittoHeaders
) {
Expand All @@ -276,7 +277,7 @@ public CompletionStage<Void> validateThingEventData(@Nullable final ThingDefinit
.map(validationConfig -> fetchResolveAndValidateWith(thingDefinition, dittoHeaders, thingModel ->
selectValidation(validationConfig)
.validateThingEventData(thingModel,
messageSubject, dataPayload, resourcePath, context
messageSubject, dataPayloadSupplier.get(), resourcePath, context
).handle(applyLogingErrorOnlyStrategy(validationConfig, context, "validateThingEventData"))
))
.orElseGet(DefaultWotThingModelValidator::success);
Expand Down Expand Up @@ -493,7 +494,7 @@ public CompletionStage<Void> validateFeatureActionInput(@Nullable final ThingDef
@Nullable final FeatureDefinition featureDefinition,
final String featureId,
final String messageSubject,
@Nullable final JsonValue inputPayload,
final Supplier<JsonValue> inputPayloadSupplier,
final JsonPointer resourcePath,
final DittoHeaders dittoHeaders
) {
Expand All @@ -504,7 +505,7 @@ public CompletionStage<Void> validateFeatureActionInput(@Nullable final ThingDef
dittoHeaders, featureThingModel ->
selectValidation(validationConfig)
.validateFeatureActionInput(featureThingModel,
featureId, messageSubject, inputPayload, resourcePath, context
featureId, messageSubject, inputPayloadSupplier.get(), resourcePath, context
).handle(applyLogingErrorOnlyStrategy(validationConfig, context, "validateFeatureActionInput"))
))
.orElseGet(DefaultWotThingModelValidator::success);
Expand All @@ -515,7 +516,7 @@ public CompletionStage<Void> validateFeatureActionOutput(@Nullable final ThingDe
@Nullable final FeatureDefinition featureDefinition,
final String featureId,
final String messageSubject,
@Nullable final JsonValue inputPayload,
final Supplier<JsonValue> inputPayloadSupplier,
final JsonPointer resourcePath,
final DittoHeaders dittoHeaders
) {
Expand All @@ -526,7 +527,7 @@ public CompletionStage<Void> validateFeatureActionOutput(@Nullable final ThingDe
dittoHeaders, featureThingModel ->
selectValidation(validationConfig)
.validateFeatureActionOutput(featureThingModel,
featureId, messageSubject, inputPayload, resourcePath, context
featureId, messageSubject, inputPayloadSupplier.get(), resourcePath, context
).handle(applyLogingErrorOnlyStrategy(validationConfig, context, "validateFeatureActionOutput"))
))
.orElseGet(DefaultWotThingModelValidator::success);
Expand All @@ -537,7 +538,7 @@ public CompletionStage<Void> validateFeatureEventData(@Nullable final ThingDefin
@Nullable final FeatureDefinition featureDefinition,
final String featureId,
final String messageSubject,
@Nullable final JsonValue dataPayload,
final Supplier<JsonValue> dataPayloadSupplier,
final JsonPointer resourcePath,
final DittoHeaders dittoHeaders
) {
Expand All @@ -548,7 +549,7 @@ public CompletionStage<Void> validateFeatureEventData(@Nullable final ThingDefin
dittoHeaders, featureThingModel ->
selectValidation(validationConfig)
.validateFeatureEventData(featureThingModel,
featureId, messageSubject, dataPayload, resourcePath, context
featureId, messageSubject, dataPayloadSupplier.get(), resourcePath, context
).handle(applyLogingErrorOnlyStrategy(validationConfig, context, "validateFeatureEventData"))
))
.orElseGet(DefaultWotThingModelValidator::success);
Expand Down
Loading

0 comments on commit 69c7f34

Please sign in to comment.