Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.eclipse.uprotocol.transport.builder;

import org.eclipse.uprotocol.v1.UUri;
import org.eclipse.uprotocol.validation.ValidationException;
import org.eclipse.uprotocol.v1.UMessage;
import org.eclipse.uprotocol.v1.UAttributes;
import org.eclipse.uprotocol.v1.UCode;
Expand Down Expand Up @@ -139,8 +140,10 @@ public static UMessageBuilder response(UUri source, UUri sink, UUID reqid) {
throw new IllegalArgumentException("sink must be a response and source must be an rpc method.");
}

if (UuidValidator.Validators.UPROTOCOL.validator().validate(reqid).getCode() != UCode.OK) {
throw new IllegalArgumentException("reqid is not a valid UUID.");
try {
UuidValidator.Validators.UPROTOCOL.validator().validate(reqid);
} catch (ValidationException e) {
throw new IllegalArgumentException("reqid is not a valid UUID.", e);
}

return new UMessageBuilder(source, UuidFactory.Factories.UPROTOCOL.factory().create(),
Expand All @@ -159,8 +162,10 @@ public static UMessageBuilder response(UAttributes request) {
Objects.requireNonNull(request, "request cannot be null.");

// Validate the request
if (UAttributesValidator.Validators.REQUEST.validator().validate(request).isFailure()) {
throw new IllegalArgumentException("request must contain valid request attributes.");
try {
UAttributesValidator.Validators.REQUEST.validator().validate(request);
} catch (ValidationException e) {
throw new IllegalArgumentException("request is not a valid request attributes.", e);
}

return new UMessageBuilder(
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@

import org.eclipse.uprotocol.uuid.factory.UuidUtils;
import org.eclipse.uprotocol.v1.UUID;
import org.eclipse.uprotocol.v1.UStatus;
import org.eclipse.uprotocol.v1.UCode;
import org.eclipse.uprotocol.validation.ValidationResult;
import org.eclipse.uprotocol.validation.ValidationException;
import org.eclipse.uprotocol.validation.ValidationUtils;

import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* A Validator for uProtocol UUIDs.
Expand Down Expand Up @@ -53,48 +51,63 @@ public UuidValidator validator() {
}
}

public UStatus validate(UUID uuid) {
final String errorMessage = Stream.of(
validateVersion(uuid),
validateTime(uuid))
.filter(ValidationResult::isFailure)
.map(ValidationResult::getMessage)
.collect(Collectors.joining(","));
return errorMessage.isBlank() ? ValidationResult.success().toStatus()
: UStatus.newBuilder().setCode(UCode.INVALID_ARGUMENT).setMessage(errorMessage).build();
/**
* Checks if a UUID is valid according to the specific variant/version of the UUID.
*
* @param uuid The UUID to validate.
* @throws NullPointerException if the UUID is null.
* @throws ValidationException if the UUID is invalid.
*/
public void validate(UUID uuid) {
Objects.requireNonNull(uuid);
final var errors = ValidationUtils.collectErrors(uuid,
this::validateVersion,
this::validateTime
);
if (!errors.isEmpty()) {
throw new ValidationException(errors);
}
}

public abstract ValidationResult validateVersion(UUID uuid);
/**
* Validates the version of the UUID.
*
* @param uuid The UUID to check.
* @throws ValidationException if the UUID is invalid.
*/
public abstract void validateVersion(UUID uuid);

public ValidationResult validateTime(UUID uuid) {
public void validateTime(UUID uuid) {
final Optional<Long> time = UuidUtils.getTime(uuid);
return time.isPresent() && (time.get() > 0) ? ValidationResult.success()
: ValidationResult.failure(String.format("Invalid UUID Time"));
if (time.isPresent() && (time.get() > 0)) {
return;
}
throw new ValidationException("Invalid UUID Time");
}

private static class InvalidValidator extends UuidValidator {

@Override
public ValidationResult validateVersion(UUID uuid) {
return ValidationResult.failure(String.format("Invalid UUID Version"));
public void validateVersion(UUID uuid) {
throw new ValidationException("Invalid UUID Version");
}
}

private static class UUIDv6Validator extends UuidValidator {
@Override
public ValidationResult validateVersion(UUID uuid) {
return UuidUtils.isUuidv6(uuid)
? ValidationResult.success()
: ValidationResult.failure(String.format("Not a UUIDv6 Version"));
public void validateVersion(UUID uuid) {
if (!UuidUtils.isUuidv6(uuid)) {
throw new ValidationException("Not a UUIDv6 Version");
}
}
}

private static class UUIDv7Validator extends UuidValidator {
@Override
public ValidationResult validateVersion(UUID uuid) {
return UuidUtils.isUProtocol(uuid)
? ValidationResult.success()
: ValidationResult.failure(String.format("Invalid UUIDv7 Version"));
public void validateVersion(UUID uuid) {
if (!UuidUtils.isUProtocol(uuid)) {
throw new ValidationException("Invalid UUIDv7 Version");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* SPDX-FileCopyrightText: 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.uprotocol.validation;

import java.util.List;
import java.util.stream.Collectors;

/**
* Indicates an error that has occurred during validation of a uProtocol type.
*/
public class ValidationException extends RuntimeException {

private static final long serialVersionUID = 1L;
private final List<Exception> causes;

/**
* Creates a new exception for an error message.
*
* @param message The message.
*/
public ValidationException(String message) {
super(message);
this.causes = List.of();
}

/**
* Creates a new exception for multiple causes.
*
* @param causes The causes for the validation failure.
*/
public ValidationException(List<Exception> causes) {
super("Multiple validation errors");
this.causes = List.copyOf(causes);
}

@Override
public String getMessage() {
if (causes.isEmpty()) {
return super.getMessage();
}
return causes.stream()
.map(Exception::getMessage)
.collect(Collectors.joining(","));
}

/**
* Gets the causes of this exception.
*
* @return An unmodifiable view of the causes.
*/
public final List<Exception> getCauses() {
return causes;
}
}
108 changes: 0 additions & 108 deletions src/main/java/org/eclipse/uprotocol/validation/ValidationResult.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.uprotocol.validation;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public final class ValidationUtils {

private ValidationUtils() {
// Utility class
}

/**
* Collects all exception thrown by checks performed on a given subject.
*
* @param <T> The type of the subject.
* @param subject The subject to perform checks on.
* @param checks The validation checks to perform.
* @return A list of exceptions thrown during validation.
*/
@SafeVarargs
public static <T> List<Exception> collectErrors(T subject, Consumer<T>... checks) {
Objects.requireNonNull(subject);
Objects.requireNonNull(checks);

return Arrays.stream(checks)
.map(check -> {
try {
check.accept(subject);
return null; // No exception = valid
} catch (Exception e) {
return e;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.eclipse.uprotocol.v1.UMessageType;
import org.eclipse.uprotocol.v1.UStatus;
import org.eclipse.uprotocol.v1.UUri;
import org.eclipse.uprotocol.validation.ValidationResult;
import org.eclipse.uprotocol.validation.ValidationException;

import com.google.protobuf.InvalidProtocolBufferException;

Expand Down Expand Up @@ -85,9 +85,16 @@ public TestUTransport(UUri source) {

@Override
public CompletionStage<UStatus> send(UMessage message) {
if (message == null) {
return CompletableFuture.completedFuture(UStatus.newBuilder()
.setCode(UCode.INVALID_ARGUMENT)
.setMessage("Message cannot be null")
.build());
}
UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes());

if ( (message == null) || validator.validate(message.getAttributes()) != ValidationResult.success()) {
try {
validator.validate(message.getAttributes());
} catch (ValidationException e) {
return CompletableFuture.completedFuture(UStatus.newBuilder()
.setCode(UCode.INVALID_ARGUMENT)
.setMessage("Invalid message attributes")
Expand Down
Loading