Skip to content

Commit

Permalink
fix: dspace 2024/1 compliant transformers
Browse files Browse the repository at this point in the history
  • Loading branch information
wolf4ood committed Oct 24, 2024
1 parent d708305 commit fe8c1b2
Show file tree
Hide file tree
Showing 38 changed files with 2,973 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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.transform.transformer.dspace.v2024.from;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.JsonBuilderFactory;
import jakarta.json.JsonObject;
import jakarta.json.stream.JsonCollectors;
import org.eclipse.edc.jsonld.spi.JsonLdNamespace;
import org.eclipse.edc.jsonld.spi.transformer.AbstractNamespaceAwareJsonLdTransformer;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.transform.spi.TransformerContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Set;

import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.jsonld.spi.Namespaces.DSPACE_SCHEMA_2024_1;
import static org.eclipse.edc.spi.types.domain.DataAddress.EDC_DATA_ADDRESS_TYPE_PROPERTY;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.DSPACE_DATAADDRESS_TYPE_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTIES_PROPERTY_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTY_NAME_PROPERTY_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTY_PROPERTY_TYPE_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_TYPE_PROPERTY_TERM;

public class JsonObjectFromDataAddressDspace2024Transformer extends AbstractNamespaceAwareJsonLdTransformer<DataAddress, JsonObject> {

private static final Set<String> EXCLUDED_PROPERTIES = Set.of(EDC_DATA_ADDRESS_TYPE_PROPERTY);
private final JsonBuilderFactory jsonFactory;
private final ObjectMapper mapper;

public JsonObjectFromDataAddressDspace2024Transformer(JsonBuilderFactory jsonFactory, ObjectMapper mapper) {
this(jsonFactory, mapper, new JsonLdNamespace(DSPACE_SCHEMA_2024_1));
}

public JsonObjectFromDataAddressDspace2024Transformer(JsonBuilderFactory jsonFactory, ObjectMapper mapper, JsonLdNamespace namespace) {
super(DataAddress.class, JsonObject.class, namespace);
this.jsonFactory = jsonFactory;
this.mapper = mapper;
}

@Override
public @Nullable JsonObject transform(@NotNull DataAddress dataAddress, @NotNull TransformerContext context) {
var endpointProperties = dataAddress.getProperties().entrySet().stream()
.filter(e -> !EXCLUDED_PROPERTIES.contains(e.getKey()))
.map(it -> endpointProperty(it.getKey(), it.getValue()))
.collect(JsonCollectors.toJsonArray());

return jsonFactory.createObjectBuilder()
.add(TYPE, forNamespace(DSPACE_DATAADDRESS_TYPE_TERM))
.add(forNamespace(ENDPOINT_TYPE_PROPERTY_TERM), id(jsonFactory, dataAddress.getType()))
.add(forNamespace(ENDPOINT_PROPERTIES_PROPERTY_TERM), endpointProperties)
.build();
}

private JsonObject endpointProperty(String key, Object value) {
var builder = jsonFactory.createObjectBuilder()
.add(TYPE, forNamespace(ENDPOINT_PROPERTY_PROPERTY_TYPE_TERM))
.add(forNamespace(ENDPOINT_PROPERTY_NAME_PROPERTY_TERM), key);

if (value instanceof String stringVal) {
builder.add(forNamespace(ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM), stringVal);
} else {
builder.add(forNamespace(ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM), mapper.convertValue(value, JsonObject.class));
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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.transform.transformer.dspace.v2024.from;

import jakarta.json.Json;
import org.eclipse.edc.jsonld.spi.JsonLdNamespace;
import org.eclipse.edc.jsonld.util.JacksonJsonLd;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.transform.spi.TransformerContext;
import org.junit.jupiter.api.Test;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
import static org.eclipse.edc.jsonld.spi.Namespaces.DSPACE_SCHEMA_2024_1;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTIES_PROPERTY_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTY_NAME_PROPERTY_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTY_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM;
import static org.eclipse.edc.transform.transformer.dspace.DataAddressDspaceSerialization.ENDPOINT_TYPE_PROPERTY_TERM;
import static org.mockito.Mockito.mock;

class JsonObjectFromDataAddressDspace2024TransformerTest {

private final JsonObjectFromDataAddressDspace2024Transformer transformer = new JsonObjectFromDataAddressDspace2024Transformer(
Json.createBuilderFactory(Map.of()), JacksonJsonLd.createObjectMapper());
private final TransformerContext context = mock();


private final JsonLdNamespace namespace = new JsonLdNamespace(DSPACE_SCHEMA_2024_1);

@Test
void transform() {
var dataAddress = DataAddress.Builder.newInstance()
.type("https://w3id.org/idsa/v4.1/HTTP")
.property("endpoint", "https://example.com")
.property("authorization", "secret-token")
.property("foo", "bar")
.build();

var jsonObject = transformer.transform(dataAddress, context);

assertThat(jsonObject).isNotNull();
assertThat(jsonObject.getJsonObject(namespace.toIri(ENDPOINT_TYPE_PROPERTY_TERM)).getString(ID)).isEqualTo("https://w3id.org/idsa/v4.1/HTTP");
assertThat(jsonObject.get(namespace.toIri(ENDPOINT_PROPERTY_TERM))).isEqualTo(null);
assertThat(jsonObject.getJsonArray(namespace.toIri(ENDPOINT_PROPERTIES_PROPERTY_TERM))).hasSize(3)
.anySatisfy(jv -> {
assertThat(jv.asJsonObject().getString(namespace.toIri(ENDPOINT_PROPERTY_NAME_PROPERTY_TERM))).isEqualTo("authorization");
assertThat(jv.asJsonObject().getString(namespace.toIri(ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM))).isEqualTo("secret-token");
}).anySatisfy(jv -> {
assertThat(jv.asJsonObject().getString(namespace.toIri(ENDPOINT_PROPERTY_NAME_PROPERTY_TERM))).isEqualTo("foo");
assertThat(jv.asJsonObject().getString(namespace.toIri(ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM))).isEqualTo("bar");
})
.anySatisfy(jv -> {
assertThat(jv.asJsonObject().getString(namespace.toIri(ENDPOINT_PROPERTY_NAME_PROPERTY_TERM))).isEqualTo("endpoint");
assertThat(jv.asJsonObject().getString(namespace.toIri(ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM))).isEqualTo("https://example.com");
});
}

@Test
void transform_withComplexProperty() {
var dataAddress = DataAddress.Builder.newInstance()
.type("https://w3id.org/idsa/v4.1/HTTP")
.property("endpoint", "https://example.com")
.property("authorization", "secret-token")
.property("foo", Map.of("complexObj", Map.of("key1", "value1", "key2", Map.of("key3", "value3"))))
.build();

var jsonObject = transformer.transform(dataAddress, context);

assertThat(jsonObject).isNotNull();
assertThat(jsonObject.getJsonArray(namespace.toIri(ENDPOINT_PROPERTIES_PROPERTY_TERM)))
.anySatisfy(jv -> {
assertThat(jv.asJsonObject().getString(namespace.toIri(ENDPOINT_PROPERTY_NAME_PROPERTY_TERM))).isEqualTo("foo");
assertThat(jv.asJsonObject().getJsonObject(namespace.toIri(ENDPOINT_PROPERTY_VALUE_PROPERTY_TERM)))
.containsKey("complexObj");
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.eclipse.edc.protocol.dsp.catalog.transform.from.JsonObjectFromDatasetTransformer;
import org.eclipse.edc.protocol.dsp.catalog.transform.from.JsonObjectFromDistributionTransformer;
import org.eclipse.edc.protocol.dsp.catalog.transform.to.JsonObjectToCatalogRequestMessageTransformer;
import org.eclipse.edc.protocol.dsp.catalog.transform.v2024.from.JsonObjectFromCatalogV2024Transformer;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.system.ServiceExtension;
Expand Down Expand Up @@ -66,8 +67,13 @@ public String name() {
public void initialize(ServiceExtensionContext context) {
var mapper = typeManager.getMapper(JSON_LD);

registerV08Transformers(mapper);
registerV2024Transformers(mapper);

registerTransformers(DSP_TRANSFORMER_CONTEXT_V_08, DSP_NAMESPACE_V_08, mapper);
registerTransformers(DSP_TRANSFORMER_CONTEXT_V_2024_1, DSP_NAMESPACE_V_2024_1, mapper);


}

private void registerTransformers(String version, JsonLdNamespace namespace, ObjectMapper mapper) {
Expand All @@ -77,10 +83,22 @@ private void registerTransformers(String version, JsonLdNamespace namespace, Obj
dspApiTransformerRegistry.register(new JsonObjectFromCatalogRequestMessageTransformer(jsonFactory, namespace));
dspApiTransformerRegistry.register(new JsonObjectToCatalogRequestMessageTransformer(namespace));

dspApiTransformerRegistry.register(new JsonObjectFromCatalogTransformer(jsonFactory, mapper, participantIdMapper, namespace));
dspApiTransformerRegistry.register(new JsonObjectFromDatasetTransformer(jsonFactory, mapper));
dspApiTransformerRegistry.register(new JsonObjectFromDistributionTransformer(jsonFactory));
dspApiTransformerRegistry.register(new JsonObjectFromDataServiceTransformer(jsonFactory));
dspApiTransformerRegistry.register(new JsonObjectFromCatalogErrorTransformer(jsonFactory, namespace));
}

private void registerV08Transformers(ObjectMapper mapper) {
var jsonFactory = Json.createBuilderFactory(Map.of());
var dspApiTransformerRegistry = registry.forContext(DSP_TRANSFORMER_CONTEXT_V_08);
dspApiTransformerRegistry.register(new JsonObjectFromCatalogTransformer(jsonFactory, mapper, participantIdMapper, DSP_NAMESPACE_V_08));

}

private void registerV2024Transformers(ObjectMapper mapper) {
var jsonFactory = Json.createBuilderFactory(Map.of());
var dspApiTransformerRegistry = registry.forContext(DSP_TRANSFORMER_CONTEXT_V_2024_1);
dspApiTransformerRegistry.register(new JsonObjectFromCatalogV2024Transformer(jsonFactory, mapper, participantIdMapper, DSP_NAMESPACE_V_2024_1));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2023 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.protocol.dsp.catalog.transform.v2024.from;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.JsonBuilderFactory;
import jakarta.json.JsonObject;
import org.eclipse.edc.connector.controlplane.catalog.spi.Catalog;
import org.eclipse.edc.jsonld.spi.JsonLdNamespace;
import org.eclipse.edc.jsonld.spi.transformer.AbstractNamespaceAwareJsonLdTransformer;
import org.eclipse.edc.participant.spi.ParticipantIdMapper;
import org.eclipse.edc.transform.spi.TransformerContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static jakarta.json.stream.JsonCollectors.toJsonArray;
import static java.util.Optional.ofNullable;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_CATALOG_TYPE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATA_SERVICE_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DISTRIBUTION_ATTRIBUTE;
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DSPACE_PROPERTY_PARTICIPANT_ID_TERM;
import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_NAMESPACE_V_2024_1;

/**
* Converts from a {@link Catalog} to a DCAT catalog as a {@link JsonObject} in JSON-LD expanded form.
*/
public class JsonObjectFromCatalogV2024Transformer extends AbstractNamespaceAwareJsonLdTransformer<Catalog, JsonObject> {
private final JsonBuilderFactory jsonFactory;
private final ObjectMapper mapper;
private final ParticipantIdMapper participantIdMapper;

public JsonObjectFromCatalogV2024Transformer(JsonBuilderFactory jsonFactory, ObjectMapper mapper, ParticipantIdMapper participantIdMapper) {
this(jsonFactory, mapper, participantIdMapper, DSP_NAMESPACE_V_2024_1);
}

public JsonObjectFromCatalogV2024Transformer(JsonBuilderFactory jsonFactory, ObjectMapper mapper, ParticipantIdMapper participantIdMapper, JsonLdNamespace namespace) {
super(Catalog.class, JsonObject.class, namespace);
this.jsonFactory = jsonFactory;
this.mapper = mapper;
this.participantIdMapper = participantIdMapper;
}

@Override
public @Nullable JsonObject transform(@NotNull Catalog catalog, @NotNull TransformerContext context) {
var datasets = catalog.getDatasets().stream()
.map(offer -> context.transform(offer, JsonObject.class))
.collect(toJsonArray());

var dataServices = catalog.getDataServices().stream()
.map(service -> context.transform(service, JsonObject.class))
.collect(toJsonArray());

var distributions = catalog.getDistributions().stream()
.map(distro -> context.transform(distro, JsonObject.class))
.collect(toJsonArray());

var objectBuilder = jsonFactory.createObjectBuilder()
.add(ID, catalog.getId())
.add(TYPE, DCAT_CATALOG_TYPE)
.add(DCAT_DATASET_ATTRIBUTE, datasets)
.add(DCAT_DISTRIBUTION_ATTRIBUTE, distributions)
.add(DCAT_DATA_SERVICE_ATTRIBUTE, dataServices);

ofNullable(catalog.getParticipantId()).ifPresent(pid -> objectBuilder.add(forNamespace(DSPACE_PROPERTY_PARTICIPANT_ID_TERM), id(jsonFactory, participantIdMapper.toIri(pid))));

transformProperties(catalog.getProperties(), objectBuilder, mapper, context);

return objectBuilder.build();
}
}
Loading

0 comments on commit fe8c1b2

Please sign in to comment.