Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(registry):[#616] Add new filter type for digital twin registry c… #647

Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ _**For better traceability add the corresponding GitHub issue number in each cha

## [Unreleased]

### Fixed

- IRS now searches for Digital Twin Registry contract offers by
type `dct:type`: `https://w3id.org/catenax/taxonomy#DigitalTwinRegistry`
or `edc:type`: `data.core.digitalTwinRegistry`. #616
- Fix missing and malformed properties for EDC policy transformation. #648


## [5.1.2] - 2024-05-13

### Fixed
Expand Down
6 changes: 3 additions & 3 deletions docs/src/api/irs-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ paths:
createdOn: 2024-03-28T03:34:42.9454448Z
validUntil: 2025-12-12T23:59:59.999Z
permissions:
- action: USE
- action: use
constraint:
and:
- leftOperand: Membership
Expand Down Expand Up @@ -1807,7 +1807,7 @@ components:
policy:
'@type': Policy
odrl:permission:
- odrl:action: USE
- odrl:action: use
odrl:constraint:
odrl:and:
- odrl:leftOperand: Membership
Expand Down Expand Up @@ -2200,7 +2200,7 @@ components:
policy:
'@type': Policy
odrl:permission:
- odrl:action: USE
- odrl:action: use
odrl:constraint:
odrl:and:
- odrl:leftOperand: Membership
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ public DecentralDigitalTwinRegistryService decentralDigitalTwinRegistryService(
@Value("${digitalTwinRegistry.lookupShellsTemplate:}") final String lookupShellsTemplate,
final EdcConfiguration edcConfiguration) {

final EdcEndpointReferenceRetriever endpointReferenceRetriever = (edcConnectorEndpoint, assetType, assetValue, bpn) -> {
final EdcEndpointReferenceRetriever endpointReferenceRetriever = (edcConnectorEndpoint, bpn) -> {
try {
return facade.getEndpointReferencesForAsset(edcConnectorEndpoint, assetType, assetValue, bpn);
return facade.getEndpointReferencesForRegistryAsset(edcConnectorEndpoint, bpn);
} catch (EdcClientException e) {
throw new EdcRetrieverException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ private void registerPolicy(final String policyId) {
"policy": {
"odrl:permission": [
{
"odrl:action": "USE",
"odrl:action": "use",
"odrl:constraint": {
"@type": "AtomicConstraint",
"odrl:or": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
/**
* Public API facade for EDC domain
*/
@SuppressWarnings({"PMD.ExcessiveImports", "PMD.UseObjectForClearerAPI"})
@SuppressWarnings({ "PMD.ExcessiveImports",
"PMD.UseObjectForClearerAPI"
})
public interface EdcSubmodelClient {

CompletableFuture<SubmodelDescriptor> getSubmodelPayload(String connectorEndpoint, String submodelDataplaneUrl,
Expand All @@ -52,5 +54,8 @@ List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForAsset(Str
List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForAsset(String endpointAddress,
String filterKey, String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference, String bpn)
throws EdcClientException;

List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForRegistryAsset(String endpointAddress,
String bpn) throws EdcClientException;
}

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static org.eclipse.tractusx.irs.edc.client.configuration.JsonLdConfiguration.NAMESPACE_EDC_ID;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
Expand All @@ -52,6 +53,7 @@
import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotificationResponse;
import org.eclipse.tractusx.irs.edc.client.model.notification.NotificationContent;
import org.eclipse.tractusx.irs.edc.client.util.Masker;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.StopWatch;

/**
Expand All @@ -65,6 +67,11 @@
})
public class EdcSubmodelClientImpl implements EdcSubmodelClient {

private static final String DT_DCAT_TYPE_ID = "'http://purl.org/dc/terms/type'.'@id'";
private static final String DT_TAXONOMY_REGISTRY = "https://w3id.org/catenax/taxonomy#DigitalTwinRegistry";
private static final String DT_EDC_TYPE = "https://w3id.org/edc/v0.0.1/ns/type";
private static final String DT_DATA_CORE_REGISTRY = "data.core.digitalTwinRegistry";

private final EdcConfiguration config;
private final ContractNegotiationService contractNegotiationService;
private final EdcDataPlaneClient edcDataPlaneClient;
Expand Down Expand Up @@ -99,8 +106,7 @@ private Optional<SubmodelDescriptor> retrieveSubmodelData(final String submodelD
final String payload = edcDataPlaneClient.getData(endpointDataReference, submodelDataplaneUrl);
stopWatchOnEdcTask(stopWatch);

return Optional.of(
new SubmodelDescriptor(endpointDataReference.getContractId(), payload));
return Optional.of(new SubmodelDescriptor(endpointDataReference.getContractId(), payload));
}

return Optional.empty();
Expand Down Expand Up @@ -234,11 +240,17 @@ public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForAs
endpointAddress, filterKey, filterValue));
}

// We need to process each contract offer in parallel
// (see src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml
// and src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml)
return contractOffers.stream().map(contractOffer -> {
return createCompletableFuturesForContractOffers(endpointDataReferenceStatus, bpn, contractOffers,
providerWithSuffix, stopWatch);
}

// We need to process each contract offer in parallel
// (see src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml
// and src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml)
private @NotNull List<CompletableFuture<EndpointDataReference>> createCompletableFuturesForContractOffers(
final EndpointDataReferenceStatus endpointDataReferenceStatus, final String bpn,
final List<CatalogItem> contractOffers, final String providerWithSuffix, final StopWatch stopWatch) {
return contractOffers.stream().map(contractOffer -> {
final NegotiationResponse negotiationResponse;
try {
negotiationResponse = negotiateContract(endpointDataReferenceStatus, contractOffer, providerWithSuffix,
Expand All @@ -262,6 +274,41 @@ public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForAs
}).toList();
}

@Override
public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForRegistryAsset(
final String endpointAddress, final String bpn) throws EdcClientException {
return execute(endpointAddress, () -> getEndpointReferencesForRegistryAsset(endpointAddress,
new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW), bpn));
}

public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForRegistryAsset(
final String endpointAddress, final EndpointDataReferenceStatus endpointDataReferenceStatus,
final String bpn) throws EdcClientException {
final StopWatch stopWatch = new StopWatch();
stopWatch.start("Get EndpointDataReference task for shell descriptor, endpoint " + endpointAddress);
final String providerWithSuffix = appendSuffix(endpointAddress, config.getControlplane().getProviderSuffix());

// CatalogItem = contract offer
final List<CatalogItem> contractOffers = new ArrayList<>(
catalogFacade.fetchCatalogByFilter(providerWithSuffix, DT_DCAT_TYPE_ID, DT_TAXONOMY_REGISTRY, bpn));

if (contractOffers.isEmpty()) {
final List<CatalogItem> contractOffersDataCore = catalogFacade.fetchCatalogByFilter(providerWithSuffix,
DT_EDC_TYPE, DT_DATA_CORE_REGISTRY, bpn);
contractOffers.addAll(contractOffersDataCore);
}

if (contractOffers.isEmpty()) {
throw new EdcClientException(
"No DigitalTwinRegistry contract offers found for endpointAddress '%s' filterKey '%s', filterValue '%s' or filterKey '%s', filterValue '%s'".formatted(
endpointAddress, DT_DCAT_TYPE_ID, DT_TAXONOMY_REGISTRY, DT_EDC_TYPE,
DT_DATA_CORE_REGISTRY));
}

return createCompletableFuturesForContractOffers(endpointDataReferenceStatus, bpn, contractOffers,
providerWithSuffix, stopWatch);
}

private NegotiationResponse negotiateContract(final EndpointDataReferenceStatus endpointDataReferenceStatus,
final CatalogItem catalogItem, final String providerWithSuffix, final String bpn)
throws EdcClientException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
@SuppressWarnings("PMD.UseObjectForClearerAPI")
public class EdcSubmodelClientLocalStub implements EdcSubmodelClient {

public static final String NOT_IMPLEMENTED = "Not implemented";
private final SubmodelTestdataCreator testdataCreator;

/* package */
Expand Down Expand Up @@ -73,12 +74,18 @@ public CompletableFuture<EdcNotificationResponse> sendNotification(final String
public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForAsset(final String endpointAddress,
final String filterKey, final String filterValue,
final EndpointDataReferenceStatus cachedEndpointDataReference, final String bpn) throws EdcClientException {
throw new EdcClientException("Not implemented");
throw new EdcClientException(NOT_IMPLEMENTED);
}

@Override
public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForAsset(final String endpointAddress,
final String filterKey, final String filterValue, final String bpn) throws EdcClientException {
throw new EdcClientException("Not implemented");
throw new EdcClientException(NOT_IMPLEMENTED);
}

@Override
public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForRegistryAsset(
final String endpointAddress, final String bpn) throws EdcClientException {
throw new EdcClientException(NOT_IMPLEMENTED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
*/
@Slf4j
@RequiredArgsConstructor
@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.UseObjectForClearerAPI"})
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals",
"PMD.UseObjectForClearerAPI"
})
public class EdcSubmodelFacade {

private final EdcSubmodelClient client;
Expand Down Expand Up @@ -93,9 +95,9 @@ public EdcNotificationResponse sendNotification(final String submodelEndpointAdd
}
}

public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForAsset(final String endpointAddress,
final String filterKey, final String filterValue, final String bpn) throws EdcClientException {
return client.getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue, bpn);
public List<CompletableFuture<EndpointDataReference>> getEndpointReferencesForRegistryAsset(
final String endpointAddress, final String bpn) throws EdcClientException {
return client.getEndpointReferencesForRegistryAsset(endpointAddress, bpn);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,15 @@ public class EdcAssetService {
private static final String ASSET_CREATION_PROPERTY_DESCRIPTION = "https://w3id.org/edc/v0.0.1/ns/description";
private static final String ASSET_CREATION_PROPERTY_CONTENT_TYPE = "https://w3id.org/edc/v0.0.1/ns/contenttype";
private static final String ASSET_CREATION_PROPERTY_POLICY_ID = "https://w3id.org/edc/v0.0.1/ns/policy-id";
private static final String ASSET_CREATION_PROPERTY_TYPE = "https://w3id.org/edc/v0.0.1/ns/type";
private static final String ASSET_CREATION_PROPERTY_EDC_TYPE = "https://w3id.org/edc/v0.0.1/ns/type";
private static final String ASSET_CREATION_PROPERTY_DATA_CORE_REGISTRY = "data.core.digitalTwinRegistry";
private static final String ASSET_CREATION_PROPERTY_DCAT_TYPE = "http://purl.org/dc/terms/type";
private static final String ASSET_CREATION_PROPERTY_DCAT_REGISTRY = "https://w3id.org/catenax/taxonomy#DigitalTwinRegistry";
private static final String ASSET_CREATION_PROPERTY_COMMON_VERSION_KEY = "https://w3id.org/catenax/ontology/common#version";
private static final String ASSET_CREATION_PROPERTY_COMMON_VERSION_VALUE = "3.0";
private static final String ASSET_CREATION_PROPERTY_NOTIFICATION_TYPE = "https://w3id.org/edc/v0.0.1/ns/notificationtype";
private static final String ASSET_CREATION_PROPERTY_NOTIFICATION_METHOD = "https://w3id.org/edc/v0.0.1/ns/notificationmethod";

public static final String DATA_ADDRESS_TYPE_HTTP_DATA = "HttpData";

private final EdcTransformer edcTransformer;
Expand Down Expand Up @@ -128,7 +134,7 @@ private Asset createNotificationAssetRequest(final String assetName, final Strin
final String assetId = UUID.randomUUID().toString();
final Map<String, Object> properties = Map.of(ASSET_CREATION_PROPERTY_DESCRIPTION, assetName,
ASSET_CREATION_PROPERTY_CONTENT_TYPE, DEFAULT_CONTENT_TYPE, ASSET_CREATION_PROPERTY_POLICY_ID,
DEFAULT_POLICY_ID, ASSET_CREATION_PROPERTY_TYPE, notificationType.getValue(),
DEFAULT_POLICY_ID, ASSET_CREATION_PROPERTY_EDC_TYPE, notificationType.getValue(),
ASSET_CREATION_PROPERTY_NOTIFICATION_TYPE, notificationType.getValue(),
ASSET_CREATION_PROPERTY_NOTIFICATION_METHOD, notificationMethod.getValue());

Expand All @@ -153,7 +159,10 @@ private Asset createNotificationAssetRequest(final String assetName, final Strin

private Asset createDtrAssetRequest(final String assetId, final String baseUrl) {
final Map<String, Object> properties = Map.of(ASSET_CREATION_PROPERTY_DESCRIPTION,
"Digital Twin Registry Asset", ASSET_CREATION_PROPERTY_TYPE, "data.core.digitalTwinRegistry");
"Digital Twin Registry Asset", ASSET_CREATION_PROPERTY_EDC_TYPE,
ASSET_CREATION_PROPERTY_DATA_CORE_REGISTRY, ASSET_CREATION_PROPERTY_COMMON_VERSION_KEY,
ASSET_CREATION_PROPERTY_COMMON_VERSION_VALUE, ASSET_CREATION_PROPERTY_DCAT_TYPE,
Map.of("@id", ASSET_CREATION_PROPERTY_DCAT_REGISTRY));

final DataAddress dataAddress = DataAddress.Builder.newInstance()
.type("DataAddress")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ public class JsonLdConfiguration {
public static final String NAMESPACE_EDC_PARTICIPANT_ID = NAMESPACE_EDC + "participantId";
public static final String NAMESPACE_EDC_ID = NAMESPACE_EDC + "id";
public static final String NAMESPACE_TRACTUSX = "https://w3id.org/tractusx/v0.0.1/ns/";
public static final String NAMESPACE_DCT = "https://purl.org/dc/terms/";
public static final String NAMESPACE_DCT = "http://purl.org/dc/terms/";
public static final String JSON_LD_OBJECT_MAPPER = "jsonLdObjectMapper";
public static final String NAMESPACE_CATENAX_POLICY = "https://w3id.org/catenax/policy/";

@Bean /* package */ TitaniumJsonLd titaniumJsonLd(final Monitor monitor) {
final TitaniumJsonLd titaniumJsonLd = new TitaniumJsonLd(monitor);
Expand All @@ -62,6 +63,7 @@ public class JsonLdConfiguration {
titaniumJsonLd.registerNamespace("edc", NAMESPACE_EDC);
titaniumJsonLd.registerNamespace("dcat", JsonLdConfiguration.NAMESPACE_DCAT);
titaniumJsonLd.registerNamespace("dspace", NAMESPACE_DSPACE);
titaniumJsonLd.registerNamespace("cx-policy", NAMESPACE_CATENAX_POLICY);
return titaniumJsonLd;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
@JsonIgnoreProperties(ignoreUnknown = true)
public class Permission {

@Schema(implementation = PolicyType.class, example = "USE")
@Schema(implementation = PolicyType.class, example = "use")
@JsonAlias({"odrl:action"})
private PolicyType action;
@Schema
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@
********************************************************************************/
package org.eclipse.tractusx.irs.edc.client.policy;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.fasterxml.jackson.annotation.JsonValue;

/**
* A PolicyType object use in Permission
*/
@Getter
@RequiredArgsConstructor
public enum PolicyType {
ACCESS("access"),
USE("use");

ACCESS, USE

@JsonValue
private final String value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@
@RequiredArgsConstructor
public class EdcPolicyDefinitionService {

private static final String USE_ACTION = "USE";
private static final String POLICY_TYPE = "Policy";
private static final String POLICY_DEFINITION_TYPE = "PolicyDefinitionRequestDto";
private static final String ATOMIC_CONSTRAINT = "AtomicConstraint";
private static final String CONSTRAINT = "Constraint";
private static final String OPERATOR_PREFIX = "odrl:";
private static final String USE_ACTION = "use";
ds-jhartmann marked this conversation as resolved.
Show resolved Hide resolved

private final EdcConfiguration config;
private final RestTemplate restTemplate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,20 @@
********************************************************************************/
package org.eclipse.tractusx.irs.edc.client;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException;
import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification;
import org.eclipse.tractusx.irs.edc.client.model.notification.NotificationContent;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class EdcSubmodelClientLocalStubTest {

@Mock
private SubmodelTestdataCreator testdataCreator;

@InjectMocks
private EdcSubmodelClientLocalStub edcSubmodelClientLocalStub;

Expand All @@ -47,6 +46,32 @@ void shouldThrowExceptionFor() {
String assetId = "urn:uuid:c35ee875-5443-4a2d-bc14-fdacd64b9446";

// when
assertThrows(EdcClientException.class, () -> edcSubmodelClientLocalStub.getSubmodelPayload("", "", assetId, ""));
assertThrows(EdcClientException.class,
() -> edcSubmodelClientLocalStub.getSubmodelPayload("", "", assetId, ""));
}

@Test
void sendNotification() {
final EdcNotification<NotificationContent> notification = EdcNotification.builder().build();
final var actual = edcSubmodelClientLocalStub.sendNotification("", "", notification, "");
assertThat(actual).isCompleted();
}

@Test
void getEndpointReferencesForAsset() {
assertThrows(EdcClientException.class,
() -> edcSubmodelClientLocalStub.getEndpointReferencesForAsset("", "", "", ""));
}

@Test
void testGetEndpointReferencesForAsset() {
assertThrows(EdcClientException.class,
() -> edcSubmodelClientLocalStub.getEndpointReferencesForAsset("", "", "", ""));
}

@Test
void getEndpointReferencesForRegistryAsset() {
assertThrows(EdcClientException.class,
() -> edcSubmodelClientLocalStub.getEndpointReferencesForRegistryAsset("", ""));
}
}
Loading
Loading