From eea642be8a3da6ec1f1efbc55341381c447e20b7 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Thu, 4 Jun 2026 12:11:06 +0200 Subject: [PATCH 1/3] feat: provide asset property for CatalogAsset type --- .../ControlPlaneServicesExtension.java | 2 +- .../services/asset/AssetServiceImpl.java | 41 +++--- .../services/asset/AssetServiceImplTest.java | 82 +++++++----- .../catalog/CatalogCoreExtension.java | 5 +- .../CatalogDefaultServicesExtension.java | 5 +- .../catalog/DatasetResolverImpl.java | 17 ++- .../catalog/DefaultDistributionResolver.java | 16 ++- .../DatasetResolverImplIntegrationTest.java | 2 +- .../catalog/DatasetResolverImplTest.java | 2 +- .../DefaultDistributionResolverTest.java | 3 +- .../edc/api/management/ManagementApi.java | 3 +- .../schema/ManagementApiJsonSchema.java | 11 ++ .../ManagementApiConfigurationExtension.java | 2 + .../resources/management-api-version.json | 2 +- ...ManagementApiSchemaValidatorExtension.java | 117 +++++++----------- .../management/v4/catalog-asset-schema.json | 14 ++- .../schema/management/v5/asset-schema.json | 53 ++++++++ .../management/v5/catalog-asset-schema.json | 55 ++++++++ ...gementApiSchemaValidatorExtensionTest.java | 4 +- .../management/asset/AssetApiV5Extension.java | 14 +-- .../controlplane/asset/spi/domain/Asset.java | 15 +++ .../v4/AssetApiV4EndToEndTest.java | 3 +- .../v5/AssetApiV5EndToEndTest.java | 25 ++-- 23 files changed, 347 insertions(+), 146 deletions(-) create mode 100644 extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json create mode 100644 extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json diff --git a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java index f426e5d68fb..530d03bc809 100644 --- a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java +++ b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java @@ -181,7 +181,7 @@ public AssetService assetService() { var assetObservable = new AssetObservableImpl(); assetObservable.registerListener(new AssetEventListener(eventRouter)); return new AssetServiceImpl(assetIndex, contractNegotiationStore, transactionContext, assetObservable, - new AssetQueryValidator()); + new AssetQueryValidator(), monitor); } @Provider diff --git a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java index 8e64db7d5cf..7a7d6e75a5e 100644 --- a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java +++ b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java @@ -22,6 +22,7 @@ import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates; import org.eclipse.edc.connector.controlplane.services.query.QueryValidator; import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.Criterion; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.result.ServiceResult; @@ -41,15 +42,17 @@ public class AssetServiceImpl implements AssetService { private final TransactionContext transactionContext; private final AssetObservable observable; private final QueryValidator queryValidator; + private final Monitor monitor; public AssetServiceImpl(AssetIndex index, ContractNegotiationStore contractNegotiationStore, TransactionContext transactionContext, AssetObservable observable, - QueryValidator queryValidator) { + QueryValidator queryValidator, Monitor monitor) { this.index = index; this.contractNegotiationStore = contractNegotiationStore; this.transactionContext = transactionContext; this.observable = observable; this.queryValidator = queryValidator; + this.monitor = monitor; } @Override @@ -72,14 +75,14 @@ public ServiceResult create(Asset asset) { return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE); } - return transactionContext.execute(() -> { - var createResult = index.create(asset); - if (createResult.succeeded()) { - observable.invokeForEach(l -> l.created(asset)); - return ServiceResult.success(asset); - } - return ServiceResult.fromFailure(createResult); - }); + logWarningWhenAssetCatalogPropertiesAreNotSet(asset); + + return transactionContext.execute(() -> + index.create(asset) + .onSuccess(i -> observable.invokeForEach(l -> l.created(asset))) + .flatMap(ServiceResult::from) + .map(i -> asset) + ); } @Override @@ -108,11 +111,21 @@ public ServiceResult update(Asset asset) { return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE); } - return transactionContext.execute(() -> { - var updatedAsset = index.updateAsset(asset); - updatedAsset.onSuccess(a -> observable.invokeForEach(l -> l.updated(a))); - return ServiceResult.from(updatedAsset); - }); + logWarningWhenAssetCatalogPropertiesAreNotSet(asset); + + return transactionContext.execute(() -> + index.updateAsset(asset) + .onSuccess(a -> observable.invokeForEach(l -> l.updated(a))) + .flatMap(ServiceResult::from) + ); + } + + @Deprecated(since = "management-api:v4") + private void logWarningWhenAssetCatalogPropertiesAreNotSet(Asset asset) { + if (asset.isCatalog() && (asset.getCatalogUrl() == null || asset.getCatalogFormat() == null)) { + monitor.warning("The 'CatalogAsset' type is expecting 'catalogUrl' and 'catalogFormat' properties," + + "please adapt your clients accordingly"); + } } private List queryAssets(QuerySpec query) { diff --git a/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImplTest.java b/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImplTest.java index e5425914034..76afe17f372 100644 --- a/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImplTest.java +++ b/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImplTest.java @@ -24,6 +24,7 @@ import org.eclipse.edc.connector.controlplane.services.query.QueryValidator; import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.spi.result.ServiceFailure; @@ -51,6 +52,7 @@ import static org.eclipse.edc.spi.result.ServiceFailure.Reason.NOT_FOUND; import static org.mockito.AdditionalMatchers.and; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; @@ -69,9 +71,10 @@ class AssetServiceImplTest { private final TransactionContext dummyTransactionContext = new NoopTransactionContext(); private final AssetObservable observable = mock(); private final QueryValidator queryValidator = mock(); + private final Monitor monitor = mock(); private final AssetService service = new AssetServiceImpl(index, contractNegotiationStore, dummyTransactionContext, - observable, queryValidator); + observable, queryValidator, monitor); @Test void findById_shouldRelyOnAssetIndex() { @@ -146,6 +149,16 @@ void shouldNotCreateAssetIfItAlreadyExists() { assertThat(inserted).isFailed().extracting(ServiceFailure::getReason).isEqualTo(CONFLICT); } + @Test + void shouldLogWarning_whenAssetCatalogAndPropertiesNotSet() { + var asset = createAssetBuilder("assetId").property(Asset.PROPERTY_IS_CATALOG, "true").build(); + when(index.create(asset)).thenReturn(StoreResult.success()); + + service.create(asset); + + verify(monitor).warning(anyString()); + } + @Test void shouldFail_whenPropertiesAreDuplicated() { var asset = createAssetBuilder("assetId").property("property", "value").privateProperty("property", "other-value").build(); @@ -246,41 +259,54 @@ private static Stream nonFinalStates() { } } - @Test - void updateAsset_shouldUpdateWhenExists() { - var asset = createAsset("assetId"); - when(index.updateAsset(asset)).thenReturn(StoreResult.success(asset)); + @Nested + class Update { + @Test + void shouldUpdateWhenExists() { + var asset = createAsset("assetId"); + when(index.updateAsset(asset)).thenReturn(StoreResult.success(asset)); - var updated = service.update(asset); + var updated = service.update(asset); - assertThat(updated.succeeded()).isTrue(); - verify(index).updateAsset(eq(asset)); - verifyNoMoreInteractions(index); - verify(observable).invokeForEach(any()); - } + assertThat(updated.succeeded()).isTrue(); + verify(index).updateAsset(eq(asset)); + verifyNoMoreInteractions(index); + verify(observable).invokeForEach(any()); + } - @Test - void updateAsset_shouldReturnNotFound_whenNotExists() { - var asset = createAsset("assetId"); - when(index.updateAsset(eq(asset))).thenReturn(StoreResult.notFound("test")); + @Test + void shouldReturnNotFound_whenNotExists() { + var asset = createAsset("assetId"); + when(index.updateAsset(eq(asset))).thenReturn(StoreResult.notFound("test")); - var updated = service.update(asset); + var updated = service.update(asset); - assertThat(updated.failed()).isTrue(); - assertThat(updated.reason()).isEqualTo(NOT_FOUND); - verify(index, times(1)).updateAsset(asset); - verifyNoMoreInteractions(index); - verify(observable, never()).invokeForEach(any()); - } + assertThat(updated.failed()).isTrue(); + assertThat(updated.reason()).isEqualTo(NOT_FOUND); + verify(index, times(1)).updateAsset(asset); + verifyNoMoreInteractions(index); + verify(observable, never()).invokeForEach(any()); + } - @Test - void updateAsset_shouldFail_whenPropertiesAreDuplicated() { - var asset = createAssetBuilder("assetId").property("property", "value").privateProperty("property", "other-value").build(); + @Test + void shouldLogWarning_whenAssetCatalogAndPropertiesNotSet() { + var asset = createAssetBuilder("assetId").property(Asset.PROPERTY_IS_CATALOG, "true").build(); + when(index.updateAsset(asset)).thenReturn(StoreResult.success(asset)); - var result = service.update(asset); + service.update(asset); + + verify(monitor).warning(anyString()); + } - assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(BAD_REQUEST); - verifyNoInteractions(index); + @Test + void shouldFail_whenPropertiesAreDuplicated() { + var asset = createAssetBuilder("assetId").property("property", "value").privateProperty("property", "other-value").build(); + + var result = service.update(asset); + + assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(BAD_REQUEST); + verifyNoInteractions(index); + } } @NotNull diff --git a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogCoreExtension.java b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogCoreExtension.java index 3bde3348e9d..fc370b75a57 100644 --- a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogCoreExtension.java +++ b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogCoreExtension.java @@ -24,6 +24,7 @@ import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provider; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.CriterionOperatorRegistry; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; @@ -52,6 +53,8 @@ public class CatalogCoreExtension implements ServiceExtension { @Inject private PolicyEngine policyEngine; + @Inject + private Monitor monitor; @Override public String name() { @@ -67,7 +70,7 @@ public void initialize(ServiceExtensionContext context) { public DatasetResolver datasetResolver() { var contractDefinitionResolver = new ContractDefinitionResolverImpl(contractDefinitionStore, policyEngine, policyDefinitionStore); return new DatasetResolverImpl(contractDefinitionResolver, assetIndex, policyDefinitionStore, - distributionResolver, criterionOperatorRegistry); + distributionResolver, criterionOperatorRegistry, monitor); } } diff --git a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogDefaultServicesExtension.java b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogDefaultServicesExtension.java index 861ff8edd08..bc5566e490a 100644 --- a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogDefaultServicesExtension.java +++ b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/CatalogDefaultServicesExtension.java @@ -20,6 +20,7 @@ import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provider; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; @@ -30,6 +31,8 @@ public class CatalogDefaultServicesExtension implements ServiceExtension { @Inject private DataFlowController dataFlowController; + @Inject + private Monitor monitor; private DataServiceRegistry dataServiceRegistry; @@ -50,7 +53,7 @@ public DataServiceRegistry dataServiceRegistry() { @Provider(isDefault = true) public DistributionResolver distributionResolver() { - return new DefaultDistributionResolver(dataServiceRegistry, dataFlowController); + return new DefaultDistributionResolver(dataServiceRegistry, dataFlowController, monitor); } } diff --git a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java index 3d52b8435d6..56998e7b97f 100644 --- a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java +++ b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java @@ -26,11 +26,11 @@ import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractDefinition; import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition; import org.eclipse.edc.connector.controlplane.policy.spi.store.PolicyDefinitionStore; -import org.eclipse.edc.dataaddress.httpdata.spi.HttpDataAddressSchema; import org.eclipse.edc.participant.spi.ParticipantAgent; import org.eclipse.edc.participantcontext.spi.types.ParticipantContext; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.policy.model.PolicyType; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.CriterionOperatorRegistry; import org.eclipse.edc.spi.query.QuerySpec; import org.jetbrains.annotations.NotNull; @@ -44,6 +44,7 @@ import static java.lang.Integer.MAX_VALUE; import static org.eclipse.edc.participantcontext.spi.types.ParticipantResource.filterByParticipantContextId; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; public class DatasetResolverImpl implements DatasetResolver { @@ -52,15 +53,17 @@ public class DatasetResolverImpl implements DatasetResolver { private final PolicyDefinitionStore policyDefinitionStore; private final DistributionResolver distributionResolver; private final CriterionOperatorRegistry criterionOperatorRegistry; + private final Monitor monitor; public DatasetResolverImpl(ContractDefinitionResolver contractDefinitionResolver, AssetIndex assetIndex, PolicyDefinitionStore policyDefinitionStore, DistributionResolver distributionResolver, - CriterionOperatorRegistry criterionOperatorRegistry) { + CriterionOperatorRegistry criterionOperatorRegistry, Monitor monitor) { this.contractDefinitionResolver = contractDefinitionResolver; this.assetIndex = assetIndex; this.policyDefinitionStore = policyDefinitionStore; this.distributionResolver = distributionResolver; this.criterionOperatorRegistry = criterionOperatorRegistry; + this.monitor = monitor; } @Override @@ -104,11 +107,19 @@ public Dataset getById(ParticipantContext participantContext, ParticipantAgent a return Dataset.Builder.newInstance(); } + var catalogUrl = asset.getCatalogUrl(); + if (catalogUrl == null) { + monitor.warning(""" + Asset %s has no '%s' property and the DataAddress type is used instead, please adapt it as the + DataAddress will be removed from Asset in the forthcoming versions""" + .formatted(asset.getId(), Asset.PROPERTY_CATALOG_URL)); + catalogUrl = asset.getDataAddress().getStringProperty(EDC_NAMESPACE + "baseUrl", null); + } return Catalog.Builder.newInstance() .dataService(DataService.Builder.newInstance() .id(Base64.getUrlEncoder().encodeToString(asset.getId().getBytes())) .endpointDescription(asset.getDescription()) - .endpointUrl(asset.getDataAddress().getStringProperty(HttpDataAddressSchema.BASE_URL, null)) + .endpointUrl(catalogUrl) .build()); } diff --git a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java index 735c9ede511..839ff512d94 100644 --- a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java +++ b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java @@ -21,6 +21,7 @@ import org.eclipse.edc.connector.controlplane.catalog.spi.Distribution; import org.eclipse.edc.connector.controlplane.catalog.spi.DistributionResolver; import org.eclipse.edc.connector.controlplane.transfer.spi.flow.DataFlowController; +import org.eclipse.edc.spi.monitor.Monitor; import java.util.Base64; import java.util.List; @@ -29,17 +30,28 @@ public class DefaultDistributionResolver implements DistributionResolver { private final DataServiceRegistry dataServiceRegistry; private final DataFlowController dataFlowController; + private final Monitor monitor; - public DefaultDistributionResolver(DataServiceRegistry dataServiceRegistry, DataFlowController dataFlowController) { + public DefaultDistributionResolver(DataServiceRegistry dataServiceRegistry, DataFlowController dataFlowController, + Monitor monitor) { this.dataServiceRegistry = dataServiceRegistry; this.dataFlowController = dataFlowController; + this.monitor = monitor; } @Override public List getDistributions(String protocol, Asset asset) { if (asset.isCatalog()) { + var catalogFormat = asset.getCatalogFormat(); + if (catalogFormat == null) { + monitor.warning(""" + Asset %s has no '%s' property and the DataAddress type is used instead, please adapt it as the + DataAddress will be removed from Asset in the forthcoming versions""" + .formatted(asset.getId(), Asset.PROPERTY_CATALOG_FORMAT)); + catalogFormat = asset.getDataAddress().getType(); + } return List.of(Distribution.Builder.newInstance() - .format(asset.getDataAddress().getType()) + .format(catalogFormat) .dataService(DataService.Builder.newInstance() .id(Base64.getUrlEncoder().encodeToString(asset.getId().getBytes())) .build()) diff --git a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplIntegrationTest.java b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplIntegrationTest.java index 3e758b8f647..faf0783a656 100644 --- a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplIntegrationTest.java +++ b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplIntegrationTest.java @@ -78,7 +78,7 @@ void setUp() { assetIndex, policyStore, mock(), - criterionOperatorRegistry); + criterionOperatorRegistry, mock()); var policyDefinition = PolicyDefinition.Builder.newInstance().policy(Policy.Builder.newInstance().build()).build(); when(policyStore.findById(any())).thenReturn(policyDefinition); } diff --git a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplTest.java b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplTest.java index c2ddacc5717..f9052024951 100644 --- a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplTest.java +++ b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImplTest.java @@ -79,7 +79,7 @@ class DatasetResolverImplTest { @BeforeEach void setUp() { datasetResolver = new DatasetResolverImpl(definitionResolver, assetIndex, policyStore, distributionResolver, - CriterionOperatorRegistryImpl.ofDefaults()); + CriterionOperatorRegistryImpl.ofDefaults(), mock()); } private ContractDefinition.Builder contractDefinitionBuilder(String id) { diff --git a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java index 42b6958b2a5..b289810dfee 100644 --- a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java +++ b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java @@ -36,7 +36,8 @@ class DefaultDistributionResolverTest { private final DataServiceRegistry dataServiceRegistry = mock(); private final DataFlowController dataFlowController = mock(); - private final DefaultDistributionResolver resolver = new DefaultDistributionResolver(dataServiceRegistry, dataFlowController); + private final DefaultDistributionResolver resolver = new DefaultDistributionResolver(dataServiceRegistry, + dataFlowController, mock()); @Test void shouldReturnDistributionsForEveryTransferType() { diff --git a/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/ManagementApi.java b/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/ManagementApi.java index 338fd5c22ec..b7c8138d3dc 100644 --- a/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/ManagementApi.java +++ b/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/ManagementApi.java @@ -20,11 +20,12 @@ public interface ManagementApi { String MANAGEMENT_API_CONTEXT = "management-api"; String MANAGEMENT_API_V_4 = "v4"; + String MANAGEMENT_API_V_5 = "v5"; // JSON-LD scope for management API String MANAGEMENT_SCOPE = "MANAGEMENT_API"; - // JSON-LD scope for management API version 4 alpha String MANAGEMENT_SCOPE_V4 = MANAGEMENT_SCOPE + ":" + MANAGEMENT_API_V_4; + String MANAGEMENT_SCOPE_V5 = MANAGEMENT_SCOPE + ":" + MANAGEMENT_API_V_5; } diff --git a/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/schema/ManagementApiJsonSchema.java b/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/schema/ManagementApiJsonSchema.java index 33d2b21617a..4aefe350db7 100644 --- a/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/schema/ManagementApiJsonSchema.java +++ b/extensions/common/api/lib/management-api-lib/src/main/java/org/eclipse/edc/api/management/schema/ManagementApiJsonSchema.java @@ -17,6 +17,7 @@ public interface ManagementApiJsonSchema { String EDC_MGMT_V4_SCHEMA_PREFIX = "https://w3id.org/edc/connector/management/schema/v4"; + String EDC_MGMT_V5_SCHEMA_PREFIX = "https://w3id.org/edc/connector/management/schema/v5"; String DSPACE_2025_SCHEMA_PREFIX = "https://w3id.org/dspace/2025/1"; interface V4 { @@ -60,4 +61,14 @@ static String version() { return "v4"; } } + + interface V5 { + + String ASSET = EDC_MGMT_V5_SCHEMA_PREFIX + "/asset-schema.json"; + String CATALOG_ASSET = EDC_MGMT_V5_SCHEMA_PREFIX + "/catalog-asset-schema.json"; + + static String version() { + return "v5"; + } + } } diff --git a/extensions/common/api/management-api-configuration/src/main/java/org/eclipse/edc/connector/api/management/configuration/ManagementApiConfigurationExtension.java b/extensions/common/api/management-api-configuration/src/main/java/org/eclipse/edc/connector/api/management/configuration/ManagementApiConfigurationExtension.java index b630d2ca0d5..a725b8aac3f 100644 --- a/extensions/common/api/management-api-configuration/src/main/java/org/eclipse/edc/connector/api/management/configuration/ManagementApiConfigurationExtension.java +++ b/extensions/common/api/management-api-configuration/src/main/java/org/eclipse/edc/connector/api/management/configuration/ManagementApiConfigurationExtension.java @@ -65,6 +65,7 @@ import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_API_V_4; import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_SCOPE; import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_SCOPE_V4; +import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_SCOPE_V5; 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; @@ -135,6 +136,7 @@ public void initialize(ServiceExtensionContext context) { } jsonLd.registerContext(EDC_CONNECTOR_MANAGEMENT_CONTEXT_V2, MANAGEMENT_SCOPE_V4); + jsonLd.registerContext(EDC_CONNECTOR_MANAGEMENT_CONTEXT_V2, MANAGEMENT_SCOPE_V5); webService.registerResource(ApiContext.MANAGEMENT, new ObjectMapperProvider(typeManager, JSON_LD)); webService.registerResource(ApiContext.MANAGEMENT, new DeprecatedVersionLog(context.getMonitor())); diff --git a/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json b/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json index 23b2d92b540..a4056d808c3 100644 --- a/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json +++ b/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json @@ -14,7 +14,7 @@ { "version": "5.0.0-beta", "urlPath": "/v5beta", - "lastUpdated": "2026-05-29T09:00:00Z", + "lastUpdated": "2026-06-04T09:00:00Z", "maturity": "beta" } ] diff --git a/extensions/common/api/management-api-schema-validator/src/main/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtension.java b/extensions/common/api/management-api-schema-validator/src/main/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtension.java index 562307c302c..3a75178b480 100644 --- a/extensions/common/api/management-api-schema-validator/src/main/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtension.java +++ b/extensions/common/api/management-api-schema-validator/src/main/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtension.java @@ -15,6 +15,8 @@ package org.eclipse.edc.connector.api.management.schema; import jakarta.json.JsonObject; +import org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4; +import org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V5; import org.eclipse.edc.connector.api.management.schema.CustomSchemaValidatorConfigParser.CustomValidatorGroup; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; @@ -33,36 +35,7 @@ import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.DSPACE_2025_SCHEMA_PREFIX; import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.EDC_MGMT_V4_SCHEMA_PREFIX; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.ASSET; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.ASSOCIATE_DATASPACE_PROFILE_CONTEXT; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CATALOG_ASSET; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CATALOG_REQUEST; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CEL_EXPRESSION; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CEL_EXPRESSION_TEST_REQUEST; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CONTRACT_AGREEMENT; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CONTRACT_DEFINITION; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CONTRACT_NEGOTIATION; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CONTRACT_NEGOTIATION_STATE; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.CONTRACT_REQUEST; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.DATAPLANE_INSTANCE; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.DATASET_REQUEST; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.DISCOVERY_REQUEST; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.EDR_ENTRY; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.ID_RESPONSE; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.PARTICIPANT_CONTEXT; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.PARTICIPANT_CONTEXT_CONFIG; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.POLICY_DEFINITION; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.POLICY_EVALUATION_PLAN; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.POLICY_EVALUATION_REQUEST; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.POLICY_VALIDATION_RESULT; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.QUERY_SPEC; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.SECRET; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.SUSPEND_TRANSFER; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.TERMINATE_NEGOTIATION; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.TERMINATE_TRANSFER; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.TRANSFER_PROCESS; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.TRANSFER_PROCESS_STATE; -import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.V4.TRANSFER_REQUEST; +import static org.eclipse.edc.api.management.schema.ManagementApiJsonSchema.EDC_MGMT_V5_SCHEMA_PREFIX; import static org.eclipse.edc.connector.api.management.schema.ManagementApiSchemaValidatorExtension.NAME; import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_ASSET_TYPE_TERM; import static org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.EDC_CATALOG_ASSET_TYPE_TERM; @@ -93,8 +66,8 @@ public class ManagementApiSchemaValidatorExtension implements ServiceExtension { public static final String NAME = "Management API Schema Validator"; - public static final String V_4 = "v4"; - public static final String V_4_PREFIX = V_4 + ":"; + public static final String V_4_PREFIX = "v4:"; + public static final String V_5_PREFIX = "v5:"; public static final String CONFIG_PREFIX = "edc.mgmt.api.schema"; public static final String VALIDATOR_KEY = "validator"; @@ -112,41 +85,49 @@ public class ManagementApiSchemaValidatorExtension implements ServiceExtension { @Setting(context = CONFIG_PREFIX + ".." + VALIDATOR_KEY + "..", description = "Optional profile to associate with the validator in order to be activated", required = false) public static final String VALIDATOR_PROFILES_KEY = "profiles"; - private static final String EDC_CLASSPATH_SCHEMA = "classpath:schema/management/v4"; + private static final String EDC_CLASSPATH_SCHEMA_V4 = "classpath:schema/management/v4"; + private static final String EDC_CLASSPATH_SCHEMA_V5 = "classpath:schema/management/v5"; private static final String DSPACE_CLASSPATH_SCHEMA = "classpath:schema/dspace/2025"; private final Map schemaV4 = new HashMap<>() { { - put("IdResponse", ID_RESPONSE); - put(EDC_ASSET_TYPE_TERM, ASSET); - put(EDC_CATALOG_ASSET_TYPE_TERM, CATALOG_ASSET); - put(EDC_QUERY_SPEC_TYPE_TERM, QUERY_SPEC); - put(EDC_POLICY_DEFINITION_TYPE_TERM, POLICY_DEFINITION); - put(CONTRACT_DEFINITION_TYPE_TERM, CONTRACT_DEFINITION); - put(DATAPLANE_INSTANCE_TYPE_TERM, DATAPLANE_INSTANCE); - put(EDR_ENTRY_TYPE_TERM, EDR_ENTRY); - put("PolicyEvaluationPlanRequest", POLICY_EVALUATION_REQUEST); - put(EDC_POLICY_EVALUATION_PLAN_TYPE_TERM, POLICY_EVALUATION_PLAN); - put("PolicyValidationResult", POLICY_VALIDATION_RESULT); - put(EDC_SECRET_TYPE_TERM, SECRET); - put(CATALOG_REQUEST_TYPE_TERM, CATALOG_REQUEST); - put(DATASET_REQUEST_TYPE_TERM, DATASET_REQUEST); - put(CONTRACT_REQUEST_TYPE_TERM, CONTRACT_REQUEST); - put(CONTRACT_NEGOTIATION_TYPE_TERM, CONTRACT_NEGOTIATION); - put(NEGOTIATION_STATE_TYPE_TERM, CONTRACT_NEGOTIATION_STATE); - put(TERMINATE_NEGOTIATION_TYPE_TERM, TERMINATE_NEGOTIATION); - put(CONTRACT_AGREEMENT_TYPE_TERM, CONTRACT_AGREEMENT); - put(TRANSFER_REQUEST_TYPE_TERM, TRANSFER_REQUEST); - put(TRANSFER_PROCESS_TYPE_TERM, TRANSFER_PROCESS); - put("TransferState", TRANSFER_PROCESS_STATE); - put("TerminateTransfer", TERMINATE_TRANSFER); - put("SuspendTransfer", SUSPEND_TRANSFER); - put(PARTICIPANT_CONTEXT_TYPE_TERM, PARTICIPANT_CONTEXT); - put(PARTICIPANT_CONTEXT_CONFIG_TYPE_TERM, PARTICIPANT_CONTEXT_CONFIG); - put(CEL_EXPRESSION_TYPE_TERM, CEL_EXPRESSION); - put(CEL_EXPRESSION_TEST_REQUEST_TYPE_TERM, CEL_EXPRESSION_TEST_REQUEST); - put("AssociateDataspaceProfile", ASSOCIATE_DATASPACE_PROFILE_CONTEXT); - put("DiscoveryRequest", DISCOVERY_REQUEST); + put("IdResponse", V4.ID_RESPONSE); + put(EDC_ASSET_TYPE_TERM, V4.ASSET); + put(EDC_CATALOG_ASSET_TYPE_TERM, V4.CATALOG_ASSET); + put(EDC_QUERY_SPEC_TYPE_TERM, V4.QUERY_SPEC); + put(EDC_POLICY_DEFINITION_TYPE_TERM, V4.POLICY_DEFINITION); + put(CONTRACT_DEFINITION_TYPE_TERM, V4.CONTRACT_DEFINITION); + put(DATAPLANE_INSTANCE_TYPE_TERM, V4.DATAPLANE_INSTANCE); + put(EDR_ENTRY_TYPE_TERM, V4.EDR_ENTRY); + put("PolicyEvaluationPlanRequest", V4.POLICY_EVALUATION_REQUEST); + put(EDC_POLICY_EVALUATION_PLAN_TYPE_TERM, V4.POLICY_EVALUATION_PLAN); + put("PolicyValidationResult", V4.POLICY_VALIDATION_RESULT); + put(EDC_SECRET_TYPE_TERM, V4.SECRET); + put(CATALOG_REQUEST_TYPE_TERM, V4.CATALOG_REQUEST); + put(DATASET_REQUEST_TYPE_TERM, V4.DATASET_REQUEST); + put(CONTRACT_REQUEST_TYPE_TERM, V4.CONTRACT_REQUEST); + put(CONTRACT_NEGOTIATION_TYPE_TERM, V4.CONTRACT_NEGOTIATION); + put(NEGOTIATION_STATE_TYPE_TERM, V4.CONTRACT_NEGOTIATION_STATE); + put(TERMINATE_NEGOTIATION_TYPE_TERM, V4.TERMINATE_NEGOTIATION); + put(CONTRACT_AGREEMENT_TYPE_TERM, V4.CONTRACT_AGREEMENT); + put(TRANSFER_REQUEST_TYPE_TERM, V4.TRANSFER_REQUEST); + put(TRANSFER_PROCESS_TYPE_TERM, V4.TRANSFER_PROCESS); + put("TransferState", V4.TRANSFER_PROCESS_STATE); + put("TerminateTransfer", V4.TERMINATE_TRANSFER); + put("SuspendTransfer", V4.SUSPEND_TRANSFER); + put(PARTICIPANT_CONTEXT_TYPE_TERM, V4.PARTICIPANT_CONTEXT); + put(PARTICIPANT_CONTEXT_CONFIG_TYPE_TERM, V4.PARTICIPANT_CONTEXT_CONFIG); + put(CEL_EXPRESSION_TYPE_TERM, V4.CEL_EXPRESSION); + put(CEL_EXPRESSION_TEST_REQUEST_TYPE_TERM, V4.CEL_EXPRESSION_TEST_REQUEST); + put("AssociateDataspaceProfile", V4.ASSOCIATE_DATASPACE_PROFILE_CONTEXT); + put("DiscoveryRequest", V4.DISCOVERY_REQUEST); + } + }; + + private final Map schemaV5 = new HashMap<>() { + { + put(EDC_ASSET_TYPE_TERM, V5.ASSET); + put(EDC_CATALOG_ASSET_TYPE_TERM, V5.CATALOG_ASSET); } }; @@ -161,7 +142,8 @@ public void initialize(ServiceExtensionContext context) { var builder = ManagementApiSchemaValidatorProvider.Builder.newInstance() .objectMapper(() -> typeManager.getMapper(JSON_LD)) - .prefixMapping(EDC_MGMT_V4_SCHEMA_PREFIX, EDC_CLASSPATH_SCHEMA) + .prefixMapping(EDC_MGMT_V4_SCHEMA_PREFIX, EDC_CLASSPATH_SCHEMA_V4) + .prefixMapping(EDC_MGMT_V5_SCHEMA_PREFIX, EDC_CLASSPATH_SCHEMA_V5) .prefixMapping(DSPACE_2025_SCHEMA_PREFIX, DSPACE_CLASSPATH_SCHEMA); customGroups.stream() @@ -171,14 +153,11 @@ public void initialize(ServiceExtensionContext context) { var schemaValidatorProvider = builder.build(); - registerValidatorsV4(schemaValidatorProvider); + schemaV4.forEach((type, schema) -> validator.register(V_4_PREFIX + type, schemaValidatorProvider.validatorFor(schema))); + schemaV5.forEach((type, schema) -> validator.register(V_5_PREFIX + type, schemaValidatorProvider.validatorFor(schema))); registerCustomValidators(schemaValidatorProvider, customGroups); } - void registerValidatorsV4(ManagementApiSchemaValidatorProvider validatorProvider) { - schemaV4.forEach((type, schema) -> validator.register(V_4_PREFIX + type, validatorProvider.validatorFor(schema))); - } - void registerCustomValidators(ManagementApiSchemaValidatorProvider validatorProvider, List groups) { groups.forEach(group -> group.bindings().forEach(binding -> validator.register(group.version() + ":" + binding.type(), validatorForSchema(validatorProvider, binding.schema(), binding.type(), binding.profiles())))); diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json index 5c5b6fb13d7..52861ed84a9 100644 --- a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json @@ -23,7 +23,19 @@ "type": "string" }, "properties": { - "type": "object" + "type": "object", + "example": { + "catalogUrl": "http://catalog/url", + "catalogFormat": "http" + }, + "properties": { + "catalogUrl": { + "type": "string" + }, + "catalogFormat": { + "type": "string" + } + } }, "privateProperties": { "type": "object" diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json new file mode 100644 index 00000000000..b89b12c0895 --- /dev/null +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "AssetSchema", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/Asset" + } + ], + "$id": "https://w3id.org/edc/connector/management/schema/v4/asset-schema.json", + "definitions": { + "Asset": { + "type": "object", + "properties": { + "@context": { + "$ref": "https://w3id.org/edc/connector/management/schema/v4/context-schema.json" + }, + "@type": { + "type": "string", + "const": "Asset" + }, + "@id": { + "type": "string" + }, + "properties": { + "type": "object", + "example": { + "key": "value" + }, + "properties": { + "conformsTo": { + "type": "string" + } + } + }, + "privateProperties": { + "type": "object", + "example": { + "privateKey": "privateValue" + } + }, + "dataplaneMetadata": { + "$ref": "https://w3id.org/edc/connector/management/schema/v4/dataplane-metadata-schema.json" + } + }, + "required": [ + "@context", + "@type", + "properties" + ] + } + } +} diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json new file mode 100644 index 00000000000..def813dd42d --- /dev/null +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "CatalogAssetSchema", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/CatalogAsset" + } + ], + "$id": "https://w3id.org/edc/connector/management/schema/v4/catalog-asset-schema.json", + "definitions": { + "CatalogAsset": { + "type": "object", + "properties": { + "@context": { + "$ref": "https://w3id.org/edc/connector/management/schema/v4/context-schema.json" + }, + "@type": { + "type": "string", + "const": "CatalogAsset" + }, + "@id": { + "type": "string" + }, + "properties": { + "type": "object", + "example": { + "catalogUrl": "http://catalog/url", + "catalogFormat": "http" + }, + "properties": { + "catalogUrl": { + "type": "string" + }, + "catalogFormat": { + "type": "string" + } + }, + "required": ["catalogUrl", "catalogFormat"] + }, + "privateProperties": { + "type": "object" + }, + "isCatalog": { + "type": "boolean" + } + }, + "required": [ + "@context", + "@type", + "properties" + ] + } + } +} \ No newline at end of file diff --git a/extensions/common/api/management-api-schema-validator/src/test/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtensionTest.java b/extensions/common/api/management-api-schema-validator/src/test/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtensionTest.java index 13415d109e5..2f5f3fc7198 100644 --- a/extensions/common/api/management-api-schema-validator/src/test/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtensionTest.java +++ b/extensions/common/api/management-api-schema-validator/src/test/java/org/eclipse/edc/connector/api/management/schema/ManagementApiSchemaValidatorExtensionTest.java @@ -81,14 +81,14 @@ void initialize_registersCustomValidators_composedWithBuiltIn(TestExtensionConte @Test void initialize_registersCustomValidators_withDistinctVersionPrefix(TestExtensionContext context) { context.setConfig(ConfigFactory.fromMap(Map.of( - "edc.mgmt.api.schema.custom.version", "v5", + "edc.mgmt.api.schema.custom.version", "v6", "edc.mgmt.api.schema.custom.validator.asset.type", "Asset", "edc.mgmt.api.schema.custom.validator.asset.schema", "https://w3id.org/edc/connector/management/schema/v4/asset-schema.json" ))); extension.initialize(context); - verify(validatorRegistry).register(eq("v5:Asset"), any()); + verify(validatorRegistry).register(eq("v6:Asset"), any()); } @Test diff --git a/extensions/control-plane/api/management-api-v5/asset-api-v5/src/main/java/org/eclipse/edc/connector/controlplane/api/management/asset/AssetApiV5Extension.java b/extensions/control-plane/api/management-api-v5/asset-api-v5/src/main/java/org/eclipse/edc/connector/controlplane/api/management/asset/AssetApiV5Extension.java index 5dd8296e25c..87a08aee28f 100644 --- a/extensions/control-plane/api/management-api-v5/asset-api-v5/src/main/java/org/eclipse/edc/connector/controlplane/api/management/asset/AssetApiV5Extension.java +++ b/extensions/control-plane/api/management-api-v5/asset-api-v5/src/main/java/org/eclipse/edc/connector/controlplane/api/management/asset/AssetApiV5Extension.java @@ -20,7 +20,6 @@ import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.participantcontext.spi.service.ParticipantContextService; import org.eclipse.edc.participantcontext.spi.types.ParticipantResource; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; @@ -33,10 +32,10 @@ import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; import org.eclipse.edc.web.jersey.providers.jsonld.JerseyJsonLdInterceptor; import org.eclipse.edc.web.spi.WebService; -import org.eclipse.edc.web.spi.configuration.ApiContext; -import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_SCOPE_V4; +import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_SCOPE_V5; import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD; +import static org.eclipse.edc.web.spi.configuration.ApiContext.MANAGEMENT; @Extension(value = AssetApiV5Extension.NAME) public class AssetApiV5Extension implements ServiceExtension { @@ -63,9 +62,6 @@ public class AssetApiV5Extension implements ServiceExtension { @Inject private AuthorizationService authorizationService; - @Inject - private ParticipantContextService participantContextService; - @Override public String name() { return NAME; @@ -79,8 +75,10 @@ public void initialize(ServiceExtensionContext context) { authorizationService.addLookupFunction(Asset.class, this::findAsset); - webService.registerResource(ApiContext.MANAGEMENT, new AssetApiV5Controller(assetService, managementTypeTransformerRegistry, validatorRegistry, monitor, authorizationService)); - webService.registerDynamicResource(ApiContext.MANAGEMENT, AssetApiV5Controller.class, new JerseyJsonLdInterceptor(jsonLd, typeManager, JSON_LD, MANAGEMENT_SCOPE_V4, validatorRegistry, ManagementApiJsonSchema.V4.version())); + webService.registerResource(MANAGEMENT, new AssetApiV5Controller(assetService, managementTypeTransformerRegistry, + validatorRegistry, monitor, authorizationService)); + webService.registerDynamicResource(MANAGEMENT, AssetApiV5Controller.class, new JerseyJsonLdInterceptor(jsonLd, + typeManager, JSON_LD, MANAGEMENT_SCOPE_V5, validatorRegistry, ManagementApiJsonSchema.V5.version())); } diff --git a/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java b/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java index 14f7b65f964..285552664c0 100644 --- a/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java +++ b/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import org.eclipse.edc.participantcontext.spi.types.AbstractParticipantResource; import org.eclipse.edc.spi.types.domain.DataAddress; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; @@ -39,17 +40,21 @@ public class Asset extends AbstractParticipantResource { public static final String PROPERTY_ID = EDC_NAMESPACE + "id"; public static final String PROPERTY_DESCRIPTION = EDC_NAMESPACE + "description"; public static final String PROPERTY_IS_CATALOG = EDC_NAMESPACE + "isCatalog"; + public static final String PROPERTY_CATALOG_URL = EDC_NAMESPACE + "catalogUrl"; + public static final String PROPERTY_CATALOG_FORMAT = EDC_NAMESPACE + "catalogFormat"; public static final String EDC_ASSET_TYPE_TERM = "Asset"; public static final String EDC_ASSET_TYPE = EDC_NAMESPACE + EDC_ASSET_TYPE_TERM; public static final String EDC_CATALOG_ASSET_TYPE_TERM = "CatalogAsset"; public static final String EDC_CATALOG_ASSET_TYPE = EDC_NAMESPACE + EDC_CATALOG_ASSET_TYPE_TERM; public static final String EDC_ASSET_PROPERTIES = EDC_NAMESPACE + "properties"; public static final String EDC_ASSET_PRIVATE_PROPERTIES = EDC_NAMESPACE + "privateProperties"; + @Deprecated(since = "0.18.0") public static final String EDC_ASSET_DATA_ADDRESS = EDC_NAMESPACE + "dataAddress"; public static final String EDC_ASSET_DATAPLANE_METADATA = EDC_NAMESPACE + "dataplaneMetadata"; private final Map properties = new HashMap<>(); private final Map privateProperties = new HashMap<>(); private DataplaneMetadata dataplaneMetadata; + @Deprecated(since = "0.18.0") private DataAddress dataAddress; private Asset() { @@ -72,6 +77,15 @@ public boolean isCatalog() { .orElse(false); } + @Nullable + public String getCatalogUrl() { + return getPropertyAsString(PROPERTY_CATALOG_URL); + } + + public String getCatalogFormat() { + return getPropertyAsString(PROPERTY_CATALOG_FORMAT); + } + public Map getProperties() { return properties; } @@ -94,6 +108,7 @@ public Object getPrivateProperty(String key) { return privateProperties.get(key); } + @Deprecated(since = "0.18.0") public DataAddress getDataAddress() { return dataAddress; } diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v4/AssetApiV4EndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v4/AssetApiV4EndToEndTest.java index fc7a8e9bb80..bf1a95c0309 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v4/AssetApiV4EndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v4/AssetApiV4EndToEndTest.java @@ -204,7 +204,8 @@ void createAsset_whenCatalogAsset_shouldSetProperty(ManagementEndToEndTestContex .add(CONTEXT, jsonLdContext()) .add(TYPE, "CatalogAsset") .add(ID, id) - .add("properties", createPropertiesBuilder().build()) + .add("properties", createPropertiesBuilder() + .build()) .add("dataAddress", createObjectBuilder() .add(TYPE, "DataAddress") .add("type", "test-type") diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java index e4359303b0b..d567bdbf8a3 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java @@ -280,7 +280,7 @@ void queryAsset_byCatalogProperty(ManagementEndToEndV5TestContext context, Asset var body = context.baseRequest(participantTokenJwt) .contentType(ContentType.JSON) .body(context.query( - criterion(EDC_NAMESPACE + "isCatalog", "=", "true"), + criterion(Asset.PROPERTY_IS_CATALOG, "=", "true"), criterion("id", "=", id)) .toString()) .post("/v5beta/participants/" + PARTICIPANT_CONTEXT_ID + "/assets/request") @@ -409,7 +409,6 @@ void createAsset_shouldBeStored(ManagementEndToEndV5TestContext context, AssetIn .add(TYPE, "Asset") .add(ID, id) .add("properties", createPropertiesBuilder() - .add("isCatalog", "true") .add("conformsTo", "http://example.com/spec") .build()) .add("privateProperties", createObjectBuilder() @@ -438,9 +437,8 @@ void createAsset_shouldBeStored(ManagementEndToEndV5TestContext context, AssetIn var asset = assetIndex.findById(id); assertThat(asset).isNotNull(); - assertThat(asset.isCatalog()).isTrue(); + assertThat(asset.isCatalog()).isFalse(); assertThat(asset.getProperty(DCT_CONFORMS_TO_ATTRIBUTE)).isEqualTo(Map.of(ID, "http://example.com/spec")); - assertThat(asset.getPrivateProperty(EDC_NAMESPACE + "anotherProp")).isEqualTo("anotherVal"); assertThat(asset.getDataAddress().getProperty("complex")) .asInstanceOf(MAP) @@ -570,7 +568,10 @@ void createAsset_whenCatalogAsset_shouldSetProperty(ManagementEndToEndV5TestCont .add(CONTEXT, jsonLdContext()) .add(TYPE, "CatalogAsset") .add(ID, id) - .add("properties", createPropertiesBuilder().build()) + .add("properties", createPropertiesBuilder() + .add("catalogUrl", "http://catalog-url") + .add("catalogFormat", "http") + .build()) .add("dataAddress", createObjectBuilder() .add(TYPE, "DataAddress") .add("type", "test-type") @@ -590,6 +591,8 @@ void createAsset_whenCatalogAsset_shouldSetProperty(ManagementEndToEndV5TestCont var asset = assetIndex.findById(id); assertThat(asset).isNotNull(); assertThat(asset.isCatalog()).isTrue(); + assertThat(asset.getCatalogUrl()).isEqualTo("http://catalog-url"); + assertThat(asset.getCatalogFormat()).isEqualTo("http"); } @Test @@ -598,9 +601,12 @@ void createAsset_whenCatalogInPrivateProps_shouldReturnCatalogType( var id = UUID.randomUUID().toString(); var assetJson = createObjectBuilder() .add(CONTEXT, jsonLdContext()) - .add(TYPE, "Asset") + .add(TYPE, "CatalogAsset") .add(ID, id) - .add("properties", createPropertiesBuilder().add("isCatalog", "true").build()) + .add("properties", createPropertiesBuilder() + .add("catalogUrl", "http://catalog-url") + .add("catalogFormat", "http") + .build()) .add("dataAddress", createObjectBuilder() .add(TYPE, "DataAddress") .add("type", "test-type") @@ -618,7 +624,6 @@ void createAsset_whenCatalogInPrivateProps_shouldReturnCatalogType( .statusCode(200) .body(ID, is(id)); - // verify the property was set var asset = index.findById(id); assertThat(asset.isCatalog()).isTrue(); @@ -632,8 +637,8 @@ void createAsset_whenCatalogInPrivateProps_shouldReturnCatalogType( .statusCode(200) .extract().body().as(Map[].class); - assertThat(assets).isNotNull().hasSize(1); - assertThat(Asset.EDC_CATALOG_ASSET_TYPE).contains(assets[0].get(TYPE).toString()); + assertThat(assets).isNotNull().hasSize(1).singleElement() + .extracting(it -> it.get(TYPE)).isEqualTo(Asset.EDC_CATALOG_ASSET_TYPE_TERM); } @Test From b5e78d57f565498522dd4e9b0af070fd7e31b2d8 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Fri, 5 Jun 2026 09:27:37 +0200 Subject: [PATCH 2/3] get ri of catalogFormat --- .../services/asset/AssetServiceImpl.java | 10 +++++----- .../catalog/DefaultDistributionResolver.java | 14 ++++---------- .../catalog/DefaultDistributionResolverTest.java | 8 +------- .../schema/management/v4/catalog-asset-schema.json | 6 +----- .../schema/management/v5/catalog-asset-schema.json | 8 ++------ .../controlplane/asset/spi/domain/Asset.java | 6 +----- .../managementapi/v5/AssetApiV5EndToEndTest.java | 3 --- 7 files changed, 14 insertions(+), 41 deletions(-) diff --git a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java index 7a7d6e75a5e..18fc764407d 100644 --- a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java +++ b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java @@ -75,7 +75,7 @@ public ServiceResult create(Asset asset) { return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE); } - logWarningWhenAssetCatalogPropertiesAreNotSet(asset); + logWarningWhenCatalogAssetPropertyIsNotSet(asset); return transactionContext.execute(() -> index.create(asset) @@ -111,7 +111,7 @@ public ServiceResult update(Asset asset) { return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE); } - logWarningWhenAssetCatalogPropertiesAreNotSet(asset); + logWarningWhenCatalogAssetPropertyIsNotSet(asset); return transactionContext.execute(() -> index.updateAsset(asset) @@ -121,9 +121,9 @@ public ServiceResult update(Asset asset) { } @Deprecated(since = "management-api:v4") - private void logWarningWhenAssetCatalogPropertiesAreNotSet(Asset asset) { - if (asset.isCatalog() && (asset.getCatalogUrl() == null || asset.getCatalogFormat() == null)) { - monitor.warning("The 'CatalogAsset' type is expecting 'catalogUrl' and 'catalogFormat' properties," + + private void logWarningWhenCatalogAssetPropertyIsNotSet(Asset asset) { + if (asset.isCatalog() && asset.getCatalogUrl() == null) { + monitor.warning("The 'CatalogAsset' type is expecting 'catalogUrl' property" + "please adapt your clients accordingly"); } } diff --git a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java index 839ff512d94..3fd9e2ac9d5 100644 --- a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java +++ b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java @@ -42,22 +42,16 @@ public DefaultDistributionResolver(DataServiceRegistry dataServiceRegistry, Data @Override public List getDistributions(String protocol, Asset asset) { if (asset.isCatalog()) { - var catalogFormat = asset.getCatalogFormat(); - if (catalogFormat == null) { - monitor.warning(""" - Asset %s has no '%s' property and the DataAddress type is used instead, please adapt it as the - DataAddress will be removed from Asset in the forthcoming versions""" - .formatted(asset.getId(), Asset.PROPERTY_CATALOG_FORMAT)); - catalogFormat = asset.getDataAddress().getType(); - } return List.of(Distribution.Builder.newInstance() - .format(catalogFormat) + .format("application/json") .dataService(DataService.Builder.newInstance() .id(Base64.getUrlEncoder().encodeToString(asset.getId().getBytes())) .build()) .build()); } - return dataFlowController.transferTypesFor(asset).stream().map((format) -> createDistribution(asset.getParticipantContextId(), protocol, format)).toList(); + return dataFlowController.transferTypesFor(asset).stream() + .map((format) -> createDistribution(asset.getParticipantContextId(), protocol, format)) + .toList(); } private Distribution createDistribution(String participantContextId, String protocol, String format) { diff --git a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java index b289810dfee..ad7dd5a77db 100644 --- a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java +++ b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java @@ -18,7 +18,6 @@ import org.eclipse.edc.connector.controlplane.catalog.spi.DataService; import org.eclipse.edc.connector.controlplane.catalog.spi.DataServiceRegistry; import org.eclipse.edc.connector.controlplane.transfer.spi.flow.DataFlowController; -import org.eclipse.edc.dataaddress.httpdata.spi.HttpDataAddressSchema; import org.eclipse.edc.spi.types.domain.DataAddress; import org.junit.jupiter.api.Test; @@ -65,12 +64,7 @@ void shouldReturnDistribution_whenAssetIsCatalog() { when(dataServiceRegistry.getDataServices(any(), any())).thenReturn(List.of(dataService)); when(dataFlowController.transferTypesFor(any(Asset.class))).thenReturn(Set.of("type1", "type2")); - var dataAddress = DataAddress.Builder.newInstance() - .type("HttpData") - .property(HttpDataAddressSchema.BASE_URL, "http://quizzqua.zz/buzz") - .build(); var asset = Asset.Builder.newInstance() - .dataAddress(dataAddress) .property(Asset.PROPERTY_IS_CATALOG, true) .description("test description") .build(); @@ -79,7 +73,7 @@ void shouldReturnDistribution_whenAssetIsCatalog() { assertThat(distributions).hasSize(1) .anySatisfy(distribution -> { - assertThat(distribution.getFormat()).isEqualTo("HttpData"); + assertThat(distribution.getFormat()).isEqualTo("application/json"); assertThat(distribution.getDataService().getId()).isNotNull(); }); } diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json index 52861ed84a9..42b0f1cc986 100644 --- a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json @@ -25,15 +25,11 @@ "properties": { "type": "object", "example": { - "catalogUrl": "http://catalog/url", - "catalogFormat": "http" + "catalogUrl": "http://catalog/url" }, "properties": { "catalogUrl": { "type": "string" - }, - "catalogFormat": { - "type": "string" } } }, diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json index def813dd42d..8f68d37903b 100644 --- a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json @@ -25,18 +25,14 @@ "properties": { "type": "object", "example": { - "catalogUrl": "http://catalog/url", - "catalogFormat": "http" + "catalogUrl": "http://catalog/url" }, "properties": { "catalogUrl": { "type": "string" - }, - "catalogFormat": { - "type": "string" } }, - "required": ["catalogUrl", "catalogFormat"] + "required": ["catalogUrl"] }, "privateProperties": { "type": "object" diff --git a/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java b/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java index 285552664c0..202ba68b7cf 100644 --- a/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java +++ b/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java @@ -41,7 +41,6 @@ public class Asset extends AbstractParticipantResource { public static final String PROPERTY_DESCRIPTION = EDC_NAMESPACE + "description"; public static final String PROPERTY_IS_CATALOG = EDC_NAMESPACE + "isCatalog"; public static final String PROPERTY_CATALOG_URL = EDC_NAMESPACE + "catalogUrl"; - public static final String PROPERTY_CATALOG_FORMAT = EDC_NAMESPACE + "catalogFormat"; public static final String EDC_ASSET_TYPE_TERM = "Asset"; public static final String EDC_ASSET_TYPE = EDC_NAMESPACE + EDC_ASSET_TYPE_TERM; public static final String EDC_CATALOG_ASSET_TYPE_TERM = "CatalogAsset"; @@ -82,10 +81,6 @@ public String getCatalogUrl() { return getPropertyAsString(PROPERTY_CATALOG_URL); } - public String getCatalogFormat() { - return getPropertyAsString(PROPERTY_CATALOG_FORMAT); - } - public Map getProperties() { return properties; } @@ -199,6 +194,7 @@ public Builder property(String key, Object value) { return self(); } + @Deprecated(since = "0.18.0") public Builder dataAddress(DataAddress dataAddress) { entity.dataAddress = dataAddress; return self(); diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java index d567bdbf8a3..56a06dae917 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java @@ -570,7 +570,6 @@ void createAsset_whenCatalogAsset_shouldSetProperty(ManagementEndToEndV5TestCont .add(ID, id) .add("properties", createPropertiesBuilder() .add("catalogUrl", "http://catalog-url") - .add("catalogFormat", "http") .build()) .add("dataAddress", createObjectBuilder() .add(TYPE, "DataAddress") @@ -592,7 +591,6 @@ void createAsset_whenCatalogAsset_shouldSetProperty(ManagementEndToEndV5TestCont assertThat(asset).isNotNull(); assertThat(asset.isCatalog()).isTrue(); assertThat(asset.getCatalogUrl()).isEqualTo("http://catalog-url"); - assertThat(asset.getCatalogFormat()).isEqualTo("http"); } @Test @@ -605,7 +603,6 @@ void createAsset_whenCatalogInPrivateProps_shouldReturnCatalogType( .add(ID, id) .add("properties", createPropertiesBuilder() .add("catalogUrl", "http://catalog-url") - .add("catalogFormat", "http") .build()) .add("dataAddress", createObjectBuilder() .add(TYPE, "DataAddress") From 3c3cae791a9dc1844dc4e2e9ddd888116210cdf7 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Fri, 5 Jun 2026 11:47:20 +0200 Subject: [PATCH 3/3] define endpointURL and format properties --- .../document/dspace-edc-context-v1.jsonld | 9 ++++ .../document/management-context-v2.jsonld | 11 ++++- .../services/asset/AssetServiceImpl.java | 14 +++--- .../control-plane-catalog/build.gradle.kts | 1 + .../catalog/DatasetResolverImpl.java | 14 +++--- .../catalog/DefaultDistributionResolver.java | 15 ++++++- .../DefaultDistributionResolverTest.java | 4 +- .../management/v4/catalog-asset-schema.json | 8 +++- .../schema/management/v5/asset-schema.json | 2 +- .../management/v5/catalog-asset-schema.json | 12 ++++-- .../controlplane/asset/spi/domain/Asset.java | 9 +--- .../v5/AssetApiV5EndToEndTest.java | 43 +++++++++++-------- .../v5/CatalogApiV5EndToEndTest.java | 42 +++++++++--------- 13 files changed, 114 insertions(+), 70 deletions(-) diff --git a/core/common/lib/json-ld-lib/src/main/resources/document/dspace-edc-context-v1.jsonld b/core/common/lib/json-ld-lib/src/main/resources/document/dspace-edc-context-v1.jsonld index 3fafd229b9f..4b4b1c2e59d 100644 --- a/core/common/lib/json-ld-lib/src/main/resources/document/dspace-edc-context-v1.jsonld +++ b/core/common/lib/json-ld-lib/src/main/resources/document/dspace-edc-context-v1.jsonld @@ -3,6 +3,7 @@ "@version": 1.1, "edc": "https://w3id.org/edc/v0.0.1/ns/", "dct": "http://purl.org/dc/terms/", + "dcat": "http://www.w3.org/ns/dcat#", "QuerySpec": { "@id": "edc:QuerySpec", "@context": { @@ -31,6 +32,14 @@ "conformsTo": { "@id": "dct:conformsTo", "@type": "@id" + }, + "endpointURL": { + "@id": "dcat:endpointURL", + "@type": "@id" + }, + "format": { + "@id": "dct:format", + "@type": "@id" } } } \ No newline at end of file diff --git a/core/common/lib/json-ld-lib/src/main/resources/document/management-context-v2.jsonld b/core/common/lib/json-ld-lib/src/main/resources/document/management-context-v2.jsonld index 32ba3feedac..36d4a1279b9 100644 --- a/core/common/lib/json-ld-lib/src/main/resources/document/management-context-v2.jsonld +++ b/core/common/lib/json-ld-lib/src/main/resources/document/management-context-v2.jsonld @@ -3,6 +3,7 @@ "@version": 1.1, "edc": "https://w3id.org/edc/v0.0.1/ns/", "dct": "http://purl.org/dc/terms/", + "dcat": "http://www.w3.org/ns/dcat#", "Asset": { "@id": "edc:Asset", "@context": { @@ -56,7 +57,15 @@ "properties": { "@id": "edc:properties", "@context": { - "@vocab": "https://w3id.org/edc/v0.0.1/ns/" + "@vocab": "https://w3id.org/edc/v0.0.1/ns/", + "endpointURL": { + "@id": "dcat:endpointURL", + "@type": "@id" + }, + "format": { + "@id": "dct:format", + "@type": "@id" + } } }, "privateProperties": { diff --git a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java index 18fc764407d..d1c5701a31e 100644 --- a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java +++ b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/asset/AssetServiceImpl.java @@ -32,6 +32,8 @@ import java.util.function.Predicate; import static java.lang.String.format; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_ENDPOINT_URL_ATTRIBUTE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCT_FORMAT_ATTRIBUTE; public class AssetServiceImpl implements AssetService { @@ -75,7 +77,7 @@ public ServiceResult create(Asset asset) { return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE); } - logWarningWhenCatalogAssetPropertyIsNotSet(asset); + logWarningWhenCatalogAssetPropertiesAreNotSet(asset); return transactionContext.execute(() -> index.create(asset) @@ -111,7 +113,7 @@ public ServiceResult update(Asset asset) { return ServiceResult.badRequest(DUPLICATED_KEYS_MESSAGE); } - logWarningWhenCatalogAssetPropertyIsNotSet(asset); + logWarningWhenCatalogAssetPropertiesAreNotSet(asset); return transactionContext.execute(() -> index.updateAsset(asset) @@ -121,10 +123,10 @@ public ServiceResult update(Asset asset) { } @Deprecated(since = "management-api:v4") - private void logWarningWhenCatalogAssetPropertyIsNotSet(Asset asset) { - if (asset.isCatalog() && asset.getCatalogUrl() == null) { - monitor.warning("The 'CatalogAsset' type is expecting 'catalogUrl' property" + - "please adapt your clients accordingly"); + private void logWarningWhenCatalogAssetPropertiesAreNotSet(Asset asset) { + if (asset.isCatalog() && (asset.getProperty(DCAT_ENDPOINT_URL_ATTRIBUTE) == null || asset.getProperty(DCT_FORMAT_ATTRIBUTE) == null)) { + monitor.warning("The 'CatalogAsset' type is expecting 'endpointURL' and 'format' properties " + + "please adapt your clients accordingly"); } } diff --git a/core/control-plane/control-plane-catalog/build.gradle.kts b/core/control-plane/control-plane-catalog/build.gradle.kts index 1751dcb292b..3d1db5940aa 100644 --- a/core/control-plane/control-plane-catalog/build.gradle.kts +++ b/core/control-plane/control-plane-catalog/build.gradle.kts @@ -17,6 +17,7 @@ plugins { } dependencies { + api(project(":spi:common:json-ld-spi")) api(project(":spi:control-plane:catalog-spi")) api(project(":spi:control-plane:contract-spi")) api(project(":spi:control-plane:transfer-spi")) diff --git a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java index 56998e7b97f..f78df91c78a 100644 --- a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java +++ b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DatasetResolverImpl.java @@ -43,6 +43,7 @@ import java.util.stream.Stream; import static java.lang.Integer.MAX_VALUE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_ENDPOINT_URL_ATTRIBUTE; import static org.eclipse.edc.participantcontext.spi.types.ParticipantResource.filterByParticipantContextId; import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; @@ -107,19 +108,20 @@ public Dataset getById(ParticipantContext participantContext, ParticipantAgent a return Dataset.Builder.newInstance(); } - var catalogUrl = asset.getCatalogUrl(); - if (catalogUrl == null) { + var endpointUrl = asset.getPropertyAsString(DCAT_ENDPOINT_URL_ATTRIBUTE); + if (endpointUrl == null) { monitor.warning(""" - Asset %s has no '%s' property and the DataAddress type is used instead, please adapt it as the + Asset %s has no 'endpointURL' property and the DataAddress baseUrl is used instead, please adapt it as the DataAddress will be removed from Asset in the forthcoming versions""" - .formatted(asset.getId(), Asset.PROPERTY_CATALOG_URL)); - catalogUrl = asset.getDataAddress().getStringProperty(EDC_NAMESPACE + "baseUrl", null); + .formatted(asset.getId())); + endpointUrl = asset.getDataAddress().getStringProperty(EDC_NAMESPACE + "baseUrl", null); } + return Catalog.Builder.newInstance() .dataService(DataService.Builder.newInstance() .id(Base64.getUrlEncoder().encodeToString(asset.getId().getBytes())) .endpointDescription(asset.getDescription()) - .endpointUrl(catalogUrl) + .endpointUrl(endpointUrl) .build()); } diff --git a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java index 3fd9e2ac9d5..d2e5a249ebe 100644 --- a/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java +++ b/core/control-plane/control-plane-catalog/src/main/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolver.java @@ -22,9 +22,13 @@ import org.eclipse.edc.connector.controlplane.catalog.spi.DistributionResolver; import org.eclipse.edc.connector.controlplane.transfer.spi.flow.DataFlowController; import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.domain.DataAddress; import java.util.Base64; import java.util.List; +import java.util.Optional; + +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCT_FORMAT_ATTRIBUTE; public class DefaultDistributionResolver implements DistributionResolver { @@ -42,8 +46,17 @@ public DefaultDistributionResolver(DataServiceRegistry dataServiceRegistry, Data @Override public List getDistributions(String protocol, Asset asset) { if (asset.isCatalog()) { + var format = asset.getPropertyAsString(DCT_FORMAT_ATTRIBUTE); + if (format == null) { + monitor.warning(""" + Asset %s has no 'format' property and the DataAddress type is used instead, please adapt it as the + DataAddress will be removed from Asset in the forthcoming versions""" + .formatted(asset.getId())); + format = Optional.ofNullable(asset.getDataAddress()).map(DataAddress::getType).orElse(""); + } + return List.of(Distribution.Builder.newInstance() - .format("application/json") + .format(format) .dataService(DataService.Builder.newInstance() .id(Base64.getUrlEncoder().encodeToString(asset.getId().getBytes())) .build()) diff --git a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java index ad7dd5a77db..65dfb9f2f53 100644 --- a/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java +++ b/core/control-plane/control-plane-catalog/src/test/java/org/eclipse/edc/connector/controlplane/catalog/DefaultDistributionResolverTest.java @@ -18,6 +18,7 @@ import org.eclipse.edc.connector.controlplane.catalog.spi.DataService; import org.eclipse.edc.connector.controlplane.catalog.spi.DataServiceRegistry; import org.eclipse.edc.connector.controlplane.transfer.spi.flow.DataFlowController; +import org.eclipse.edc.jsonld.spi.PropertyAndTypeNames; import org.eclipse.edc.spi.types.domain.DataAddress; import org.junit.jupiter.api.Test; @@ -66,6 +67,7 @@ void shouldReturnDistribution_whenAssetIsCatalog() { var asset = Asset.Builder.newInstance() .property(Asset.PROPERTY_IS_CATALOG, true) + .property(PropertyAndTypeNames.DCT_FORMAT_ATTRIBUTE, "format") .description("test description") .build(); @@ -73,7 +75,7 @@ void shouldReturnDistribution_whenAssetIsCatalog() { assertThat(distributions).hasSize(1) .anySatisfy(distribution -> { - assertThat(distribution.getFormat()).isEqualTo("application/json"); + assertThat(distribution.getFormat()).isEqualTo("format"); assertThat(distribution.getDataService().getId()).isNotNull(); }); } diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json index 42b0f1cc986..67f55da537d 100644 --- a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/catalog-asset-schema.json @@ -25,10 +25,14 @@ "properties": { "type": "object", "example": { - "catalogUrl": "http://catalog/url" + "endpointURL": "http://catalog/url", + "format": "http://w3c.org/dspace/profile/catalog" }, "properties": { - "catalogUrl": { + "endpointURL": { + "type": "string" + }, + "format": { "type": "string" } } diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json index b89b12c0895..c8585a6dee9 100644 --- a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/asset-schema.json @@ -7,7 +7,7 @@ "$ref": "#/definitions/Asset" } ], - "$id": "https://w3id.org/edc/connector/management/schema/v4/asset-schema.json", + "$id": "https://w3id.org/edc/connector/management/schema/v5/asset-schema.json", "definitions": { "Asset": { "type": "object", diff --git a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json index 8f68d37903b..6870d6a7911 100644 --- a/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json +++ b/extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v5/catalog-asset-schema.json @@ -7,7 +7,7 @@ "$ref": "#/definitions/CatalogAsset" } ], - "$id": "https://w3id.org/edc/connector/management/schema/v4/catalog-asset-schema.json", + "$id": "https://w3id.org/edc/connector/management/schema/v5/catalog-asset-schema.json", "definitions": { "CatalogAsset": { "type": "object", @@ -25,14 +25,18 @@ "properties": { "type": "object", "example": { - "catalogUrl": "http://catalog/url" + "endpointURL": "http://catalog/url", + "format": "http://w3c.org/dspace/profile/catalog" }, "properties": { - "catalogUrl": { + "endpointURL": { + "type": "string" + }, + "format": { "type": "string" } }, - "required": ["catalogUrl"] + "required": ["endpointURL", "format"] }, "privateProperties": { "type": "object" diff --git a/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java b/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java index 202ba68b7cf..d19cca95dd6 100644 --- a/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java +++ b/spi/control-plane/asset-spi/src/main/java/org/eclipse/edc/connector/controlplane/asset/spi/domain/Asset.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import org.eclipse.edc.participantcontext.spi.types.AbstractParticipantResource; import org.eclipse.edc.spi.types.domain.DataAddress; -import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; @@ -40,7 +39,6 @@ public class Asset extends AbstractParticipantResource { public static final String PROPERTY_ID = EDC_NAMESPACE + "id"; public static final String PROPERTY_DESCRIPTION = EDC_NAMESPACE + "description"; public static final String PROPERTY_IS_CATALOG = EDC_NAMESPACE + "isCatalog"; - public static final String PROPERTY_CATALOG_URL = EDC_NAMESPACE + "catalogUrl"; public static final String EDC_ASSET_TYPE_TERM = "Asset"; public static final String EDC_ASSET_TYPE = EDC_NAMESPACE + EDC_ASSET_TYPE_TERM; public static final String EDC_CATALOG_ASSET_TYPE_TERM = "CatalogAsset"; @@ -76,11 +74,6 @@ public boolean isCatalog() { .orElse(false); } - @Nullable - public String getCatalogUrl() { - return getPropertyAsString(PROPERTY_CATALOG_URL); - } - public Map getProperties() { return properties; } @@ -128,7 +121,7 @@ public boolean hasDuplicatePropertyKeys() { return true; } - private String getPropertyAsString(String key) { + public String getPropertyAsString(String key) { var val = getProperty(key); return val != null ? val.toString() : null; } diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java index 56a06dae917..5079627c496 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/AssetApiV5EndToEndTest.java @@ -51,13 +51,16 @@ 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; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_ENDPOINT_URL_ATTRIBUTE; import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCT_CONFORMS_TO_ATTRIBUTE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCT_FORMAT_ATTRIBUTE; import static org.eclipse.edc.spi.constants.CoreConstants.EDC_CONNECTOR_MANAGEMENT_CONTEXT_V2; import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; import static org.eclipse.edc.spi.query.Criterion.criterion; import static org.eclipse.edc.test.e2e.managementapi.v5.TestFunction.createParticipant; import static org.eclipse.edc.test.e2e.managementapi.v5.TestFunction.participantContext; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesRegex; import static org.hamcrest.Matchers.notNullValue; @@ -569,11 +572,8 @@ void createAsset_whenCatalogAsset_shouldSetProperty(ManagementEndToEndV5TestCont .add(TYPE, "CatalogAsset") .add(ID, id) .add("properties", createPropertiesBuilder() - .add("catalogUrl", "http://catalog-url") - .build()) - .add("dataAddress", createObjectBuilder() - .add(TYPE, "DataAddress") - .add("type", "test-type") + .add("endpointURL", "http://catalog-url") + .add("format", "http://format") .build()) .build() .toString(); @@ -583,14 +583,23 @@ void createAsset_whenCatalogAsset_shouldSetProperty(ManagementEndToEndV5TestCont .body(assetJson) .post("/v5beta/participants/" + PARTICIPANT_CONTEXT_ID + "/assets") .then() - .log().ifError() + .log().ifValidationFails() .statusCode(200) .body(ID, is(id)); + context.baseRequest(participantTokenJwt) + .get("/v5beta/participants/" + PARTICIPANT_CONTEXT_ID + "/assets/" + id) + .then() + .log().ifValidationFails() + .statusCode(200) + .body("properties.endpointURL", equalTo("http://catalog-url")) + .body("properties.format", equalTo("http://format")); + var asset = assetIndex.findById(id); assertThat(asset).isNotNull(); assertThat(asset.isCatalog()).isTrue(); - assertThat(asset.getCatalogUrl()).isEqualTo("http://catalog-url"); + assertThat(asset.getPropertyAsString(DCAT_ENDPOINT_URL_ATTRIBUTE)).isNotNull(); + assertThat(asset.getPropertyAsString(DCT_FORMAT_ATTRIBUTE)).isNotNull(); } @Test @@ -602,8 +611,10 @@ void createAsset_whenCatalogInPrivateProps_shouldReturnCatalogType( .add(TYPE, "CatalogAsset") .add(ID, id) .add("properties", createPropertiesBuilder() - .add("catalogUrl", "http://catalog-url") - .build()) + .add("endpointURL", "http://catalog-url") + .add("format", "http://format") + .build() + ) .add("dataAddress", createObjectBuilder() .add(TYPE, "DataAddress") .add("type", "test-type") @@ -624,18 +635,12 @@ void createAsset_whenCatalogInPrivateProps_shouldReturnCatalogType( var asset = index.findById(id); assertThat(asset.isCatalog()).isTrue(); - // query the asset, assert that @type: CatalogAsset - var assets = context.baseRequest(participantTokenJwt) - .contentType(ContentType.JSON) - .body(context.query(criterion("id", "=", id)).toString()) - .post("/v5beta/participants/" + PARTICIPANT_CONTEXT_ID + "/assets/request") + context.baseRequest(participantTokenJwt) + .get("/v5beta/participants/" + PARTICIPANT_CONTEXT_ID + "/assets/" + id) .then() - .log().ifError() + .log().ifValidationFails() .statusCode(200) - .extract().body().as(Map[].class); - - assertThat(assets).isNotNull().hasSize(1).singleElement() - .extracting(it -> it.get(TYPE)).isEqualTo(Asset.EDC_CATALOG_ASSET_TYPE_TERM); + .body("'@type'", equalTo(Asset.EDC_CATALOG_ASSET_TYPE_TERM)); } @Test diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/CatalogApiV5EndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/CatalogApiV5EndToEndTest.java index 16ce43ec9bd..55c427f962e 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/CatalogApiV5EndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/CatalogApiV5EndToEndTest.java @@ -25,6 +25,7 @@ import org.eclipse.edc.connector.controlplane.policy.spi.store.PolicyDefinitionStore; import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.jsonld.spi.PropertyAndTypeNames; import org.eclipse.edc.junit.annotations.EndToEndTest; import org.eclipse.edc.junit.annotations.PostgresqlIntegrationTest; import org.eclipse.edc.junit.extensions.ComponentRuntimeExtension; @@ -52,6 +53,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Stream; import static io.restassured.http.ContentType.JSON; import static jakarta.json.Json.createArrayBuilder; @@ -316,24 +318,24 @@ void requestCatalog_whenAssetIsCatalogAsset_shouldReturnCatalogOfCatalogs(Manage PolicyDefinitionStore policyDefinitionStore, ContractDefinitionStore contractDefinitionStore) { - // create CatalogAsset var catalogAssetId = "catalog-asset-" + UUID.randomUUID(); - var httpData = createAsset(catalogAssetId, "HttpData") + var catalogAsset = createAssetBuilder(catalogAssetId) .property(Asset.PROPERTY_IS_CATALOG, true) + .property(PropertyAndTypeNames.DCAT_ENDPOINT_URL_ATTRIBUTE, "http://quizzqua.zz/buzz") + .property(PropertyAndTypeNames.DCT_FORMAT_ATTRIBUTE, "format") .participantContextId(COUNTER_PARTY_ID) .build(); - httpData.getDataAddress().getProperties().put(EDC_NAMESPACE + "baseUrl", "http://quizzqua.zz/buzz"); - assetIndex.create(httpData); - // create conventional asset - var normalAssetId = "normal-asset-" + UUID.randomUUID(); - assetIndex.create(createAsset(normalAssetId, "test-type").participantContextId(COUNTER_PARTY_ID).build()); + assetIndex.create(catalogAsset); - var assetSelectorCriteria = List.of(Criterion.criterion("id", "in", List.of(catalogAssetId, normalAssetId))); + var conventionalAssetId = "normal-asset-" + UUID.randomUUID(); + var conventionalAsset = createAsset(conventionalAssetId, "test-type").participantContextId(COUNTER_PARTY_ID).build(); + Stream.of(catalogAsset, conventionalAsset).forEach(assetIndex::create); + + var assetSelectorCriteria = List.of(Criterion.criterion("id", "in", List.of(catalogAssetId, conventionalAssetId))); createContractOffer(policyDefinitionStore, contractDefinitionStore, assetSelectorCriteria); - // request all assets var requestBody = createObjectBuilder() .add(CONTEXT, createArrayBuilder().add(EDC_CONNECTOR_MANAGEMENT_CONTEXT_V2)) .add(TYPE, "CatalogRequest") @@ -343,23 +345,21 @@ void requestCatalog_whenAssetIsCatalogAsset_shouldReturnCatalogOfCatalogs(Manage .build() .toString(); - var body = context.baseRequest(participantTokenJwt) + context.baseRequest(participantTokenJwt) .contentType(JSON) .body(requestBody) .post("/v5beta/participants/%s/catalog/request".formatted(PARTICIPANT_CONTEXT_ID)) .then() .statusCode(200) - .contentType(JSON); - - var str = body.extract().asString(); - body.body(TYPE, is("Catalog")) + .contentType(JSON) + .body(TYPE, is("Catalog")) .body("'service'", notNullValue()) - // findAll is the restAssured way to express JSON Path filters .body("catalog[0].'@type'", equalTo("Catalog")) .body("catalog[0].isCatalog", equalTo(true)) .body("catalog[0].'@id'", equalTo(catalogAssetId)) .body("catalog[0].service[0].endpointURL", equalTo("http://quizzqua.zz/buzz")) - .body("catalog[0].distribution[0].accessService.'@id'", equalTo(Base64.getUrlEncoder().encodeToString(catalogAssetId.getBytes()))); + .body("catalog[0].distribution[0].accessService.'@id'", equalTo(Base64.getUrlEncoder().encodeToString(catalogAssetId.getBytes()))) + .body("catalog[0].distribution[0].format", equalTo("format")); } @Test @@ -445,7 +445,7 @@ void getDatasetWithResponseChannel_shouldReturnDataset(ManagementEndToEndV5TestC .type("test-type") .responseChannel(responseChannel) .build(); - assetIndex.create(createAsset("asset-response", dataAddressWithResponseChannel).build()); + assetIndex.create(createAssetBuilder("asset-response").dataAddress(dataAddressWithResponseChannel).build()); var requestBody = createObjectBuilder() .add(CONTEXT, createArrayBuilder().add(EDC_CONNECTOR_MANAGEMENT_CONTEXT_V2)) .add(TYPE, "DatasetRequest") @@ -692,17 +692,17 @@ private Asset.Builder createAsset(String id, String sourceType) { var address = DataAddress.Builder.newInstance() .type(sourceType) .build(); - return createAsset(id, address); + + return createAssetBuilder(id) + .dataAddress(address); } - private Asset.Builder createAsset(String id, DataAddress address) { + private Asset.Builder createAssetBuilder(String id) { return Asset.Builder.newInstance() - .dataAddress(address) .participantContextId(PARTICIPANT_CONTEXT_ID) .id(id); } - private void createParticipant(ParticipantContextService participantContextService, ParticipantContextConfigStore configStore, String participantContextId) { var pc = ParticipantContext.Builder.newInstance()