Skip to content

Commit

Permalink
fix: assignee and assigner serialization as @id
Browse files Browse the repository at this point in the history
  • Loading branch information
wolf4ood committed Nov 21, 2024
1 parent 4819c8e commit 29bf34a
Show file tree
Hide file tree
Showing 15 changed files with 350 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static java.lang.String.format;

public class TypeTransformerRegistryImpl implements TypeTransformerRegistry {
private final Map<String, Class<?>> aliases = new HashMap<>();
private final List<TypeTransformer<?, ?>> transformers = new ArrayList<>();
private final Map<String, TypeTransformerRegistry> contextRegistries = new HashMap<>();
private TypeTransformerRegistry parent;

public TypeTransformerRegistryImpl() {
}

private TypeTransformerRegistryImpl(TypeTransformerRegistry parent) {
this.parent = parent;
}

@Override
public void register(TypeTransformer<?, ?> transformer) {
Expand All @@ -40,7 +49,7 @@ public void register(TypeTransformer<?, ?> transformer) {

@Override
public @NotNull TypeTransformerRegistry forContext(String context) {
return contextRegistries.computeIfAbsent(context, k -> new ContextTransformerRegistry(this));
return contextRegistries.computeIfAbsent(context, k -> new TypeTransformerRegistryImpl(this));
}

@Override
Expand All @@ -49,6 +58,7 @@ public void register(TypeTransformer<?, ?> transformer) {
.filter(t -> t.getInputType().isInstance(input) && t.getOutputType().equals(outputType))
.findAny()
.map(it -> (TypeTransformer<INPUT, OUTPUT>) it)
.or(() -> Optional.ofNullable(parent).map(p -> p.transformerFor(input, outputType)))
.orElseThrow(() -> new EdcException(format("No Transformer registered that can handle %s -> %s", input.getClass(), outputType)));
}

Expand All @@ -66,26 +76,4 @@ public <INPUT, OUTPUT> Result<OUTPUT> transform(@NotNull INPUT input, @NotNull C
}
}

private static class ContextTransformerRegistry extends TypeTransformerRegistryImpl {

private final TypeTransformerRegistry parent;

ContextTransformerRegistry(TypeTransformerRegistry parent) {
this.parent = parent;
}

@Override
public @NotNull TypeTransformerRegistry forContext(String context) {
throw new EdcException("'forContext' cannot be called on ContextTransformerRegistry, please refer to the generic TypeTransformerRegistry");
}

@Override
public @NotNull <INPUT, OUTPUT> TypeTransformer<INPUT, OUTPUT> transformerFor(@NotNull INPUT input, @NotNull Class<OUTPUT> outputType) {
try {
return super.transformerFor(input, outputType);
} catch (EdcException e) {
return parent.transformerFor(input, outputType);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.eclipse.edc.transform;

import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.transform.spi.TypeTransformer;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
Expand All @@ -23,6 +24,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;

public class TypeTransformerRegistryImplTest {

Expand Down Expand Up @@ -75,9 +78,31 @@ void shouldReturnRegistryForSpecificContext() {
}

@Test
void shouldThrowException_whenForContextIsCalled() {
assertThatThrownBy(() -> contextRegistry.forContext("any")).isInstanceOf(EdcException.class);
void shouldReturnRegistryForSpecificNestedContext() {
var nestedContextRegistry = contextRegistry.forContext("nestedContext");
nestedContextRegistry.register(new IntegerStringTypeTransformer());

assertThat(nestedContextRegistry.transform(5, String.class))
.isSucceeded().isEqualTo("5");
assertThatThrownBy(() -> contextRegistry.transform(5, String.class)).isInstanceOf(EdcException.class);
assertThatThrownBy(() -> registry.transform(5, String.class)).isInstanceOf(EdcException.class);
}

@Test
void shouldTransformUsingNestedContext() {
var nestedContextRegistry = contextRegistry.forContext("nestedContext");
nestedContextRegistry.register(new IntegerStringTypeTransformer());

TypeTransformer<Integer, String> typeTransformer = mock();
contextRegistry.register(typeTransformer);
registry.register(typeTransformer);

assertThat(nestedContextRegistry.transform(5, String.class))
.isSucceeded().isEqualTo("5");

verifyNoInteractions(typeTransformer);
}

}

@Nested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import jakarta.json.JsonBuilderFactory;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.JsonValue;
import org.eclipse.edc.jsonld.spi.transformer.AbstractJsonLdTransformer;
import org.eclipse.edc.participant.spi.ParticipantIdMapper;
import org.eclipse.edc.policy.model.Action;
Expand Down Expand Up @@ -76,16 +77,22 @@
public class JsonObjectFromPolicyTransformer extends AbstractJsonLdTransformer<Policy, JsonObject> {
private final JsonBuilderFactory jsonFactory;
private final ParticipantIdMapper participantIdMapper;
private final boolean participantsAsId;

public JsonObjectFromPolicyTransformer(JsonBuilderFactory jsonFactory, ParticipantIdMapper participantIdMapper) {
this(jsonFactory, participantIdMapper, false);
}

public JsonObjectFromPolicyTransformer(JsonBuilderFactory jsonFactory, ParticipantIdMapper participantIdMapper, boolean participantsAsId) {
super(Policy.class, JsonObject.class);
this.jsonFactory = jsonFactory;
this.participantIdMapper = participantIdMapper;
this.participantsAsId = participantsAsId;
}

@Override
public @Nullable JsonObject transform(@NotNull Policy policy, @NotNull TransformerContext context) {
return policy.accept(new Visitor(jsonFactory, participantIdMapper));
return policy.accept(new Visitor(jsonFactory, participantIdMapper, participantsAsId));
}

/**
Expand All @@ -94,10 +101,12 @@ public JsonObjectFromPolicyTransformer(JsonBuilderFactory jsonFactory, Participa
private static class Visitor implements Policy.Visitor<JsonObject>, Rule.Visitor<JsonObject>, Constraint.Visitor<JsonObject>, Expression.Visitor<JsonObject> {
private final JsonBuilderFactory jsonFactory;
private final ParticipantIdMapper participantIdMapper;
private final boolean participantsAsId;

Visitor(JsonBuilderFactory jsonFactory, ParticipantIdMapper participantIdMapper) {
Visitor(JsonBuilderFactory jsonFactory, ParticipantIdMapper participantIdMapper, boolean participantsAsId) {
this.jsonFactory = jsonFactory;
this.participantIdMapper = participantIdMapper;
this.participantsAsId = participantsAsId;
}

@Override
Expand All @@ -115,19 +124,6 @@ public JsonObject visitXoneConstraint(XoneConstraint xoneConstraint) {
return visitMultiplicityConstraint(ODRL_XONE_CONSTRAINT_ATTRIBUTE, xoneConstraint);
}

private JsonObject visitMultiplicityConstraint(String operandType, MultiplicityConstraint multiplicityConstraint) {
var constraintsBuilder = jsonFactory.createArrayBuilder();
for (var constraint : multiplicityConstraint.getConstraints()) {
Optional.of(constraint)
.map(c -> c.accept(this))
.ifPresent(constraintsBuilder::add);
}

return jsonFactory.createObjectBuilder()
.add(operandType, constraintsBuilder.build())
.build();
}

@Override
public JsonObject visitAtomicConstraint(AtomicConstraint atomicConstraint) {
var constraintBuilder = jsonFactory.createObjectBuilder();
Expand Down Expand Up @@ -166,8 +162,8 @@ public JsonObject visitPolicy(Policy policy) {
.add(ODRL_PROHIBITION_ATTRIBUTE, prohibitionsBuilder)
.add(ODRL_OBLIGATION_ATTRIBUTE, obligationsBuilder);

Optional.ofNullable(policy.getAssignee()).map(participantIdMapper::toIri).ifPresent(it -> builder.add(ODRL_ASSIGNEE_ATTRIBUTE, it));
Optional.ofNullable(policy.getAssigner()).map(participantIdMapper::toIri).ifPresent(it -> builder.add(ODRL_ASSIGNER_ATTRIBUTE, it));
Optional.ofNullable(policy.getAssignee()).map(participantIdMapper::toIri).ifPresent(it -> builder.add(ODRL_ASSIGNEE_ATTRIBUTE, visitParticipantId(it)));
Optional.ofNullable(policy.getAssigner()).map(participantIdMapper::toIri).ifPresent(it -> builder.add(ODRL_ASSIGNER_ATTRIBUTE, visitParticipantId(it)));

Optional.ofNullable(policy.getTarget())
.ifPresent(target -> builder.add(
Expand Down Expand Up @@ -219,6 +215,27 @@ public JsonObject visitDuty(Duty duty) {
return obligationBuilder.build();
}

private JsonValue visitParticipantId(String participantId) {
if (participantsAsId) {
return jsonFactory.createObjectBuilder().add(ID, participantId).build();
} else {
return Json.createValue(participantId);
}
}

private JsonObject visitMultiplicityConstraint(String operandType, MultiplicityConstraint multiplicityConstraint) {
var constraintsBuilder = jsonFactory.createArrayBuilder();
for (var constraint : multiplicityConstraint.getConstraints()) {
Optional.of(constraint)
.map(c -> c.accept(this))
.ifPresent(constraintsBuilder::add);
}

return jsonFactory.createObjectBuilder()
.add(operandType, constraintsBuilder.build())
.build();
}

private JsonObjectBuilder visitRule(Rule rule) {
var ruleBuilder = jsonFactory.createObjectBuilder();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,23 @@ void transform_xoneConstraint_returnJsonObject() {
verify(context, never()).reportProblem(anyString());
}

@Test
void transform_assigneeAndAssignerAsIds() {
var transformer = new JsonObjectFromPolicyTransformer(jsonFactory, participantIdMapper, true);
var policy = Policy.Builder.newInstance()
.target("target")
.assignee("assignee")
.assigner("assigner")
.build();

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

assertThat(result.getJsonObject(ODRL_ASSIGNEE_ATTRIBUTE).getString(ID)).isEqualTo("assignee");
assertThat(result.getJsonObject(ODRL_ASSIGNER_ATTRIBUTE).getString(ID)).isEqualTo("assigner");

verify(context, never()).reportProblem(anyString());
}

@ParameterizedTest
@ArgumentsSource(PolicyTypeToOdrl.class)
void shouldMapPolicyTypeToOdrlType(PolicyType type, String expectedType) {
Expand All @@ -383,18 +400,6 @@ void shouldMapPolicyTypeToOdrlType(PolicyType type, String expectedType) {
assertThat(result.getString(TYPE)).isEqualTo(expectedType);
}

private static class PolicyTypeToOdrl implements ArgumentsProvider {

@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
return Stream.of(
arguments(SET, ODRL_POLICY_TYPE_SET),
arguments(OFFER, ODRL_POLICY_TYPE_OFFER),
arguments(CONTRACT, ODRL_POLICY_TYPE_AGREEMENT)
);
}
}

private Action getAction() {
return Action.Builder.newInstance().type("use").build();
}
Expand All @@ -406,4 +411,16 @@ private AtomicConstraint getConstraint() {
.rightExpression(new LiteralExpression("right"))
.build();
}

private static class PolicyTypeToOdrl implements ArgumentsProvider {

@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
return Stream.of(
arguments(SET, ODRL_POLICY_TYPE_SET),
arguments(OFFER, ODRL_POLICY_TYPE_OFFER),
arguments(CONTRACT, ODRL_POLICY_TYPE_AGREEMENT)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,17 @@
public class DspApiConfigurationExtension implements ServiceExtension {

public static final String NAME = "Dataspace Protocol API Configuration Extension";

@Setting(description = "Configures endpoint for reaching the Protocol API in the form \"<hostname:protocol.port/protocol.path>\"", key = "edc.dsp.callback.address", required = false)
private String callbackAddress;

@SettingContext("Protocol API context setting key")
private static final String PROTOCOL_CONFIG_KEY = "web.http." + ApiContext.PROTOCOL;

public static final WebServiceSettings SETTINGS = WebServiceSettings.Builder.newInstance()
.apiConfigKey(PROTOCOL_CONFIG_KEY)
.contextAlias(ApiContext.PROTOCOL)
.defaultPath("/api/v1/dsp")
.defaultPort(8282)
.name("Protocol API")
.build();

@Setting(description = "Configures endpoint for reaching the Protocol API in the form \"<hostname:protocol.port/protocol.path>\"", key = "edc.dsp.callback.address", required = false)
private String callbackAddress;
@Inject
private TypeManager typeManager;
@Inject
Expand Down Expand Up @@ -158,7 +154,6 @@ private void registerTransformers(String version, JsonLdNamespace dspNamespace,

// EDC model to JSON-LD transformers
var dspApiTransformerRegistry = transformerRegistry.forContext(version);
dspApiTransformerRegistry.register(new JsonObjectFromPolicyTransformer(jsonBuilderFactory, participantIdMapper));
dspApiTransformerRegistry.register(new JsonObjectFromAssetTransformer(jsonBuilderFactory, mapper));
dspApiTransformerRegistry.register(new JsonObjectFromQuerySpecTransformer(jsonBuilderFactory));
dspApiTransformerRegistry.register(new JsonObjectFromCriterionTransformer(jsonBuilderFactory, mapper));
Expand All @@ -181,6 +176,7 @@ private void registerV08Transformers(ObjectMapper mapper) {
// EDC model to JSON-LD transformers
var dspApiTransformerRegistry = transformerRegistry.forContext(DSP_TRANSFORMER_CONTEXT_V_08);

dspApiTransformerRegistry.register(new JsonObjectFromPolicyTransformer(jsonBuilderFactory, participantIdMapper));
dspApiTransformerRegistry.register(new JsonObjectFromDataAddressDspaceTransformer(jsonBuilderFactory, mapper));

}
Expand All @@ -191,6 +187,7 @@ private void registerV2024Transformers(ObjectMapper mapper) {
// EDC model to JSON-LD transformers
var dspApiTransformerRegistry = transformerRegistry.forContext(DSP_TRANSFORMER_CONTEXT_V_2024_1);

dspApiTransformerRegistry.register(new JsonObjectFromPolicyTransformer(jsonBuilderFactory, participantIdMapper, true));
dspApiTransformerRegistry.register(new JsonObjectFromDataAddressDspace2024Transformer(jsonBuilderFactory, mapper));

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.api.management;

public interface ManagementApi {

String MANAGEMENT_API_CONTEXT = "management-api";

String MANAGEMENT_API_V_3_1_ALPHA = "v3.1-alpha";
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@

import static java.lang.String.format;
import static java.util.Optional.ofNullable;
import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_API_CONTEXT;
import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_API_V_3_1_ALPHA;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_PREFIX;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA;
Expand Down Expand Up @@ -92,12 +94,9 @@ public class ManagementApiConfigurationExtension implements ServiceExtension {
.useDefaultContext(true)
.name(WEB_SERVICE_NAME)
.build();

private static final boolean DEFAULT_MANAGEMENT_API_ENABLE_CONTEXT = false;
@Setting(description = "Configures endpoint for reaching the Management API, in the format \"<hostname:management.port/management.path>\"", key = "edc.management.endpoint", required = false)
private String managementApiEndpoint;

private static final boolean DEFAULT_MANAGEMENT_API_ENABLE_CONTEXT = false;

@Setting(description = "If set enable the usage of management api JSON-LD context.", defaultValue = "" + DEFAULT_MANAGEMENT_API_ENABLE_CONTEXT, key = "edc.management.context.enabled")
private boolean managementApiContextEnabled;

Expand Down Expand Up @@ -150,7 +149,7 @@ public void initialize(ServiceExtensionContext context) {
webService.registerResource(ApiContext.MANAGEMENT, new ObjectMapperProvider(jsonLdMapper));
webService.registerResource(ApiContext.MANAGEMENT, new JerseyJsonLdInterceptor(jsonLd, jsonLdMapper, MANAGEMENT_SCOPE));

var managementApiTransformerRegistry = transformerRegistry.forContext("management-api");
var managementApiTransformerRegistry = transformerRegistry.forContext(MANAGEMENT_API_CONTEXT);

var factory = Json.createBuilderFactory(Map.of());
managementApiTransformerRegistry.register(new JsonObjectFromContractAgreementTransformer(factory));
Expand All @@ -167,6 +166,10 @@ public void initialize(ServiceExtensionContext context) {
managementApiTransformerRegistry.register(new JsonObjectToAssetTransformer());
managementApiTransformerRegistry.register(new JsonValueToGenericTypeTransformer(jsonLdMapper));

var managementApiTransformerRegistryV31Alpha = managementApiTransformerRegistry.forContext(MANAGEMENT_API_V_3_1_ALPHA);

managementApiTransformerRegistryV31Alpha.register(new JsonObjectFromPolicyTransformer(factory, participantIdMapper, true));

registerVersionInfo(getClass().getClassLoader());
}

Expand Down
Loading

0 comments on commit 29bf34a

Please sign in to comment.