Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Christophe '116' Loiseau authored and ununhexium committed Feb 22, 2024
1 parent 3b42ce9 commit 266efee
Show file tree
Hide file tree
Showing 17 changed files with 224 additions and 38 deletions.
13 changes: 13 additions & 0 deletions docs/sovity-edc-api-wrapper.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,10 @@ components:
JSON values)
description: Private Asset Properties (that are not strings but other JSON
values)
customJsonAsString:
type: string
description: "Contains custom properties as serialized JSON object.This\
\ string must represent a JSON _object_ (no array, scalar nor null)."
description: Type-Safe OpenAPI generator friendly Asset Create DTO that supports
an opinionated subset of the original EDC Asset Entity.
IdResponseDto:
Expand Down Expand Up @@ -867,6 +871,11 @@ components:
JSON values)
description: Private Asset Properties (that are not strings but other JSON
values)
customJsonAsString:
type: string
description: "Contains all the custom properties in the JSON format serialized\
\ in a JSON string.This string must represent a JSON object.The types\
\ array, number, string, null are not supported."
description: Data for editing an asset.
AssetPage:
required:
Expand Down Expand Up @@ -1041,6 +1050,10 @@ components:
assetJsonLd:
type: string
description: Contains the entire asset in the JSON-LD format
customJsonAsString:
type: string
description: "Contains custom properties as serialized JSON object.This\
\ string must represent a JSON _object_ (no array, scalar nor null)."
description: Type-Safe Asset Metadata as needed by our UI
UiContractOffer:
required:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,28 @@ public class UiAsset {
@Schema(description = "Temporal coverage end date (inclusive)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private LocalDate temporalCoverageToInclusive;

// TODO: rm
@Schema(description = "Unhandled Asset Properties (that were strings)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> additionalProperties;

// TODO: rm
@Schema(description = "Unhandled Asset Properties (that were not strings but other JSON values)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> additionalJsonProperties;

// TODO: rm
@Schema(description = "Private Asset Properties (that were strings)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> privateProperties;

// TODO: rm
@Schema(description = "Private Asset Properties (that were not strings but other JSON values)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> privateJsonProperties;

@Schema(description = "Contains the entire asset in the JSON-LD format", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private String assetJsonLd;

@Schema(description = "Contains custom properties as serialized JSON object." +
"This string must represent a JSON _object_ (no array, scalar nor null).",
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
// TODO: try to make this a map so at least we can easily access the properties
private String customJsonAsString;
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,25 @@ public class UiAssetCreateRequest {
@Schema(description = "Data Address", requiredMode = Schema.RequiredMode.REQUIRED)
private Map<String, String> dataAddressProperties;

// TODO: rm
@Schema(description = "Custom Asset Properties (that are strings)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> additionalProperties;

// TODO: rm
@Schema(description = "Custom Asset Properties (that are not strings but other JSON values)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> additionalJsonProperties;

// TODO: rm
@Schema(description = "Private Asset Properties (that are strings)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> privateProperties;

// TODO: rm
@Schema(description = "Private Asset Properties (that are not strings but other JSON values)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> privateJsonProperties;

@Schema(description = "Contains custom properties as serialized JSON object." +
"This string must represent a JSON _object_ (no array, scalar nor null).",
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
// TODO: try to make this a map so at least we can easily access the properties
private String customJsonAsString;
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,26 @@ public class UiAssetEditMetadataRequest {
@Schema(description = "Temporal coverage end date (inclusive)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private LocalDate temporalCoverageToInclusive;

// TODO: rm
@Schema(description = "Custom Asset Properties (that are strings)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> additionalProperties;

// TODO: rm
@Schema(description = "Custom Asset Properties (that are not strings but other JSON values)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> additionalJsonProperties;

// TODO: rm
@Schema(description = "Private Asset Properties (that are strings)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> privateProperties;

// TODO: rm
@Schema(description = "Private Asset Properties (that are not strings but other JSON values)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private Map<String, String> privateJsonProperties;

@Schema(description = "Contains all the custom properties in the JSON format serialized in a JSON string." +
"This string must represent a JSON object." +
"The types array, number, string, null are not supported.",
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
// TODO: try to make this a map so at least we can easily access the properties
private String customJsonAsString;
}
5 changes: 3 additions & 2 deletions extensions/wrapper/wrapper-common-mappers/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ dependencies {
testAnnotationProcessor("org.projectlombok:lombok:${lombokVersion}")
testCompileOnly("org.projectlombok:lombok:${lombokVersion}")
testImplementation("${edcGroup}:json-ld:${edcVersion}")
testImplementation("net.javacrumbs.json-unit:json-unit-assertj:3.2.7")
testImplementation("org.assertj:assertj-core:${assertj}")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testImplementation("org.mockito:mockito-core:${mockitoVersion}")
testImplementation("org.mockito:mockito-inline:${mockitoVersion}")
testImplementation("org.mockito:mockito-junit-jupiter:${mockitoVersion}")
testImplementation("org.assertj:assertj-core:${assertj}")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ protected static JsonObjectBuilder addNonNullJsonValue(JsonObjectBuilder builder
builder.add(key, value);
return builder;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import jakarta.json.JsonValue;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.val;
import org.jetbrains.annotations.Nullable;

import java.util.List;
Expand Down Expand Up @@ -102,6 +103,9 @@ public UiAsset buildUiAsset(JsonObject assetJsonLd, String connectorEndpoint, St

// Additional / Remaining Properties
// TODO: diff nested objects
// TODO: the remaining JSON LD props
// Let users see the JsonLd that was not handled by the UiAsset class.
// Put those properties in customJsonLd.
JsonObject remaining = removeHandledProperties(properties, List.of(
// Implicitly handled / should be skipped if found
Prop.ID,
Expand Down Expand Up @@ -142,14 +146,26 @@ public UiAsset buildUiAsset(JsonObject assetJsonLd, String connectorEndpoint, St
HttpDatasourceHints.PATH,
HttpDatasourceHints.QUERY_PARAMS
));

// TODO this must go away
uiAsset.setAdditionalProperties(getStringProperties(remaining));
// TODO this must go away
uiAsset.setAdditionalJsonProperties(getJsonProperties(remaining));

// Private Properties
// TODO this must go away
var privateProperties = JsonLdUtils.tryCompact(getPrivateProperties(assetJsonLd));
uiAsset.setPrivateProperties(getStringProperties(privateProperties));
uiAsset.setPrivateJsonProperties(getJsonProperties(privateProperties));

// TODO must extract the string properties from CUSTOM_JSON and puts them in
// de.sovity.edc.ext.wrapper.api.common.model.UiAsset.customJson

// TODO: do I support only object or arbitrary json values?
// TODO add postman example for this
val customJsonAsString = JsonLdUtils.string(remaining, Prop.SovityDcatExt.CUSTOM_JSON);
uiAsset.setCustomJsonAsString(customJsonAsString);

return uiAsset;
}

Expand Down Expand Up @@ -213,13 +229,14 @@ private JsonObjectBuilder getAssetProperties(
.add(Prop.Foaf.NAME, organizationName));

var dataAddress = uiAssetCreateRequest.getDataAddressProperties();
if (dataAddress.get(Prop.Edc.TYPE).equals("HttpData")) {
if (dataAddress != null && dataAddress.get(Prop.Edc.TYPE).equals("HttpData")) {
addNonNull(properties, HttpDatasourceHints.BODY, trueIfTrue(dataAddress, Prop.Edc.PROXY_BODY));
addNonNull(properties, HttpDatasourceHints.PATH, trueIfTrue(dataAddress, Prop.Edc.PROXY_PATH));
addNonNull(properties, HttpDatasourceHints.QUERY_PARAMS, trueIfTrue(dataAddress, Prop.Edc.PROXY_QUERY_PARAMS));
addNonNull(properties, HttpDatasourceHints.METHOD, trueIfTrue(dataAddress, Prop.Edc.PROXY_METHOD));
}

// TODO: these blocks must be replaced by extracting the sovity:customJson strings props
var additionalProperties = uiAssetCreateRequest.getAdditionalProperties();
if (additionalProperties != null) {
additionalProperties.forEach((k, v) -> addNonNull(properties, k, v));
Expand All @@ -230,6 +247,10 @@ private JsonObjectBuilder getAssetProperties(
additionalJsonProperties.forEach((k, v) -> addNonNullJsonValue(properties, k, v));
}

// TODO: merge customJsonLd with the customProperties here

addNonNull(properties, Prop.SovityDcatExt.CUSTOM_JSON, uiAssetCreateRequest.getCustomJsonAsString());

return properties;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@
import de.sovity.edc.utils.JsonUtils;
import de.sovity.edc.utils.jsonld.vocab.Prop;
import lombok.SneakyThrows;
import net.javacrumbs.jsonunit.assertj.JsonAssertions;
import org.eclipse.edc.core.transform.TypeTransformerRegistryImpl;
import org.eclipse.edc.jsonld.TitaniumJsonLd;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static jakarta.json.Json.createArrayBuilder;
import static jakarta.json.Json.createObjectBuilder;
Expand All @@ -34,7 +32,7 @@ class AssetMapperTest {
@BeforeEach
void setup() {
var jsonLd = new TitaniumJsonLd(mock(Monitor.class));
var typeTransformerRegistry = mock(TypeTransformerRegistry.class);
var typeTransformerRegistry = mock(TypeTransformerRegistryImpl.class);
var uiAssetBuilder = new UiAssetMapper(new EdcPropertyUtils(), new AssetJsonLdUtils(), new MarkdownToTextConverter(), new TextUtils(), x -> endpoint.equals(x));
assetMapper = new AssetMapper(typeTransformerRegistry, uiAssetBuilder, jsonLd);
}
Expand All @@ -43,7 +41,7 @@ void setup() {
@SneakyThrows
void test_buildAssetDto() {
// Arrange
String assetJsonLd = new String(Files.readAllBytes(Paths.get(getClass().getResource("/example-asset.jsonld").toURI())));
String assetJsonLd = TestUtils.loadResourceAsString("/example-asset.jsonld");

// Act
var uiAsset = assetMapper.buildUiAsset(JsonUtils.parseJsonObj(assetJsonLd), endpoint, participantId);
Expand All @@ -54,8 +52,10 @@ void test_buildAssetDto() {
assertThat(uiAsset.getParticipantId()).isEqualTo(participantId);
assertThat(uiAsset.getTitle()).isEqualTo("My Asset");
assertThat(uiAsset.getLanguage()).isEqualTo("https://w3id.org/idsa/code/EN");
assertThat(uiAsset.getDescription()).isEqualTo("# Lorem Ipsum...\n## h2 title\n[Link text Here](example.com) 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
assertThat(uiAsset.getDescriptionShortText()).isEqualTo("Lorem Ipsum... h2 title Link text Here 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
assertThat(uiAsset.getDescription()).isEqualTo(
"# Lorem Ipsum...\n## h2 title\n[Link text Here](example.com) 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
assertThat(uiAsset.getDescriptionShortText()).isEqualTo(
"Lorem Ipsum... h2 title Link text Here 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
assertThat(uiAsset.getIsOwnConnector()).isEqualTo(true);
assertThat(uiAsset.getCreatorOrganizationName()).isEqualTo("My Organization Name");
assertThat(uiAsset.getPublisherHomepage()).isEqualTo("https://data-source.my-org/about");
Expand Down Expand Up @@ -85,14 +85,18 @@ void test_buildAssetDto() {
assertThat(uiAsset.getTemporalCoverageToInclusive()).isEqualTo("2024-01-22");

assertThat(uiAsset.getAssetJsonLd()).contains("\"%s\"".formatted(Prop.Edc.ID));
assertThat(uiAsset.getAdditionalProperties()).containsExactlyEntriesOf(Map.of(
"http://unknown/some-custom-string", "some-string-value"));
assertThat(uiAsset.getAdditionalJsonProperties()).containsExactlyEntriesOf(Map.of(
"http://unknown/some-custom-obj", "{\"http://unknown/a\":\"b\"}"));
assertThat(uiAsset.getPrivateProperties()).containsExactlyEntriesOf(Map.of(
"http://unknown/some-custom-private-string", "some-private-value"));
assertThat(uiAsset.getPrivateJsonProperties()).containsExactlyEntriesOf(Map.of(
"http://unknown/some-custom-private-obj", "{\"http://unknown/a-private\":\"b-private\"}"));
// TODO: check where to put those old additional properties
// assertThat(uiAsset.getAdditionalProperties()).containsExactlyEntriesOf(Map.of(
// "http://unknown/some-custom-string", "some-string-value"));
// assertThat(uiAsset.getAdditionalJsonProperties()).containsExactlyEntriesOf(Map.of(
// "http://unknown/some-custom-obj", "{\"http://unknown/a\":\"b\"}"));
// assertThat(uiAsset.getPrivateProperties()).containsExactlyEntriesOf(Map.of(
// "http://unknown/some-custom-private-string", "some-private-value"));
// assertThat(uiAsset.getPrivateJsonProperties()).containsExactlyEntriesOf(Map.of(
// "http://unknown/some-custom-private-obj", "{\"http://unknown/a-private\":\"b-private\"}"));

JsonAssertions.assertThatJson(uiAsset.getCustomJsonAsString())
.isEqualTo(TestUtils.loadResourceAsString("/expected-custom-json.json"));
}

@Test
Expand All @@ -102,6 +106,7 @@ void test_empty() {
var assetJsonLd = createObjectBuilder()
.add(Prop.ID, "my-asset-1")
.build();

// Act
var uiAsset = assetMapper.buildUiAsset(assetJsonLd, endpoint, participantId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package de.sovity.edc.ext.wrapper.api.common.mappers;

import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;

import java.nio.file.Files;
import java.nio.file.Paths;

public class TestUtils {
@NotNull
@SneakyThrows
public static String loadResourceAsString(String name) {
return new String(Files.readAllBytes(Paths.get(TestUtils.class.getResource(name).toURI())));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package de.sovity.edc.ext.wrapper.api.common.mappers.utils;

import de.sovity.edc.ext.wrapper.api.common.model.UiAssetCreateRequest;
import de.sovity.edc.utils.JsonUtils;
import de.sovity.edc.utils.jsonld.vocab.Prop;
import lombok.val;
import org.junit.jupiter.api.Test;

import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
import static org.mockito.Mockito.mock;

class UiAssetMapperTest {
@Test
void test_buildAssetJsonLdContainsCustomJson() {
// Arrange
val mapper = new UiAssetMapper(
mock(EdcPropertyUtils.class),
mock(AssetJsonLdUtils.class),
mock(MarkdownToTextConverter.class),
mock(TextUtils.class),
mock(OwnConnectorEndpointService.class)
);
val createRequest = new UiAssetCreateRequest();

createRequest.setId("my-asset");
createRequest.setTitle("My Asset");
createRequest.setCustomJsonAsString("verbatim JSON string");

// Act
val jsonLd = mapper.buildAssetJsonLd(createRequest, "my-organisation");
val serialized = JsonUtils.toJson(jsonLd);

// Assert
assertThatJson(serialized).isObject().containsKey(Prop.Edc.PROPERTIES);

val properties = jsonLd.getJsonObject(Prop.Edc.PROPERTIES);
val serializedProperties = JsonUtils.toJson(properties);
assertThatJson(serializedProperties).isObject().containsEntry(
"https://semantic.sovity.io/dcat-ext#customJson",
"verbatim JSON string");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"array":[3,1,4,1,5],"boolean":false,"null":null,"number":116,"object":{"key":"value"},"string":"value"}
Loading

0 comments on commit 266efee

Please sign in to comment.