Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(policy): handle 'remedy' attribute in Prohibition #4056

Merged
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 @@ -42,6 +42,7 @@

import java.util.Optional;

import static jakarta.json.stream.JsonCollectors.toJsonArray;
import static java.util.UUID.randomUUID;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
Expand All @@ -65,6 +66,7 @@
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_TYPE_SET;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_PROHIBITION_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_REFINEMENT_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_REMEDY_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_RIGHT_OPERAND_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_TARGET_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_XONE_CONSTRAINT_ATTRIBUTE;
Expand Down Expand Up @@ -195,6 +197,12 @@ public JsonObject visitPermission(Permission permission) {
public JsonObject visitProhibition(Prohibition prohibition) {
var prohibitionBuilder = visitRule(prohibition);

var remedies = prohibition.getRemedies();
if (remedies != null && !remedies.isEmpty()) {
var remediesJson = remedies.stream().map(this::visitDuty).collect(toJsonArray());
prohibitionBuilder.add(ODRL_REMEDY_ATTRIBUTE, remediesJson);
}

return prohibitionBuilder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
import org.eclipse.edc.jsonld.spi.transformer.AbstractJsonLdTransformer;
import org.eclipse.edc.policy.model.Action;
import org.eclipse.edc.policy.model.Constraint;
import org.eclipse.edc.policy.model.Duty;
import org.eclipse.edc.policy.model.Prohibition;
import org.eclipse.edc.transform.spi.TransformerContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_ACTION_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_CONSTRAINT_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_REMEDY_ATTRIBUTE;

/**
* Converts from an ODRL prohibition as a {@link JsonObject} in JSON-LD expanded form to a {@link Prohibition}.
Expand All @@ -39,15 +41,11 @@ public JsonObjectToProhibitionTransformer() {
public @Nullable Prohibition transform(@NotNull JsonObject object, @NotNull TransformerContext context) {
var builder = Prohibition.Builder.newInstance();

visitProperties(object, key -> {
switch (key) {
case ODRL_ACTION_ATTRIBUTE:
return value -> builder.action(transformObject(value, Action.class, context));
case ODRL_CONSTRAINT_ATTRIBUTE:
return value -> builder.constraints(transformArray(value, Constraint.class, context));
default:
return doNothing();
}
visitProperties(object, key -> switch (key) {
case ODRL_ACTION_ATTRIBUTE -> value -> builder.action(transformObject(value, Action.class, context));
case ODRL_CONSTRAINT_ATTRIBUTE -> value -> builder.constraints(transformArray(value, Constraint.class, context));
case ODRL_REMEDY_ATTRIBUTE -> value -> builder.remedies(transformArray(value, Duty.class, context));
default -> doNothing();
});

return builderResult(builder::build, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_TYPE_SET;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_PROHIBITION_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_REFINEMENT_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_REMEDY_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_RIGHT_OPERAND_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_TARGET_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_XONE_CONSTRAINT_ATTRIBUTE;
Expand Down Expand Up @@ -237,14 +238,17 @@ void transform_permissionWithConstraintAndDuty_returnJsonObject() {
void transform_prohibitionWithConstraint_returnJsonObject() {
var constraint = getConstraint();
var action = getAction();
var remedy = Duty.Builder.newInstance().action(Action.Builder.newInstance().type("remedyAction").build()).build();
var prohibition = Prohibition.Builder.newInstance()
.action(action)
.constraint(constraint)
.remedy(remedy)
.build();
var policy = Policy.Builder.newInstance().prohibition(prohibition).build();

var result = transformer.transform(policy, context);


assertThat(result).isNotNull();
var prohibitionJson = result.get(ODRL_PROHIBITION_ATTRIBUTE).asJsonArray().get(0).asJsonObject();
assertThat(prohibitionJson.getJsonArray(ODRL_CONSTRAINT_ATTRIBUTE)).hasSize(1);

Expand All @@ -255,6 +259,12 @@ void transform_prohibitionWithConstraint_returnJsonObject() {
.isEqualTo(constraint.getOperator().getOdrlRepresentation());
assertThat(constraintJson.getJsonObject(ODRL_RIGHT_OPERAND_ATTRIBUTE).getJsonString(VALUE).getString())
.isEqualTo(((LiteralExpression) constraint.getRightExpression()).getValue());

assertThat(prohibitionJson.getJsonArray(ODRL_REMEDY_ATTRIBUTE)).hasSize(1).first()
.extracting(JsonValue::asJsonObject).satisfies(remedyJson -> {
assertThat(remedyJson.getJsonObject(ODRL_ACTION_ATTRIBUTE).getString(ODRL_ACTION_TYPE_ATTRIBUTE))
.isEqualTo("remedyAction");
});

verify(context, never()).reportProblem(anyString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,18 @@
import org.eclipse.edc.policy.model.Action;
import org.eclipse.edc.policy.model.AtomicConstraint;
import org.eclipse.edc.policy.model.Constraint;
import org.eclipse.edc.policy.model.Duty;
import org.eclipse.edc.transform.spi.TransformerContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.Map;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.edc.core.transform.transformer.TestInput.getExpanded;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_ACTION_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_CONSTRAINT_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_CONSTRAINT_TYPE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_REMEDY_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_TARGET_ATTRIBUTE;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
Expand All @@ -43,59 +42,43 @@
import static org.mockito.Mockito.when;

class JsonObjectToProhibitionTransformerTest {
private static final String TARGET = "target";

private final TransformerContext context = mock(TransformerContext.class);

private final TransformerContext context = mock();
private final Action action = Action.Builder.newInstance().type("type").build();
private final Constraint constraint = AtomicConstraint.Builder.newInstance().build();

private JsonObjectToProhibitionTransformer transformer;
private final JsonObjectToProhibitionTransformer transformer = new JsonObjectToProhibitionTransformer();

@BeforeEach
void setUp() {
transformer = new JsonObjectToProhibitionTransformer();

when(context.transform(isA(JsonObject.class), eq(Action.class))).thenReturn(action);
when(context.transform(isA(JsonObject.class), eq(Constraint.class))).thenReturn(constraint);
}

@ParameterizedTest
@MethodSource("jsonSource")
void transform_attributesAsObjects_returnPermission(JsonObject prohibition) {
@Test
void transform_attributesAsObjects_returnPermission() {
var remedy = Duty.Builder.newInstance().build();
when(context.transform(isA(JsonObject.class), eq(Duty.class))).thenReturn(remedy);
var prohibition = Json.createObjectBuilder()
.add(ODRL_ACTION_ATTRIBUTE, Json.createObjectBuilder().add(TYPE, "Action"))
.add(ODRL_CONSTRAINT_ATTRIBUTE, Json.createObjectBuilder().add(TYPE, ODRL_CONSTRAINT_TYPE))
.add(ODRL_REMEDY_ATTRIBUTE, Json.createObjectBuilder().add(ODRL_ACTION_ATTRIBUTE, "remedyAction"))
.add(ODRL_TARGET_ATTRIBUTE, "target")
.build();

var result = transformer.transform(getExpanded(prohibition), context);

assertThat(result).isNotNull();
assertThat(result.getAction()).isEqualTo(action);
assertThat(result.getConstraints()).hasSize(1);
assertThat(result.getConstraints().get(0)).isEqualTo(constraint);
assertThat(result.getRemedies()).containsOnly(remedy);

verify(context, never()).reportProblem(anyString());
verify(context, times(1)).transform(isA(JsonObject.class), eq(Action.class));
verify(context, times(1)).transform(isA(JsonObject.class), eq(Constraint.class));
}

static Stream<JsonObject> jsonSource() {
var jsonFactory = Json.createBuilderFactory(Map.of());
var actionJson = jsonFactory.createObjectBuilder().add(TYPE, "action");
var constraintJson = jsonFactory.createObjectBuilder().add(TYPE, "constraint");

return Stream.of(
// object
jsonFactory.createObjectBuilder()
.add(ODRL_ACTION_ATTRIBUTE, actionJson)
.add(ODRL_CONSTRAINT_ATTRIBUTE, constraintJson)
.add(ODRL_TARGET_ATTRIBUTE, TARGET)
.build(),

// array version
jsonFactory.createObjectBuilder()
.add(ODRL_ACTION_ATTRIBUTE, jsonFactory.createArrayBuilder().add(actionJson))
.add(ODRL_CONSTRAINT_ATTRIBUTE, jsonFactory.createArrayBuilder().add(constraintJson))
.add(ODRL_TARGET_ATTRIBUTE, jsonFactory.createArrayBuilder().add(TARGET))
.build()

);
verify(context, times(1)).transform(isA(JsonObject.class), eq(Duty.class));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,27 @@

package org.eclipse.edc.policy.model;

import java.util.ArrayList;
import java.util.List;

import static java.util.stream.Collectors.joining;

/**
* Disallows an action if its constraints are satisfied.
*/
public class Prohibition extends Rule {

private final List<Duty> remedies = new ArrayList<>();

@Override
public <R> R accept(Visitor<R> visitor) {
return visitor.visitProhibition(this);
}

public List<Duty> getRemedies() {
return remedies;
}

@Override
public String toString() {
return "Prohibition constraints: [" + getConstraints().stream().map(Object::toString).collect(joining(",")) + "]";
Expand All @@ -42,6 +51,16 @@ public static Builder newInstance() {
return new Builder();
}

public Builder remedy(Duty remedy) {
rule.remedies.add(remedy);
return this;
}

public Builder remedies(List<Duty> remedies) {
rule.remedies.addAll(remedies);
return this;
}

public Prohibition build() {
return rule;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
import org.eclipse.edc.spi.asset.AssetIndex;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.spi.types.domain.asset.Asset;
import org.eclipse.edc.sql.testfixtures.PostgresqlEndToEndInstance;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.util.UUID;

Expand All @@ -38,6 +38,9 @@
import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX;
import static org.eclipse.edc.spi.query.Criterion.criterion;
import static org.eclipse.edc.sql.testfixtures.PostgresqlEndToEndInstance.createDatabase;
import static org.eclipse.edc.test.e2e.managementapi.Runtimes.inMemoryRuntime;
import static org.eclipse.edc.test.e2e.managementapi.Runtimes.postgresRuntime;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;

Expand All @@ -48,25 +51,30 @@ public class AssetApiEndToEndTest {

@Nested
@EndToEndTest
class InMemory extends Tests implements InMemoryRuntime {
class InMemory extends Tests {

@RegisterExtension
public static final EdcRuntimeExtension RUNTIME = inMemoryRuntime();

InMemory() {
super(RUNTIME);
}

}

@Nested
@PostgresqlIntegrationTest
class Postgres extends Tests implements PostgresRuntime {
class Postgres extends Tests {

@RegisterExtension
static final BeforeAllCallback CREATE_DATABASE = context -> createDatabase("runtime");

@RegisterExtension
public static final EdcRuntimeExtension RUNTIME = postgresRuntime();

Postgres() {
super(RUNTIME);
}

@BeforeAll
static void beforeAll() {
PostgresqlEndToEndInstance.createDatabase("runtime");
}
}

abstract static class Tests extends ManagementApiEndToEndTestBase {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
import org.eclipse.edc.spi.asset.AssetIndex;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.spi.types.domain.asset.Asset;
import org.eclipse.edc.sql.testfixtures.PostgresqlEndToEndInstance;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.util.UUID;

Expand All @@ -40,13 +40,19 @@
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX;
import static org.eclipse.edc.sql.testfixtures.PostgresqlEndToEndInstance.createDatabase;
import static org.eclipse.edc.test.e2e.managementapi.Runtimes.inMemoryRuntime;
import static org.eclipse.edc.test.e2e.managementapi.Runtimes.postgresRuntime;
import static org.hamcrest.Matchers.is;

public class CatalogApiEndToEndTest {

@Nested
@EndToEndTest
class InMemory extends Tests implements InMemoryRuntime {
class InMemory extends Tests {

@RegisterExtension
public static final EdcRuntimeExtension RUNTIME = inMemoryRuntime();

InMemory() {
super(RUNTIME);
Expand All @@ -56,17 +62,17 @@ class InMemory extends Tests implements InMemoryRuntime {

@Nested
@PostgresqlIntegrationTest
class Postgres extends Tests implements PostgresRuntime {
class Postgres extends Tests {

@RegisterExtension
static final BeforeAllCallback CREATE_DATABASE = context -> createDatabase("runtime");

@RegisterExtension
public static final EdcRuntimeExtension RUNTIME = postgresRuntime();

Postgres() {
super(RUNTIME);
}

@BeforeAll
static void beforeAll() {
PostgresqlEndToEndInstance.createDatabase("runtime");
}

}

abstract static class Tests extends ManagementApiEndToEndTestBase {
Expand Down
Loading
Loading