diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java index b1f18465a..9db57ae2a 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java @@ -32,5 +32,5 @@ + " subset of the original EDC Policy Entity.") public class UiPolicyCreateRequest { @Schema(description = "Conjunction of required expressions for the policy to evaluate to TRUE.") - private List constraints; + private List expressions; } diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpression.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpression.java new file mode 100644 index 000000000..5c5b4a84c --- /dev/null +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpression.java @@ -0,0 +1,35 @@ +package de.sovity.edc.ext.wrapper.api.common.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import java.util.List; + + +@Data +@AllArgsConstructor +@RequiredArgsConstructor +@Builder(toBuilder = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = + "Represents a single Ui Policy Literal or a List of Ui Policy Expressions. The Literal" + + " will be evaluated if the expressionType is LITERAL.") +public class UiPolicyExpression { + + @Schema(description = "Either LITERAL or one of the constraint types.") + private UiPolicyExpressionType expressionType; + + @Schema(description = + "List of policy elements that are evaluated according the expressionType.") + private List expressions; + + @Schema(description = + "A single literal. Will be evaluated if the expressionType is set to " + + "LITERAL.") + private UiPolicyConstraint constraint; + +} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpressionType.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpressionType.java new file mode 100644 index 000000000..618cc4a28 --- /dev/null +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpressionType.java @@ -0,0 +1,16 @@ +package de.sovity.edc.ext.wrapper.api.common.model; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = """ + Ui Policy Expression types: + * `AND` - Several constraints, all of which must be respected + * `OR` - Several constraints, of which at least one must be respected + * `XOR` - Several constraints, of which exactly one must be respected + * `CONSTRAINT` - A single constraint for the policy + """, enumAsRef = true) +public enum UiPolicyExpressionType { + AND, OR, XOR, CONSTRAINT +} + + diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java index 78f4fcb4d..fc4eb281d 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java @@ -19,15 +19,14 @@ import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.FailedMappingException; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.PolicyValidator; -import de.sovity.edc.ext.wrapper.api.common.model.Expression; -import de.sovity.edc.ext.wrapper.api.common.model.UiPolicy; -import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyCreateRequest; +import de.sovity.edc.ext.wrapper.api.common.model.*; import de.sovity.edc.utils.JsonUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.json.JsonObject; import lombok.RequiredArgsConstructor; import org.eclipse.edc.policy.model.Action; import org.eclipse.edc.policy.model.AndConstraint; +import org.eclipse.edc.policy.model.AtomicConstraint; import org.eclipse.edc.policy.model.Constraint; import org.eclipse.edc.policy.model.OrConstraint; import org.eclipse.edc.policy.model.Permission; @@ -62,10 +61,10 @@ public UiPolicy buildUiPolicy(Policy policy) { var constraints = constraintExtractor.getPermissionConstraints(policy, errors); return UiPolicy.builder() - .policyJsonLd(toJson(buildPolicyJsonLd(policy))) - .constraints(constraints) - .errors(errors.getErrors()) - .build(); + .policyJsonLd(toJson(buildPolicyJsonLd(policy))) + .constraints(constraints) + .errors(errors.getErrors()) + .build(); } /** @@ -77,57 +76,76 @@ public UiPolicy buildUiPolicy(Policy policy) { * @return ODRL policy */ public Policy buildPolicy(UiPolicyCreateRequest policyCreateDto) { - var constraints = new ArrayList(atomicConstraintMapper.buildAtomicConstraints( - policyCreateDto.getConstraints())); + var constraints = convertExpressionsToConstraints(policyCreateDto.getExpressions()); var action = Action.Builder.newInstance().type(PolicyValidator.ALLOWED_ACTION).build(); var permission = Permission.Builder.newInstance() - .action(action) - .constraints(constraints) - .build(); + .action(action) + .constraints(constraints) + .build(); return Policy.Builder.newInstance() - .type(PolicyType.SET) - .permission(permission) - .build(); + .type(PolicyType.SET) + .permission(permission) + .build(); } public Policy buildPolicy(List constraintElements) { var constraints = buildConstraints(constraintElements); var action = Action.Builder.newInstance().type(Prop.Odrl.USE).build(); var permission = Permission.Builder.newInstance() - .action(action) - .constraints(constraints) - .build(); + .action(action) + .constraints(constraints) + .build(); return Policy.Builder.newInstance() - .type(PolicyType.SET) - .permission(permission) - .build(); + .type(PolicyType.SET) + .permission(permission) + .build(); } @NotNull private List buildConstraints(List expressions) { return expressions.stream() - .map(this::buildConstraint) - .toList(); + .map(this::buildConstraint) + .toList(); } private Constraint buildConstraint(Expression expression) { var subExpressions = expression.getExpressions(); return switch (expression.getExpressionType()) { - case ATOMIC_CONSTRAINT -> - atomicConstraintMapper.buildAtomicConstraint(expression.getAtomicConstraint()); + case ATOMIC_CONSTRAINT -> atomicConstraintMapper.buildAtomicConstraint(expression.getAtomicConstraint()); case AND -> AndConstraint.Builder.newInstance() - .constraints(buildConstraints(subExpressions)) - .build(); + .constraints(buildConstraints(subExpressions)) + .build(); case OR -> OrConstraint.Builder.newInstance() - .constraints(buildConstraints(subExpressions)) - .build(); + .constraints(buildConstraints(subExpressions)) + .build(); case XOR -> XoneConstraint.Builder.newInstance() - .constraints(buildConstraints(subExpressions)) - .build(); + .constraints(buildConstraints(subExpressions)) + .build(); + }; + } + + private List convertExpressionsToConstraints(List expressions) { + return expressions.stream() + .map(this::convertExpressionToConstraint) + .toList(); + } + + private Constraint convertExpressionToConstraint(UiPolicyExpression expression) { + return switch (expression.getExpressionType()) { + case CONSTRAINT -> atomicConstraintMapper.buildAtomicConstraint(expression.getConstraint()); + case AND -> AndConstraint.Builder.newInstance() + .constraints(convertExpressionsToConstraints(expression.getExpressions())) + .build(); + case OR -> OrConstraint.Builder.newInstance() + .constraints(convertExpressionsToConstraints(expression.getExpressions())) + .build(); + case XOR -> XoneConstraint.Builder.newInstance() + .constraints(convertExpressionsToConstraints(expression.getExpressions())) + .build(); }; } @@ -141,7 +159,7 @@ private Constraint buildConstraint(Expression expression) { */ public Policy buildPolicy(JsonObject policyJsonLd) { return typeTransformerRegistry.transform(policyJsonLd, Policy.class) - .orElseThrow(FailedMappingException::ofFailure); + .orElseThrow(FailedMappingException::ofFailure); } /** @@ -166,6 +184,6 @@ public Policy buildPolicy(String policyJsonLd) { */ public JsonObject buildPolicyJsonLd(Policy policy) { return typeTransformerRegistry.transform(policy, JsonObject.class) - .orElseThrow(FailedMappingException::ofFailure); + .orElseThrow(FailedMappingException::ofFailure); } } diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java index 47c75f218..2899170a9 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java @@ -93,7 +93,7 @@ private Optional getOperator(AtomicConstraint atomicConstraint, Map return Optional.of(operatorMapper.getOperatorDto(operator)); } - private AtomicConstraint buildAtomicConstraint(UiPolicyConstraint constraint) { + public AtomicConstraint buildAtomicConstraint(UiPolicyConstraint constraint) { var left = constraint.getLeft(); var operator = operatorMapper.getOperator(constraint.getOperator()); var right = literalMapper.getUiLiteralValue(constraint.getRight());