Skip to content

Commit 6b3e831

Browse files
authored
feat: provide asset property for CatalogAsset type (#5796)
* feat: provide asset property for CatalogAsset type * get ri of catalogFormat * define endpointURL and format properties
1 parent 6b3053b commit 6b3e831

27 files changed

Lines changed: 407 additions & 189 deletions

File tree

core/common/lib/json-ld-lib/src/main/resources/document/dspace-edc-context-v1.jsonld

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"@version": 1.1,
44
"edc": "https://w3id.org/edc/v0.0.1/ns/",
55
"dct": "http://purl.org/dc/terms/",
6+
"dcat": "http://www.w3.org/ns/dcat#",
67
"QuerySpec": {
78
"@id": "edc:QuerySpec",
89
"@context": {
@@ -31,6 +32,14 @@
3132
"conformsTo": {
3233
"@id": "dct:conformsTo",
3334
"@type": "@id"
35+
},
36+
"endpointURL": {
37+
"@id": "dcat:endpointURL",
38+
"@type": "@id"
39+
},
40+
"format": {
41+
"@id": "dct:format",
42+
"@type": "@id"
3443
}
3544
}
3645
}

core/common/lib/json-ld-lib/src/main/resources/document/management-context-v2.jsonld

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"@version": 1.1,
44
"edc": "https://w3id.org/edc/v0.0.1/ns/",
55
"dct": "http://purl.org/dc/terms/",
6+
"dcat": "http://www.w3.org/ns/dcat#",
67
"Asset": {
78
"@id": "edc:Asset",
89
"@context": {
@@ -56,7 +57,15 @@
5657
"properties": {
5758
"@id": "edc:properties",
5859
"@context": {
59-
"@vocab": "https://w3id.org/edc/v0.0.1/ns/"
60+
"@vocab": "https://w3id.org/edc/v0.0.1/ns/",
61+
"endpointURL": {
62+
"@id": "dcat:endpointURL",
63+
"@type": "@id"
64+
},
65+
"format": {
66+
"@id": "dct:format",
67+
"@type": "@id"
68+
}
6069
}
6170
},
6271
"privateProperties": {

core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public AssetService assetService() {
181181
var assetObservable = new AssetObservableImpl();
182182
assetObservable.registerListener(new AssetEventListener(eventRouter));
183183
return new AssetServiceImpl(assetIndex, contractNegotiationStore, transactionContext, assetObservable,
184-
new AssetQueryValidator());
184+
new AssetQueryValidator(), monitor);
185185
}
186186

187187
@Provider

core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates;
2323
import org.eclipse.edc.connector.controlplane.services.query.QueryValidator;
2424
import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService;
25+
import org.eclipse.edc.spi.monitor.Monitor;
2526
import org.eclipse.edc.spi.query.Criterion;
2627
import org.eclipse.edc.spi.query.QuerySpec;
2728
import org.eclipse.edc.spi.result.ServiceResult;
@@ -31,6 +32,8 @@
3132
import java.util.function.Predicate;
3233

3334
import static java.lang.String.format;
35+
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_ENDPOINT_URL_ATTRIBUTE;
36+
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCT_FORMAT_ATTRIBUTE;
3437

3538
public class AssetServiceImpl implements AssetService {
3639

@@ -41,15 +44,17 @@ public class AssetServiceImpl implements AssetService {
4144
private final TransactionContext transactionContext;
4245
private final AssetObservable observable;
4346
private final QueryValidator queryValidator;
47+
private final Monitor monitor;
4448

4549
public AssetServiceImpl(AssetIndex index, ContractNegotiationStore contractNegotiationStore,
4650
TransactionContext transactionContext, AssetObservable observable,
47-
QueryValidator queryValidator) {
51+
QueryValidator queryValidator, Monitor monitor) {
4852
this.index = index;
4953
this.contractNegotiationStore = contractNegotiationStore;
5054
this.transactionContext = transactionContext;
5155
this.observable = observable;
5256
this.queryValidator = queryValidator;
57+
this.monitor = monitor;
5358
}
5459

5560
@Override
@@ -72,14 +77,14 @@ public ServiceResult<Asset> create(Asset asset) {
7277
return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE);
7378
}
7479

75-
return transactionContext.execute(() -> {
76-
var createResult = index.create(asset);
77-
if (createResult.succeeded()) {
78-
observable.invokeForEach(l -> l.created(asset));
79-
return ServiceResult.success(asset);
80-
}
81-
return ServiceResult.fromFailure(createResult);
82-
});
80+
logWarningWhenCatalogAssetPropertiesAreNotSet(asset);
81+
82+
return transactionContext.execute(() ->
83+
index.create(asset)
84+
.onSuccess(i -> observable.invokeForEach(l -> l.created(asset)))
85+
.flatMap(ServiceResult::from)
86+
.map(i -> asset)
87+
);
8388
}
8489

8590
@Override
@@ -108,11 +113,21 @@ public ServiceResult<Asset> update(Asset asset) {
108113
return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE);
109114
}
110115

111-
return transactionContext.execute(() -> {
112-
var updatedAsset = index.updateAsset(asset);
113-
updatedAsset.onSuccess(a -> observable.invokeForEach(l -> l.updated(a)));
114-
return ServiceResult.from(updatedAsset);
115-
});
116+
logWarningWhenCatalogAssetPropertiesAreNotSet(asset);
117+
118+
return transactionContext.execute(() ->
119+
index.updateAsset(asset)
120+
.onSuccess(a -> observable.invokeForEach(l -> l.updated(a)))
121+
.flatMap(ServiceResult::from)
122+
);
123+
}
124+
125+
@Deprecated(since = "management-api:v4")
126+
private void logWarningWhenCatalogAssetPropertiesAreNotSet(Asset asset) {
127+
if (asset.isCatalog() && (asset.getProperty(DCAT_ENDPOINT_URL_ATTRIBUTE) == null || asset.getProperty(DCT_FORMAT_ATTRIBUTE) == null)) {
128+
monitor.warning("The 'CatalogAsset' type is expecting 'endpointURL' and 'format' properties " +
129+
"please adapt your clients accordingly");
130+
}
116131
}
117132

118133
private List<Asset> queryAssets(QuerySpec query) {

core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImplTest.java

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.edc.connector.controlplane.services.query.QueryValidator;
2525
import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService;
2626
import org.eclipse.edc.policy.model.Policy;
27+
import org.eclipse.edc.spi.monitor.Monitor;
2728
import org.eclipse.edc.spi.query.QuerySpec;
2829
import org.eclipse.edc.spi.result.Result;
2930
import org.eclipse.edc.spi.result.ServiceFailure;
@@ -51,6 +52,7 @@
5152
import static org.eclipse.edc.spi.result.ServiceFailure.Reason.NOT_FOUND;
5253
import static org.mockito.AdditionalMatchers.and;
5354
import static org.mockito.ArgumentMatchers.any;
55+
import static org.mockito.ArgumentMatchers.anyString;
5456
import static org.mockito.ArgumentMatchers.argThat;
5557
import static org.mockito.ArgumentMatchers.eq;
5658
import static org.mockito.ArgumentMatchers.isA;
@@ -69,9 +71,10 @@ class AssetServiceImplTest {
6971
private final TransactionContext dummyTransactionContext = new NoopTransactionContext();
7072
private final AssetObservable observable = mock();
7173
private final QueryValidator queryValidator = mock();
74+
private final Monitor monitor = mock();
7275

7376
private final AssetService service = new AssetServiceImpl(index, contractNegotiationStore, dummyTransactionContext,
74-
observable, queryValidator);
77+
observable, queryValidator, monitor);
7578

7679
@Test
7780
void findById_shouldRelyOnAssetIndex() {
@@ -146,6 +149,16 @@ void shouldNotCreateAssetIfItAlreadyExists() {
146149
assertThat(inserted).isFailed().extracting(ServiceFailure::getReason).isEqualTo(CONFLICT);
147150
}
148151

152+
@Test
153+
void shouldLogWarning_whenAssetCatalogAndPropertiesNotSet() {
154+
var asset = createAssetBuilder("assetId").property(Asset.PROPERTY_IS_CATALOG, "true").build();
155+
when(index.create(asset)).thenReturn(StoreResult.success());
156+
157+
service.create(asset);
158+
159+
verify(monitor).warning(anyString());
160+
}
161+
149162
@Test
150163
void shouldFail_whenPropertiesAreDuplicated() {
151164
var asset = createAssetBuilder("assetId").property("property", "value").privateProperty("property", "other-value").build();
@@ -246,41 +259,54 @@ private static Stream<Arguments> nonFinalStates() {
246259
}
247260
}
248261

249-
@Test
250-
void updateAsset_shouldUpdateWhenExists() {
251-
var asset = createAsset("assetId");
252-
when(index.updateAsset(asset)).thenReturn(StoreResult.success(asset));
262+
@Nested
263+
class Update {
264+
@Test
265+
void shouldUpdateWhenExists() {
266+
var asset = createAsset("assetId");
267+
when(index.updateAsset(asset)).thenReturn(StoreResult.success(asset));
253268

254-
var updated = service.update(asset);
269+
var updated = service.update(asset);
255270

256-
assertThat(updated.succeeded()).isTrue();
257-
verify(index).updateAsset(eq(asset));
258-
verifyNoMoreInteractions(index);
259-
verify(observable).invokeForEach(any());
260-
}
271+
assertThat(updated.succeeded()).isTrue();
272+
verify(index).updateAsset(eq(asset));
273+
verifyNoMoreInteractions(index);
274+
verify(observable).invokeForEach(any());
275+
}
261276

262-
@Test
263-
void updateAsset_shouldReturnNotFound_whenNotExists() {
264-
var asset = createAsset("assetId");
265-
when(index.updateAsset(eq(asset))).thenReturn(StoreResult.notFound("test"));
277+
@Test
278+
void shouldReturnNotFound_whenNotExists() {
279+
var asset = createAsset("assetId");
280+
when(index.updateAsset(eq(asset))).thenReturn(StoreResult.notFound("test"));
266281

267-
var updated = service.update(asset);
282+
var updated = service.update(asset);
268283

269-
assertThat(updated.failed()).isTrue();
270-
assertThat(updated.reason()).isEqualTo(NOT_FOUND);
271-
verify(index, times(1)).updateAsset(asset);
272-
verifyNoMoreInteractions(index);
273-
verify(observable, never()).invokeForEach(any());
274-
}
284+
assertThat(updated.failed()).isTrue();
285+
assertThat(updated.reason()).isEqualTo(NOT_FOUND);
286+
verify(index, times(1)).updateAsset(asset);
287+
verifyNoMoreInteractions(index);
288+
verify(observable, never()).invokeForEach(any());
289+
}
275290

276-
@Test
277-
void updateAsset_shouldFail_whenPropertiesAreDuplicated() {
278-
var asset = createAssetBuilder("assetId").property("property", "value").privateProperty("property", "other-value").build();
291+
@Test
292+
void shouldLogWarning_whenAssetCatalogAndPropertiesNotSet() {
293+
var asset = createAssetBuilder("assetId").property(Asset.PROPERTY_IS_CATALOG, "true").build();
294+
when(index.updateAsset(asset)).thenReturn(StoreResult.success(asset));
279295

280-
var result = service.update(asset);
296+
service.update(asset);
297+
298+
verify(monitor).warning(anyString());
299+
}
281300

282-
assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(BAD_REQUEST);
283-
verifyNoInteractions(index);
301+
@Test
302+
void shouldFail_whenPropertiesAreDuplicated() {
303+
var asset = createAssetBuilder("assetId").property("property", "value").privateProperty("property", "other-value").build();
304+
305+
var result = service.update(asset);
306+
307+
assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(BAD_REQUEST);
308+
verifyNoInteractions(index);
309+
}
284310
}
285311

286312
@NotNull

core/control-plane/control-plane-catalog/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ plugins {
1717
}
1818

1919
dependencies {
20+
api(project(":spi:common:json-ld-spi"))
2021
api(project(":spi:control-plane:catalog-spi"))
2122
api(project(":spi:control-plane:contract-spi"))
2223
api(project(":spi:control-plane:transfer-spi"))

core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogCoreExtension.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
2525
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
2626
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
27+
import org.eclipse.edc.spi.monitor.Monitor;
2728
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
2829
import org.eclipse.edc.spi.system.ServiceExtension;
2930
import org.eclipse.edc.spi.system.ServiceExtensionContext;
@@ -52,6 +53,8 @@ public class CatalogCoreExtension implements ServiceExtension {
5253

5354
@Inject
5455
private PolicyEngine policyEngine;
56+
@Inject
57+
private Monitor monitor;
5558

5659
@Override
5760
public String name() {
@@ -67,7 +70,7 @@ public void initialize(ServiceExtensionContext context) {
6770
public DatasetResolver datasetResolver() {
6871
var contractDefinitionResolver = new ContractDefinitionResolverImpl(contractDefinitionStore, policyEngine, policyDefinitionStore);
6972
return new DatasetResolverImpl(contractDefinitionResolver, assetIndex, policyDefinitionStore,
70-
distributionResolver, criterionOperatorRegistry);
73+
distributionResolver, criterionOperatorRegistry, monitor);
7174
}
7275

7376
}

core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogDefaultServicesExtension.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
2121
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
2222
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
23+
import org.eclipse.edc.spi.monitor.Monitor;
2324
import org.eclipse.edc.spi.system.ServiceExtension;
2425
import org.eclipse.edc.spi.system.ServiceExtensionContext;
2526

@@ -30,6 +31,8 @@ public class CatalogDefaultServicesExtension implements ServiceExtension {
3031

3132
@Inject
3233
private DataFlowController dataFlowController;
34+
@Inject
35+
private Monitor monitor;
3336

3437
private DataServiceRegistry dataServiceRegistry;
3538

@@ -50,7 +53,7 @@ public DataServiceRegistry dataServiceRegistry() {
5053

5154
@Provider(isDefault = true)
5255
public DistributionResolver distributionResolver() {
53-
return new DefaultDistributionResolver(dataServiceRegistry, dataFlowController);
56+
return new DefaultDistributionResolver(dataServiceRegistry, dataFlowController, monitor);
5457
}
5558

5659
}

core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractDefinition;
2727
import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition;
2828
import org.eclipse.edc.connector.controlplane.policy.spi.store.PolicyDefinitionStore;
29-
import org.eclipse.edc.dataaddress.httpdata.spi.HttpDataAddressSchema;
3029
import org.eclipse.edc.participant.spi.ParticipantAgent;
3130
import org.eclipse.edc.participantcontext.spi.types.ParticipantContext;
3231
import org.eclipse.edc.policy.model.Policy;
3332
import org.eclipse.edc.policy.model.PolicyType;
33+
import org.eclipse.edc.spi.monitor.Monitor;
3434
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
3535
import org.eclipse.edc.spi.query.QuerySpec;
3636
import org.jetbrains.annotations.NotNull;
@@ -43,7 +43,9 @@
4343
import java.util.stream.Stream;
4444

4545
import static java.lang.Integer.MAX_VALUE;
46+
import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_ENDPOINT_URL_ATTRIBUTE;
4647
import static org.eclipse.edc.participantcontext.spi.types.ParticipantResource.filterByParticipantContextId;
48+
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE;
4749

4850
public class DatasetResolverImpl implements DatasetResolver {
4951

@@ -52,15 +54,17 @@ public class DatasetResolverImpl implements DatasetResolver {
5254
private final PolicyDefinitionStore policyDefinitionStore;
5355
private final DistributionResolver distributionResolver;
5456
private final CriterionOperatorRegistry criterionOperatorRegistry;
57+
private final Monitor monitor;
5558

5659
public DatasetResolverImpl(ContractDefinitionResolver contractDefinitionResolver, AssetIndex assetIndex,
5760
PolicyDefinitionStore policyDefinitionStore, DistributionResolver distributionResolver,
58-
CriterionOperatorRegistry criterionOperatorRegistry) {
61+
CriterionOperatorRegistry criterionOperatorRegistry, Monitor monitor) {
5962
this.contractDefinitionResolver = contractDefinitionResolver;
6063
this.assetIndex = assetIndex;
6164
this.policyDefinitionStore = policyDefinitionStore;
6265
this.distributionResolver = distributionResolver;
6366
this.criterionOperatorRegistry = criterionOperatorRegistry;
67+
this.monitor = monitor;
6468
}
6569

6670
@Override
@@ -104,11 +108,20 @@ public Dataset getById(ParticipantContext participantContext, ParticipantAgent a
104108
return Dataset.Builder.newInstance();
105109
}
106110

111+
var endpointUrl = asset.getPropertyAsString(DCAT_ENDPOINT_URL_ATTRIBUTE);
112+
if (endpointUrl == null) {
113+
monitor.warning("""
114+
Asset %s has no 'endpointURL' property and the DataAddress baseUrl is used instead, please adapt it as the
115+
DataAddress will be removed from Asset in the forthcoming versions"""
116+
.formatted(asset.getId()));
117+
endpointUrl = asset.getDataAddress().getStringProperty(EDC_NAMESPACE + "baseUrl", null);
118+
}
119+
107120
return Catalog.Builder.newInstance()
108121
.dataService(DataService.Builder.newInstance()
109122
.id(Base64.getUrlEncoder().encodeToString(asset.getId().getBytes()))
110123
.endpointDescription(asset.getDescription())
111-
.endpointUrl(asset.getDataAddress().getStringProperty(HttpDataAddressSchema.BASE_URL, null))
124+
.endpointUrl(endpointUrl)
112125
.build());
113126
}
114127

0 commit comments

Comments
 (0)