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: implement Asset specialization #4297

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 @@ -19,6 +19,8 @@
import java.util.List;
import java.util.Objects;

import static java.util.Optional.ofNullable;

public class EqualOperatorPredicate implements OperatorPredicate {

@Override
Expand All @@ -42,8 +44,13 @@ public boolean test(Object property, Object operandRight) {

if (property instanceof List<?> list) {
return list.stream().anyMatch(it -> Objects.equals(it, operandRight));
} else if (property instanceof Boolean booleanProperty) {
return ofNullable(operandRight)
.map(Object::toString)
.map(Boolean::parseBoolean)
.map(booleanOperand -> booleanOperand == booleanProperty)
.orElse(false);
}

return Objects.equals(property, operandRight);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ void shouldMatchPredicate_whenObjectIsList() {
assertThat(predicate.test(List.of("one", "two"), "three")).isFalse();
}

@Test
void shouldCheckName_whenPropertyIsBoolean() {
assertThat(predicate.test(Boolean.TRUE, "ENTRY2")).isFalse();
assertThat(predicate.test(Boolean.TRUE, "true")).isTrue();
assertThat(predicate.test(Boolean.TRUE, true)).isTrue();
assertThat(predicate.test(Boolean.TRUE, false)).isFalse();
assertThat(predicate.test(Boolean.TRUE, null)).isFalse();
assertThat(predicate.test(Boolean.TRUE, "false")).isFalse();
assertThat(predicate.test(true, false)).isFalse();
}

public enum TestEnum {
ENTRY1, ENTRY2
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ void shouldMatchPredicate_whenObjectIsList() {
assertThat(predicate.test(List.of("one", "two"), "three")).isTrue();
}

@Test
void shouldCheckName_whenPropertyIsBoolean() {
assertThat(predicate.test(Boolean.TRUE, "ENTRY2")).isTrue();
assertThat(predicate.test(Boolean.TRUE, "true")).isFalse();
assertThat(predicate.test(Boolean.TRUE, true)).isFalse();
assertThat(predicate.test(Boolean.TRUE, false)).isTrue();
assertThat(predicate.test(Boolean.TRUE, "false")).isTrue();
assertThat(predicate.test(Boolean.TRUE, null)).isTrue();
assertThat(predicate.test(true, false)).isTrue();
}

public enum TestEnum {
ENTRY1, ENTRY2
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_CATALOG_ASSET_TYPE;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;

Expand Down Expand Up @@ -52,6 +53,10 @@ public JsonObjectFromAssetTransformer(JsonBuilderFactory jsonFactory, ObjectMapp
builder.add(Asset.EDC_ASSET_PRIVATE_PROPERTIES, privatePropBuilder);
}

if (asset.isCatalog()) {
builder.add(TYPE, EDC_CATALOG_ASSET_TYPE);
}

if (asset.getDataAddress() != null) {
builder.add(Asset.EDC_ASSET_DATA_ADDRESS, context.transform(asset.getDataAddress(), JsonObject.class));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_DATA_ADDRESS;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_PRIVATE_PROPERTIES;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_PROPERTIES;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_CATALOG_ASSET_TYPE;
import static org.eclipse.edc.jsonld.spi.TypeUtil.nodeType;

/**
* Converts from an {@link Asset} as a {@link JsonObject} in JSON-LD expanded form to an {@link Asset}.
Expand All @@ -43,12 +45,20 @@ public JsonObjectToAssetTransformer() {
.id(nodeId(jsonObject));

visitProperties(jsonObject, key -> switch (key) {
case EDC_ASSET_PROPERTIES -> value -> visitProperties(value.asJsonArray().getJsonObject(0), property(context, builder));
case EDC_ASSET_PRIVATE_PROPERTIES -> value -> visitProperties(value.asJsonArray().getJsonObject(0), privateProperty(context, builder));
case EDC_ASSET_DATA_ADDRESS -> value -> builder.dataAddress(transformObject(value, DataAddress.class, context));
case EDC_ASSET_PROPERTIES ->
value -> visitProperties(value.asJsonArray().getJsonObject(0), property(context, builder));
case EDC_ASSET_PRIVATE_PROPERTIES ->
value -> visitProperties(value.asJsonArray().getJsonObject(0), privateProperty(context, builder));
case EDC_ASSET_DATA_ADDRESS ->
value -> builder.dataAddress(transformObject(value, DataAddress.class, context));
default -> doNothing();
});

// the asset is a Catalog Asset, i.e. it links to another catalog
if (EDC_CATALOG_ASSET_TYPE.equals(nodeType(jsonObject))) {
builder.property(Asset.PROPERTY_IS_CATALOG, true);
}

return builderResult(builder::build, context);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_DATA_ADDRESS;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_PRIVATE_PROPERTIES;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_PROPERTIES;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_CATALOG_ASSET_TYPE;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.PROPERTY_IS_CATALOG;
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.JsonLdKeywords.VALUE;
Expand Down Expand Up @@ -132,6 +134,24 @@ void transform_customProperties_withCustomObject() {
assertThat(jsonObject.getJsonObject(EDC_ASSET_PROPERTIES).getJsonObject("https://foo.bar.org/schema/payload")).isInstanceOf(JsonObject.class);
}

@Test
void transform_shouldSetType_whenAssetIsCatalog() {
when(context.transform(isA(DataAddress.class), eq(JsonObject.class)))
.thenReturn(createObjectBuilder()
.add(EDC_DATA_ADDRESS_TYPE_PROPERTY, value("address-type"))
.build());
var dataAddress = DataAddress.Builder.newInstance().type("address-type").build();
var asset = createAssetBuilder()
.dataAddress(dataAddress)
.property(PROPERTY_IS_CATALOG, true)
.build();

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

assertThat(jsonObject).isNotNull();
assertThat(jsonObject.getString(TYPE)).isEqualTo(EDC_CATALOG_ASSET_TYPE);
}

private Asset.Builder createAssetBuilder() {
return Asset.Builder.newInstance()
.id(TEST_ASSET_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.map;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_PRIVATE_PROPERTIES;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_PROPERTIES;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_TYPE;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_CATALOG_ASSET_TYPE;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.PROPERTY_CONTENT_TYPE;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.PROPERTY_DESCRIPTION;
import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.PROPERTY_ID;
Expand Down Expand Up @@ -199,6 +201,22 @@ void shouldExcludeProperties_whenDefinedAtTheRootLevel() {
.asInstanceOf(map(String.class, Object.class)).doesNotContainKey(EDC_NAMESPACE + "thisShouldBeIgnored");
}

@Test
void shouldSetProperty_whenTypeIsCatalog() {
var jsonObj = jsonFactory.createObjectBuilder()
.add(CONTEXT, createContextBuilder().build())
.add(TYPE, EDC_CATALOG_ASSET_TYPE)
.add(ID, TEST_ASSET_ID)
.add(EDC_ASSET_PROPERTIES, createPropertiesBuilder().build())
.build();

var asset = typeTransformerRegistry.transform(TestInput.getExpanded(jsonObj), Asset.class);

assertThat(asset).withFailMessage(asset::getFailureDetail).isSucceeded();
assertThat(asset).isSucceeded()
.satisfies(a -> assertThat(a.isCatalog()).isTrue());
}

private JsonObjectBuilder createPayloadBuilder() {
return jsonFactory.createObjectBuilder()
.add(TYPE, "customPayload")
Expand Down
2 changes: 1 addition & 1 deletion docs/developer/management-domains/management-domains.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ The following implementation work will be done to support Management Domains.
The following changes will be made:

- A boolean subtype field will be introduced on `Asset` to indicate if it is a catalog. This field will be set to `true`
when an optional `@type` property is set to `dcat:Catalog` when an asset is created in the Management API.
when an optional `@type` property is set to `edc:CatalogAsset` when an asset is created in the Management API.
- The Management API will be updated in a backward-compatible way to handle optionally specifying the `@type` property
on `Asset`.
- `Catalog` will extend `Dataset`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ public class Asset extends Entity {
public static final String PROPERTY_DESCRIPTION = EDC_NAMESPACE + "description";
public static final String PROPERTY_VERSION = EDC_NAMESPACE + "version";
public static final String PROPERTY_CONTENT_TYPE = EDC_NAMESPACE + "contenttype";
public static final String PROPERTY_IS_CATALOG = EDC_NAMESPACE + "isCatalog";
public static final String EDC_ASSET_TYPE = EDC_NAMESPACE + "Asset";
public static final String EDC_CATALOG_ASSET_TYPE = EDC_NAMESPACE + "CatalogAsset";
public static final String EDC_ASSET_PROPERTIES = EDC_NAMESPACE + "properties";
public static final String EDC_ASSET_PRIVATE_PROPERTIES = EDC_NAMESPACE + "privateProperties";
public static final String EDC_ASSET_DATA_ADDRESS = EDC_NAMESPACE + "dataAddress";

private DataAddress dataAddress;
private final Map<String, Object> properties = new HashMap<>();
private final Map<String, Object> privateProperties = new HashMap<>();
private DataAddress dataAddress;

private Asset() {
}
Expand Down Expand Up @@ -79,6 +80,13 @@ public String getContentType() {
return ofNullable(getPropertyAsString(PROPERTY_CONTENT_TYPE)).orElse(getPropertyAsString("contenttype"));
}

@JsonIgnore
public boolean isCatalog() {
return ofNullable(getPropertyAsString(PROPERTY_IS_CATALOG))
.map(Boolean::parseBoolean)
.orElse(false);
}

public Map<String, Object> getProperties() {
return properties;
}
Expand All @@ -101,11 +109,6 @@ public Object getPrivateProperty(String key) {
return privateProperties.get(key);
}

private String getPropertyAsString(String key) {
var val = getProperty(key);
return val != null ? val.toString() : null;
}

public DataAddress getDataAddress() {
return dataAddress;
}
Expand All @@ -129,6 +132,11 @@ public boolean hasDuplicatePropertyKeys() {
return true;
}

private String getPropertyAsString(String key) {
var val = getProperty(key);
return val != null ? val.toString() : null;
}

@JsonPOJOBuilder(withPrefix = "")
public static class Builder extends Entity.Builder<Asset, Builder> {

Expand Down Expand Up @@ -159,6 +167,17 @@ public Builder self() {
return this;
}

@Override
public Asset build() {
super.build();

if (entity.getId() == null) {
id(UUID.randomUUID().toString());
}

return entity;
}

public Builder name(String title) {
entity.properties.put(PROPERTY_NAME, title);
return self();
Expand Down Expand Up @@ -205,17 +224,6 @@ public Builder privateProperty(String key, Object value) {
entity.privateProperties.put(key, value);
return self();
}

@Override
public Asset build() {
super.build();

if (entity.getId() == null) {
id(UUID.randomUUID().toString());
}

return entity;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,34 @@ void getNamedProperty_whenNotPresent_shouldReturnNull() {
assertThat(asset.getName()).isNull();
assertThat(asset.getVersion()).isNull();
}

@Test
void isCatalog_whenNotPresent_shouldReturnFalse() {
var asset = Asset.Builder.newInstance().build();
assertThat(asset.isCatalog()).isFalse();
}

@Test
void isCatalog_whenFalse_shouldReturnFalse() {
var asset = Asset.Builder.newInstance().property(Asset.PROPERTY_IS_CATALOG, "false").build();
assertThat(asset.isCatalog()).isFalse();

var asset2 = Asset.Builder.newInstance().property(Asset.PROPERTY_IS_CATALOG, false).build();
assertThat(asset2.isCatalog()).isFalse();
}

@Test
void isCatalog_whenTrue_shouldReturnTrue() {
var asset = Asset.Builder.newInstance().property(Asset.PROPERTY_IS_CATALOG, "true").build();
assertThat(asset.isCatalog()).isTrue();

var asset2 = Asset.Builder.newInstance().property(Asset.PROPERTY_IS_CATALOG, true).build();
assertThat(asset2.isCatalog()).isTrue();
}

@Test
void isCatalog_whenInvalidValid_shoudReturnFalse() {
var asset = Asset.Builder.newInstance().property(Asset.PROPERTY_IS_CATALOG, "foobar").build();
assertThat(asset.isCatalog()).isFalse();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@ void shouldFail_whenAssetAlreadyExists() {
.usingRecursiveFieldByFieldElementComparator()
.contains(asset);
}

@Test
void shouldCreate_withPrivateProperty() {
var asset = createAssetBuilder("test-asset").privateProperty("prop1", "val1")
.property(Asset.PROPERTY_IS_CATALOG, true)
.build();

assertThat(getAssetIndex().create(asset).succeeded()).isTrue();
var assetFound = getAssetIndex().findById("test-asset");

assertThat(assetFound).isNotNull();
assertThat(assetFound.isCatalog()).isTrue();

}
}

@Nested
Expand Down
Loading
Loading