From db1973af4fbe7cfd29b8a2ad3533bd29d898a098 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 30 Jan 2024 02:58:19 +0100 Subject: [PATCH 01/51] feat(imp):[#214] improve variable names --- .../decentral/DecentralDigitalTwinRegistryService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index 29a74348a5..201ef0091f 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -145,13 +145,12 @@ private CompletableFuture> fetchShellDe LOGPREFIX_TO_BE_REMOVED_LATER + "Fetching %s shells for bpn '%s'".formatted(keys.size(), bpn)); try { - final var connectorEndpoints = connectorEndpointsService.fetchConnectorEndpoints(bpn); + final var edcUrls = connectorEndpointsService.fetchConnectorEndpoints(bpn); - log.info(LOGPREFIX_TO_BE_REMOVED_LATER + "Found {} connector endpoints for bpn '{}'", - connectorEndpoints.size(), bpn); - calledEndpoints.addAll(connectorEndpoints); + log.info(LOGPREFIX_TO_BE_REMOVED_LATER + "Found {} connector endpoints for bpn '{}'", edcUrls.size(), bpn); + calledEndpoints.addAll(edcUrls); - return fetchShellDescriptorsForConnectorEndpoints(keys, connectorEndpoints); + return fetchShellDescriptorsForConnectorEndpoints(keys, edcUrls); } finally { StopwatchUtils.stopWatch(log, watch); From b9d9dab142d286db851c85dbc26b9b39aaa5ff21 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Wed, 31 Jan 2024 12:48:10 +0100 Subject: [PATCH 02/51] feat(imp):[#395] Partial implementation Partial implementation started in context of #214 before story was split up. This commit is just meant to back up the work. It is neither complete nor does it work yet and it still contains compile errors. --- .../irs/edc/client/EdcSubmodelClient.java | 10 +-- .../irs/edc/client/EdcSubmodelClientImpl.java | 67 ++++++++++++++----- .../client/EdcSubmodelClientLocalStub.java | 5 +- .../irs/edc/client/EdcSubmodelFacade.java | 7 +- .../irs/edc/client/EdcSubmodelClientTest.java | 4 +- .../irs/edc/client/EdcSubmodelFacadeTest.java | 6 +- .../EdcEndpointReferenceRetriever.java | 11 +-- .../EndpointDataForConnectorsService.java | 24 +++---- 8 files changed, 85 insertions(+), 49 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java index a053e05da5..2570235c81 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java @@ -23,6 +23,7 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.edc.client; +import java.util.List; import java.util.concurrent.CompletableFuture; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; @@ -44,10 +45,11 @@ CompletableFuture getSubmodelRawPayload(String connectorEndpoint, String CompletableFuture sendNotification(String submodelEndpointAddress, String assetId, EdcNotification notification) throws EdcClientException; - CompletableFuture getEndpointReferenceForAsset(String endpointAddress, String filterKey, - String filterValue) throws EdcClientException; + List> getEndpointReferencesForAsset(String endpointAddress, + String filterKey, String filterValue) throws EdcClientException; - CompletableFuture getEndpointReferenceForAsset(String endpointAddress, String filterKey, - String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference) throws EdcClientException; + List> getEndpointReferencesForAsset(String endpointAddress, + String filterKey, String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference) + throws EdcClientException; } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java index 72252ebc00..e2499b7584 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java @@ -40,7 +40,10 @@ import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; +import org.eclipse.tractusx.irs.edc.client.exceptions.ContractNegotiationException; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; +import org.eclipse.tractusx.irs.edc.client.exceptions.TransferProcessException; +import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyException; import org.eclipse.tractusx.irs.edc.client.model.CatalogItem; import org.eclipse.tractusx.irs.edc.client.model.EDRAuthCode; import org.eclipse.tractusx.irs.edc.client.model.NegotiationResponse; @@ -153,6 +156,7 @@ private EndpointDataReference getEndpointDataReference(final String connectorEnd log.info("Retrieving endpoint data reference from cache for assed id: {}", assetId); final EndpointDataReferenceStatus cachedEndpointDataReference = endpointDataReferenceCacheService.getEndpointDataReference( assetId); + EndpointDataReference endpointDataReference; if (cachedEndpointDataReference.tokenStatus() == TokenStatus.VALID) { @@ -170,7 +174,7 @@ private EndpointDataReference getEndpointDataReferenceAndAddToStorage(final Stri final String assetId, final EndpointDataReferenceStatus cachedEndpointDataReference) throws EdcClientException { try { - final EndpointDataReference endpointDataReference = getEndpointReferenceForAsset(connectorEndpoint, + final EndpointDataReference endpointDataReference = getEndpointReferencesForAsset(connectorEndpoint, NAMESPACE_EDC_ID, assetId, cachedEndpointDataReference).get(); endpointDataReferenceStorage.put(assetId, endpointDataReference); @@ -196,36 +200,63 @@ public CompletableFuture sendNotification(final String } @Override - public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, + public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue) throws EdcClientException { - return execute(endpointAddress, () -> getEndpointReferenceForAsset(endpointAddress, filterKey, filterValue, + return execute(endpointAddress, () -> getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue, new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW))); } @Override - public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, + public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue, final EndpointDataReferenceStatus endpointDataReferenceStatus) throws EdcClientException { - final StopWatch stopWatch = new StopWatch(); + final StopWatch stopWatch = new StopWatch(); stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + endpointAddress); - final String providerWithSuffix = appendSuffix(endpointAddress, - config.getControlplane().getProviderSuffix()); - final List items = catalogFacade.fetchCatalogByFilter(providerWithSuffix, filterKey, - filterValue); + final String providerWithSuffix = appendSuffix(endpointAddress, config.getControlplane().getProviderSuffix()); + final List items = catalogFacade.fetchCatalogByFilter(providerWithSuffix, filterKey, filterValue); - final NegotiationResponse response = contractNegotiationService.negotiate(providerWithSuffix, - items.stream().findFirst().orElseThrow(), endpointDataReferenceStatus); + final List catalogItems = items.stream().toList(); + if (catalogItems.isEmpty()) { + throw new EdcClientException( + "Catalog is empty for endpointAddress '%s' filterKey '%s', filterValue '%s'".formatted( + endpointAddress, filterKey, filterValue)); + } - final String storageId = getStorageId(endpointDataReferenceStatus, response); + return catalogItems.stream().map(catalogItem -> { - return pollingService.createJob() - .action(() -> retrieveEndpointReference(storageId, stopWatch)) - .timeToLive(config.getSubmodel().getRequestTtl()) - .description("waiting for Endpoint Reference retrieval") - .build() - .schedule(); + final NegotiationResponse negotiationResponse = negotiateContract(endpointDataReferenceStatus, catalogItem, + providerWithSuffix); + + final String storageId = getStorageId(endpointDataReferenceStatus, negotiationResponse); + + return pollingService.createJob() + .action(() -> retrieveEndpointReference(storageId, stopWatch)) + .timeToLive(config.getSubmodel().getRequestTtl()) + .description("waiting for Endpoint Reference retrieval") + .build() + .schedule(); + + }).toList(); + } + + private NegotiationResponse negotiateContract(final EndpointDataReferenceStatus endpointDataReferenceStatus, + final CatalogItem catalogItem, final String providerWithSuffix) { + final NegotiationResponse response; + try { + response = contractNegotiationService.negotiate(providerWithSuffix, catalogItem, + endpointDataReferenceStatus); + + // FIXME (mfischer) #214 how to handle? + } catch (ContractNegotiationException e) { + throw new RuntimeException(e); + } catch (UsagePolicyException e) { + throw new RuntimeException(e); + } catch (TransferProcessException e) { + throw new RuntimeException(e); + } + return response; } private static String getStorageId(final EndpointDataReferenceStatus endpointDataReferenceStatus, diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java index f0a4a2e826..5b85cea564 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java @@ -23,6 +23,7 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.edc.client; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -65,14 +66,14 @@ public CompletableFuture sendNotification(final String } @Override - public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, + public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue, final EndpointDataReferenceStatus cachedEndpointDataReference) throws EdcClientException { throw new EdcClientException("Not implemented"); } @Override - public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, + public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue) throws EdcClientException { throw new EdcClientException("Not implemented"); } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java index 4e1646e8a9..ad22db157b 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java @@ -23,6 +23,7 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.edc.client; +import java.util.List; import java.util.concurrent.ExecutionException; import lombok.RequiredArgsConstructor; @@ -81,10 +82,10 @@ public EdcNotificationResponse sendNotification(final String submodelEndpointAdd } @SuppressWarnings("PMD.PreserveStackTrace") - public EndpointDataReference getEndpointReferenceForAsset(final String endpointAddress, final String filterKey, - final String filterValue) throws EdcClientException { + public List getEndpointReferenceForAsset(final String endpointAddress, + final String filterKey, final String filterValue) throws EdcClientException { try { - return client.getEndpointReferenceForAsset(endpointAddress, filterKey, filterValue).get(); + return client.getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue).get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index 3f0a921243..c584bd11a1 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -343,7 +343,7 @@ void shouldRetrieveEndpointReferenceForAsset() throws Exception { endpointDataReferenceStorage.put(agreementId, expected); // act - final var result = testee.getEndpointReferenceForAsset(ENDPOINT_ADDRESS, filterKey, filterValue, + final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue, new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final EndpointDataReference actual = result.get(5, TimeUnit.SECONDS); @@ -366,7 +366,7 @@ void shouldRetrieveEndpointReferenceForAsset2() throws Exception { endpointDataReferenceStorage.put(agreementId, expected); // act - final var result = testee.getEndpointReferenceForAsset(ENDPOINT_ADDRESS, filterKey, filterValue); + final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue); final EndpointDataReference actual = result.get(5, TimeUnit.SECONDS); // assert diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java index 43146d4147..c02d4104b9 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java @@ -164,7 +164,7 @@ class GetEndpointReferenceForAssetTests { void shouldThrowEdcClientExceptionForEndpointReference() throws EdcClientException { // arrange final EdcClientException e = new EdcClientException("test"); - when(client.getEndpointReferenceForAsset(any(), any(), any())).thenThrow(e); + when(client.getEndpointReferencesForAsset(any(), any(), any())).thenThrow(e); // act ThrowableAssert.ThrowingCallable action = () -> testee.getEndpointReferenceForAsset("", "", ""); @@ -178,7 +178,7 @@ void shouldThrowExecutionExceptionForEndpointReference() throws EdcClientExcepti // arrange final ExecutionException e = new ExecutionException(new EdcClientException("test")); final CompletableFuture future = CompletableFuture.failedFuture(e); - when(client.getEndpointReferenceForAsset(any(), any(), any())).thenReturn(future); + when(client.getEndpointReferencesForAsset(any(), any(), any())).thenReturn(future); // act ThrowableAssert.ThrowingCallable action = () -> testee.getEndpointReferenceForAsset("", "", ""); @@ -194,7 +194,7 @@ void shouldRestoreInterruptOnInterruptExceptionForEndpointReference() final CompletableFuture future = mock(CompletableFuture.class); final InterruptedException e = new InterruptedException(); when(future.get()).thenThrow(e); - when(client.getEndpointReferenceForAsset(any(), any(), any())).thenReturn(future); + when(client.getEndpointReferencesForAsset(any(), any(), any())).thenReturn(future); // act testee.getEndpointReferenceForAsset("", "", ""); diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java index a78f7aba81..ea0395647e 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java @@ -23,6 +23,8 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.registryclient.decentral; +import java.util.List; + import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; /** @@ -32,12 +34,13 @@ public interface EdcEndpointReferenceRetriever { /** * Retrieves the EDC endpoint reference from the specified connector endpoint and asset combination + * * @param edcConnectorEndpoint the endpoint URL - * @param assetType the asset type id - * @param assetValue the asset type value + * @param assetType the asset type id + * @param assetValue the asset type value * @return the endpoint data reference * @throws EdcRetrieverException on any EDC errors */ - EndpointDataReference getEndpointReferenceForAsset(String edcConnectorEndpoint, String assetType, String assetValue) - throws EdcRetrieverException; + List getEndpointReferenceForAsset(String edcConnectorEndpoint, String assetType, + String assetValue) throws EdcRetrieverException; } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java index e9262c6820..a76226f414 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java @@ -23,7 +23,6 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.registryclient.decentral; -import static java.util.concurrent.CompletableFuture.supplyAsync; import static org.eclipse.tractusx.irs.common.util.concurrent.ResultFinder.LOGPREFIX_TO_BE_REMOVED_LATER; import static org.eclipse.tractusx.irs.common.util.concurrent.StopwatchUtils.startWatch; import static org.eclipse.tractusx.irs.common.util.concurrent.StopwatchUtils.stopWatch; @@ -52,38 +51,37 @@ public class EndpointDataForConnectorsService { private final EdcEndpointReferenceRetriever edcSubmodelFacade; public List> createFindEndpointDataForConnectorsFutures( - final List connectorEndpoints) { + final List edcUrls) { final String logPrefix = LOGPREFIX_TO_BE_REMOVED_LATER + "createFindEndpointDataForConnectorsFutures - "; List> futures = Collections.emptyList(); try { - log.info(logPrefix + "Creating futures to get EndpointDataReferences for endpoints: {}", - connectorEndpoints); - futures = connectorEndpoints.stream() - .map(connectorEndpoint -> supplyAsync( - () -> getEndpointReferenceForAsset(connectorEndpoint))) - .toList(); + log.info(logPrefix + "Creating futures to get EndpointDataReferences for endpoints: {}", edcUrls); + futures = edcUrls.stream() + .flatMap(edcUrl -> createGetEndpointReferencesForAssetFutures(edcUrl).stream()) + .toList(); return futures; } finally { log.info(logPrefix + "Created {} futures", futures.size()); } } - private EndpointDataReference getEndpointReferenceForAsset(final String connector) { + private List> createGetEndpointReferencesForAssetFutures( + final String edcUrl) { final String logPrefix = LOGPREFIX_TO_BE_REMOVED_LATER + "getEndpointReferenceForAsset - "; final var watch = new StopWatch(); startWatch(log, watch, - logPrefix + "Trying to retrieve EndpointDataReference for connector '%s'".formatted(connector)); + logPrefix + "Trying to retrieve EndpointDataReference for connector '%s'".formatted(edcUrl)); try { - return edcSubmodelFacade.getEndpointReferenceForAsset(connector, DT_REGISTRY_ASSET_TYPE, + return edcSubmodelFacade.getEndpointReferenceForAsset(edcUrl, DT_REGISTRY_ASSET_TYPE, DT_REGISTRY_ASSET_VALUE); } catch (EdcRetrieverException e) { - log.warn(logPrefix + "Exception occurred when retrieving EndpointDataReference from connector '{}'", - connector, e); + log.warn(logPrefix + "Exception occurred when retrieving EndpointDataReference from connector '{}'", edcUrl, + e); throw new CompletionException(e.getMessage(), e); } finally { stopWatch(log, watch); From e88fd3e6f85b31fba256a375cb7d947a2ae13d87 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 6 Feb 2024 23:07:00 +0100 Subject: [PATCH 03/51] feat(impl):[#395] Group tests --- ...igitalTwinRegistryServiceWiremockTest.java | 212 ++++++++++-------- 1 file changed, 117 insertions(+), 95 deletions(-) diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java index 36ce0ff1b6..044a55b7b0 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java @@ -70,6 +70,8 @@ import org.eclipse.tractusx.irs.registryclient.exceptions.RegistryServiceException; import org.eclipse.tractusx.irs.registryclient.exceptions.ShellNotFoundException; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; @@ -94,103 +96,123 @@ void setUp(WireMockRuntimeInfo wireMockRuntimeInfo) throws EdcRetrieverException when(edcSubmodelFacadeMock.getEndpointReferenceForAsset(any(), any(), any())).thenReturn(endpointDataReference); } - @Test - void shouldDiscoverEDCAndRequestRegistry() throws RegistryServiceException { - // Arrange - givenThat(postDiscoveryFinder200()); - givenThat(postEdcDiscovery200()); - givenThat(getLookupShells200()); - givenThat(getShellDescriptor200()); - - // Act - final Collection shells = decentralDigitalTwinRegistryService.fetchShells( - List.of(new DigitalTwinRegistryKey("testId", TEST_BPN))); - - // Assert - assertThat(shells).hasSize(1); - assertThat(shells.stream().findFirst().get().payload().getSubmodelDescriptors()).hasSize(3); - verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); - verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); - verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); - verify(exactly(1), getRequestedFor(urlPathMatching(SHELL_DESCRIPTORS_PATH + ".*"))); + @Nested + class FetchShellsTests { + @Test + void shouldDiscoverEDCAndRequestRegistry() throws RegistryServiceException { + // Arrange + givenThat(postDiscoveryFinder200()); + givenThat(postEdcDiscovery200()); + givenThat(getLookupShells200()); + givenThat(getShellDescriptor200()); + + // Act + final Collection shells = decentralDigitalTwinRegistryService.fetchShells( + List.of(new DigitalTwinRegistryKey("testId", TEST_BPN))); + + // Assert + assertThat(shells).hasSize(1); + assertThat(shells.stream().findFirst().get().payload().getSubmodelDescriptors()).hasSize(3); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); + verify(exactly(1), getRequestedFor(urlPathMatching(SHELL_DESCRIPTORS_PATH + ".*"))); + } + + @Test + void shouldThrowInCaseOfDiscoveryError() { + // Arrange + givenThat(postDiscoveryFinder404()); + final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); + + // Act & Assert + assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( + ShellNotFoundException.class); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + } + + @Test + void shouldThrowInCaseOfEdcDiscoveryError() { + // Arrange + givenThat(postDiscoveryFinder200()); + givenThat(postEdcDiscovery404()); + final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); + + // Act & Assert + assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( + ShellNotFoundException.class); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + } + + @Test + void shouldThrowInCaseOfLookupShellsError() { + // Arrange + givenThat(postDiscoveryFinder200()); + givenThat(postEdcDiscovery200()); + givenThat(getLookupShells404()); + final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); + + // Act & Assert + assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( + ShellNotFoundException.class); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); + } + + @Test + void shouldThrowInCaseOfShellDescriptorsError() { + // Arrange + givenThat(postDiscoveryFinder200()); + givenThat(postEdcDiscovery200()); + givenThat(getLookupShells200()); + givenThat(getShellDescriptor404()); + final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); + + // Act & Assert + assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( + ShellNotFoundException.class); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); + verify(exactly(1), getRequestedFor(urlPathMatching(SHELL_DESCRIPTORS_PATH + ".*"))); + } + + @Test + void shouldThrowExceptionOnEmptyShells() { + // Arrange + givenThat(postDiscoveryFinder200()); + givenThat(postEdcDiscovery200()); + givenThat(getLookupShells200Empty()); + givenThat(getShellDescriptor404()); + final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); + + // Act & Assert + assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( + ShellNotFoundException.class); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); + verify(exactly(1), getRequestedFor(urlPathMatching(SHELL_DESCRIPTORS_PATH + ".*"))); + } } - @Test - void shouldThrowInCaseOfDiscoveryError() { - // Arrange - givenThat(postDiscoveryFinder404()); - final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); - - // Act & Assert - assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( - ShellNotFoundException.class); - verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); - } - - @Test - void shouldThrowInCaseOfEdcDiscoveryError() { - // Arrange - givenThat(postDiscoveryFinder200()); - givenThat(postEdcDiscovery404()); - final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); - - // Act & Assert - assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( - ShellNotFoundException.class); - verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); - verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); - } - - @Test - void shouldThrowInCaseOfLookupShellsError() { - // Arrange - givenThat(postDiscoveryFinder200()); - givenThat(postEdcDiscovery200()); - givenThat(getLookupShells404()); - final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); - - // Act & Assert - assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( - ShellNotFoundException.class); - verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); - verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); - verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); - } - - @Test - void shouldThrowInCaseOfShellDescriptorsError() { - // Arrange - givenThat(postDiscoveryFinder200()); - givenThat(postEdcDiscovery200()); - givenThat(getLookupShells200()); - givenThat(getShellDescriptor404()); - final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); - - // Act & Assert - assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( - ShellNotFoundException.class); - verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); - verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); - verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); - verify(exactly(1), getRequestedFor(urlPathMatching(SHELL_DESCRIPTORS_PATH + ".*"))); - } - - @Test - void shouldThrowExceptionOnEmptyShells() { - // Arrange - givenThat(postDiscoveryFinder200()); - givenThat(postEdcDiscovery200()); - givenThat(getLookupShells200Empty()); - givenThat(getShellDescriptor404()); - final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); - - // Act & Assert - assertThatThrownBy(() -> decentralDigitalTwinRegistryService.fetchShells(testId)).isInstanceOf( - ShellNotFoundException.class); - verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); - verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); - verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); - verify(exactly(1), getRequestedFor(urlPathMatching(SHELL_DESCRIPTORS_PATH + ".*"))); + @Nested + class LookupShellIdentifiersTests { + + @Test + // TODO(mfischer): add tests for lookupShellIdentifiers + @Disabled("not yet implemented") + void test() { + // Arrange + // ... + + // Act & Assert + assertThatThrownBy(() -> decentralDigitalTwinRegistryService.lookupShellIdentifiers(TEST_BPN)).isInstanceOf( + ShellNotFoundException.class); + // ... + } } private EndpointDataReference endpointDataReference(final String contractAgreementId) { From e7f093978fa54a72dde225ff16945fa88c2e4a51 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Thu, 8 Feb 2024 13:11:49 +0100 Subject: [PATCH 04/51] feat(impl):[#395] Correct diagrams --- ...--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml | 2 +- .../discovery-DTR--multiple-EDCs-with-no-DTRs.puml | 4 ++-- ...Rs.puml => discovery-DTR--one-EDC-with-multiple-DTRs.puml} | 0 docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename docs/src/docs/arc42/cross-cutting/{discovery-DTR--EDC-with-multiple-DTRs.puml => discovery-DTR--one-EDC-with-multiple-DTRs.puml} (100%) diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml index 5956218ecc..dfa8181f1d 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml @@ -1,5 +1,5 @@ @startuml -actor IRS +participant IRS participant DTR IRS -> DTR: /query for globalAssetId diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml index aaed9497b2..9b2ba362e8 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml @@ -1,6 +1,6 @@ @startuml -actor IRS -actor "Discovery Service" as DiscoveryService +participant IRS +participant "Discovery Service" as DiscoveryService participant "EDC 1" as EDCProvider1 participant "EDC 2" as EDCProvider2 diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--EDC-with-multiple-DTRs.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml similarity index 100% rename from docs/src/docs/arc42/cross-cutting/discovery-DTR--EDC-with-multiple-DTRs.puml rename to docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml diff --git a/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc b/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc index 10cea2a582..ba3876e482 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc +++ b/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc @@ -8,9 +8,9 @@ __Please note that the expression "the first result" in the subsequent sections IRS queries all DTRs for the globalAssetId and will take the first result it gets. If none of the DTRs return a result, IRS will create a tombstone. -[plantuml,target=discovery-DTR--EDC-with-multiple-DTRs,format=svg] +[plantuml,target=discovery-DTR--one-EDC-with-multiple-DTRs,format=svg] .... -include::discovery-DTR--EDC-with-multiple-DTRs.puml[] +include::discovery-DTR--one-EDC-with-multiple-DTRs.puml[] .... ==== Scenario 2: Multiple EDCs with one DTR From b2d75ab8542755cad3d791fc1e12d73289c3be40 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Thu, 8 Feb 2024 13:34:00 +0100 Subject: [PATCH 05/51] feat(impl):[#395] Correct diagrams - fix arrow heads --- ...DTR--multiple-EDCs-with-multiple-DTRs.puml | 24 +++++++++---------- ...overy-DTR--multiple-EDCs-with-one-DTR.puml | 20 ++++++++-------- ...overy-DTR--one-EDC-with-multiple-DTRs.puml | 20 ++++++++-------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml index be20fd8964..fbccd27797 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml @@ -6,33 +6,33 @@ participant "EDC Provider 2" as EDCProvider2 participant "EDC Provider 3" as EDCProvider3 participant "DTR" as DTR -IRS ->> DiscoveryService: Get EDCs for BPN -DiscoveryService ->> IRS: Return list of 3 EDCs +IRS -> DiscoveryService: Get EDCs for BPN +DiscoveryService -> IRS: Return list of 3 EDCs par group CatalogRequestEDC1 - IRS ->> EDCProvider1: Query for DTR contract offer - EDCProvider1 ->> IRS: No offer + IRS -> EDCProvider1: Query for DTR contract offer + EDCProvider1 -> IRS: No offer end else group CatalogRequestEDC2 - IRS ->> EDCProvider2: Query for DTR contract offer - EDCProvider2 ->> IRS: DTR contract offer + IRS -> EDCProvider2: Query for DTR contract offer + EDCProvider2 -> IRS: DTR contract offer IRS -> EDCProvider2: Negotiate contract - IRS ->> DTR: Query for DT - DTR ->> IRS: DT + IRS -> DTR: Query for DT + DTR -> IRS: DT end else group CatalogRequestEDC3 - IRS ->> EDCProvider3: Query for DTR contract offer - EDCProvider3 ->> IRS: DTR contract offer + IRS -> EDCProvider3: Query for DTR contract offer + EDCProvider3 -> IRS: DTR contract offer IRS -> EDCProvider3: Negotiate contract - IRS ->> DTR: Query for DT - DTR ->> IRS: No DT + IRS -> DTR: Query for DT + DTR -> IRS: No DT end end @enduml diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml index f70cc4ac49..83b4f6b974 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml @@ -6,30 +6,30 @@ participant "EDC Provider 2" as EDCProvider2 participant "EDC Provider 3" as EDCProvider3 participant DTR -IRS ->> DiscoveryService: Get EDCs for BPN -DiscoveryService ->> IRS: Return list of 3 EDCs +IRS -> DiscoveryService: Get EDCs for BPN +DiscoveryService -> IRS: Return list of 3 EDCs par group CatalogRequestEDC1 - IRS ->> EDCProvider1: Query for DTR contract offer - EDCProvider1 ->> IRS: No offer + IRS -> EDCProvider1: Query for DTR contract offer + EDCProvider1 -> IRS: No offer end else group CatalogRequestEDC2 - IRS ->> EDCProvider2: Query for DTR contract offer - EDCProvider2 ->> IRS: No offer + IRS -> EDCProvider2: Query for DTR contract offer + EDCProvider2 -> IRS: No offer end else group CatalogRequestEDC3 - IRS ->> EDCProvider3: Query for DTR contract offer - EDCProvider3 ->> IRS: DTR contract offer + IRS -> EDCProvider3: Query for DTR contract offer + EDCProvider3 -> IRS: DTR contract offer IRS -> EDCProvider3: Negotiate contract - IRS ->> DTR: Query for DT - DTR ->> IRS: DT + IRS -> DTR: Query for DT + DTR -> IRS: DT end end @enduml \ No newline at end of file diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml index 0689cd80a5..4847677324 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml @@ -5,24 +5,24 @@ participant "EDC Provider" as EDCProvider participant "DTR 1" as DTR1 participant "DTR 2" as DTR2 -IRS ->> DiscoveryService: Get EDCs for BPN -DiscoveryService ->> IRS: Return list of 1 EDC -IRS ->> EDCProvider: Query for DTR contract offer -EDCProvider ->> IRS: 2 DTR contract offers +IRS -> DiscoveryService: Get EDCs for BPN +DiscoveryService -> IRS: Return list of 1 EDC +IRS -> EDCProvider: Query for DTR contract offer +EDCProvider -> IRS: 2 DTR contract offers par group Query DTR 1 - IRS ->> EDCProvider: Negotiate contract - IRS ->> DTR1: Query for DT - DTR1 ->> IRS: no DT + IRS -> EDCProvider: Negotiate contract + IRS -> DTR1: Query for DT + DTR1 -> IRS: no DT end else group Query DTR 2 - IRS ->> EDCProvider: Negotiate contract - IRS ->> DTR2: Query for DT - DTR2 ->> IRS: DT + IRS -> EDCProvider: Negotiate contract + IRS -> DTR2: Query for DT + DTR2 -> IRS: DT end end @enduml \ No newline at end of file From b9af543f290faefd0925fe0011f72f43eb87b29b Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Thu, 8 Feb 2024 17:26:18 +0100 Subject: [PATCH 06/51] feat(impl):[#395] Add some code comments to diagrams --- .../discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml | 7 +++++++ .../discovery-DTR--multiple-EDCs-with-no-DTRs.puml | 3 +++ .../discovery-DTR--multiple-EDCs-with-one-DTR.puml | 5 +++++ .../discovery-DTR--one-EDC-with-multiple-DTRs.puml | 1 + 4 files changed, 16 insertions(+) diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml index fbccd27797..4e75115760 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml @@ -11,6 +11,7 @@ DiscoveryService -> IRS: Return list of 3 EDCs par group CatalogRequestEDC1 + ' == EDC Control Plane == IRS -> EDCProvider1: Query for DTR contract offer EDCProvider1 -> IRS: No offer end @@ -18,9 +19,12 @@ par else group CatalogRequestEDC2 + ' == EDC Control Plane == IRS -> EDCProvider2: Query for DTR contract offer EDCProvider2 -> IRS: DTR contract offer IRS -> EDCProvider2: Negotiate contract + + '== EDC Data Plane == IRS -> DTR: Query for DT DTR -> IRS: DT end @@ -28,9 +32,12 @@ par else group CatalogRequestEDC3 + '== EDC Control Plane == IRS -> EDCProvider3: Query for DTR contract offer EDCProvider3 -> IRS: DTR contract offer IRS -> EDCProvider3: Negotiate contract + + '== EDC Data Plane == IRS -> DTR: Query for DT DTR -> IRS: No DT end diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml index 9b2ba362e8..0735db0bd8 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs.puml @@ -11,6 +11,7 @@ DiscoveryService -> IRS: Return list of 3 EDCs par group Catalog Request to EDC 1 + '== EDC Control Plane == IRS -> EDCProvider1: Query for DTR contract offer EDCProvider1 -> IRS: No offer end @@ -18,6 +19,7 @@ par else group Catalog Request to EDC 2 + '== EDC Control Plane == IRS -> EDCProvider2: Query for DTR contract offer EDCProvider2 -> IRS: No offer end @@ -25,6 +27,7 @@ par else group Catalog Request to EDC 3 + '== EDC Control Plane == IRS -> EDCProvider3: Query for DTR contract offer EDCProvider3 -> IRS: No offer end diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml index 83b4f6b974..d7f090ffee 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR.puml @@ -11,6 +11,7 @@ DiscoveryService -> IRS: Return list of 3 EDCs par group CatalogRequestEDC1 + '== EDC Control Plane == IRS -> EDCProvider1: Query for DTR contract offer EDCProvider1 -> IRS: No offer end @@ -18,6 +19,7 @@ par else group CatalogRequestEDC2 + '== EDC Control Plane == IRS -> EDCProvider2: Query for DTR contract offer EDCProvider2 -> IRS: No offer end @@ -25,9 +27,12 @@ par else group CatalogRequestEDC3 + '== EDC Control Plane == IRS -> EDCProvider3: Query for DTR contract offer EDCProvider3 -> IRS: DTR contract offer IRS -> EDCProvider3: Negotiate contract + + '== EDC Data Plane == IRS -> DTR: Query for DT DTR -> IRS: DT end diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml index 4847677324..b5765c0a7b 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs.puml @@ -7,6 +7,7 @@ participant "DTR 2" as DTR2 IRS -> DiscoveryService: Get EDCs for BPN DiscoveryService -> IRS: Return list of 1 EDC + IRS -> EDCProvider: Query for DTR contract offer EDCProvider -> IRS: 2 DTR contract offers From e0624846c3353edab9abed23f8f4065338b00cc2 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 9 Feb 2024 10:16:17 +0100 Subject: [PATCH 07/51] feat(impl):[#395] Add some javadoc --- .../registryclient/discovery/ConnectorEndpointsService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/discovery/ConnectorEndpointsService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/discovery/ConnectorEndpointsService.java index 590eb66a5b..a5333b659d 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/discovery/ConnectorEndpointsService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/discovery/ConnectorEndpointsService.java @@ -44,6 +44,12 @@ public class ConnectorEndpointsService { private final DiscoveryFinderClient discoveryFinderClient; private static final String CONNECTOR_ENDPOINT_SERVICE_CACHE_NAME = "connector_endpoint_service_cache"; + /** + * Get EDCs for BPN. + * + * @param bpn the BPN + * @return list of EDC URLs + */ @Cacheable(CONNECTOR_ENDPOINT_SERVICE_CACHE_NAME) public List fetchConnectorEndpoints(final String bpn) { From 2ab61cccc989c82eef64b35cec0736f9ea0318c1 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 9 Feb 2024 16:36:08 +0100 Subject: [PATCH 08/51] feat(impl):[#395] Rename variable, format code --- .../DecentralDigitalTwinRegistryService.java | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index 6860b6877c..4473ea113a 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -121,8 +121,8 @@ public Collection fetchShells(final Collection ke } } - private Stream fetchShellDescriptors( - final Map.Entry> entry, final Set calledEndpoints) { + private Stream fetchShellDescriptors(final Map.Entry> entry, + final Set calledEndpoints) { try { @@ -140,8 +140,8 @@ private Stream fetchShellDescriptors( } } - private CompletableFuture> fetchShellDescriptors( - final Set calledEndpoints, final String bpn, final List keys) { + private CompletableFuture> fetchShellDescriptors(final Set calledEndpoints, final String bpn, + final List keys) { final var watch = new StopWatch(); final String msg = "Fetching %s shells for bpn '%s'".formatted(keys.size(), bpn); @@ -149,6 +149,7 @@ private CompletableFuture> fetchShellDescriptors( log.info(msg); try { + final var edcUrls = connectorEndpointsService.fetchConnectorEndpoints(bpn); log.info("Found {} connector endpoints for bpn '{}'", edcUrls.size(), bpn); @@ -166,19 +167,19 @@ private CompletableFuture> fetchShellDescriptorsForConnectorEndpoint final List keys, final List connectorEndpoints) { final var service = endpointDataForConnectorsService; - final var futures = service.createFindEndpointDataForConnectorsFutures(connectorEndpoints) - .stream() - .map(edrFuture -> edrFuture.thenCompose(edr -> CompletableFuture.supplyAsync( - () -> fetchShellDescriptorsForKey(keys, edr)))) - .toList(); + final var shellsFuture = service.createFindEndpointDataForConnectorsFutures(connectorEndpoints) + .stream() + .map(edrFuture -> edrFuture.thenCompose(edr -> CompletableFuture.supplyAsync( + () -> fetchShellDescriptorsForKey(keys, edr)))) + .toList(); - log.debug("Created {} futures", futures.size()); + log.debug("Created {} futures", shellsFuture.size()); - return resultFinder.getFastestResult(futures); + return resultFinder.getFastestResult(shellsFuture); } - private List fetchShellDescriptorsForKey( - final List keys, final EndpointDataReference endpointDataReference) { + private List fetchShellDescriptorsForKey(final List keys, + final EndpointDataReference endpointDataReference) { final var watch = new StopWatch(); final String msg = "Fetching shell descriptors for keys %s from endpoint '%s'".formatted(keys, @@ -186,13 +187,10 @@ private List fetchShellDescriptorsForKey( watch.start(msg); log.info(msg); try { - return keys.stream().map( - key -> - new Shell( - contractNegotiationId(endpointDataReference.getAuthCode()), - fetchShellDescriptor(endpointDataReference, key) - ) - ).toList(); + return keys.stream() + .map(key -> new Shell(contractNegotiationId(endpointDataReference.getAuthCode()), + fetchShellDescriptor(endpointDataReference, key))) + .toList(); } finally { watch.stop(); log.info(TOOK_MS, watch.getLastTaskName(), watch.getLastTaskTimeMillis()); @@ -217,10 +215,7 @@ private AssetAdministrationShellDescriptor fetchShellDescriptor(final EndpointDa } private String contractNegotiationId(final String token) { - return Optional.ofNullable(token) - .map(EDRAuthCode::fromAuthCodeToken) - .map(EDRAuthCode::getCid) - .orElse(""); + return Optional.ofNullable(token).map(EDRAuthCode::fromAuthCodeToken).map(EDRAuthCode::getCid).orElse(""); } /** From b1e401cf826dbb8342cd47ea6acbeef98304dfba Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 9 Feb 2024 16:36:46 +0100 Subject: [PATCH 09/51] feat(impl):[#395] Add more detailed diagrams --- ...ple-EDCs-with-multiple-DTRs--detailed.puml | 84 +++++++++++++++++++ ...-multiple-EDCs-with-no-DTRs--detailed.puml | 58 +++++++++++++ ...-multiple-EDCs-with-one-DTR--detailed.puml | 61 ++++++++++++++ ...-one-EDC-with-multiple-DTRs--detailed.puml | 49 +++++++++++ ...y-DTR--one-EDC-with-one-DTR--detailed.puml | 41 +++++++++ .../cross-cutting/discovery-process-dtr.adoc | 45 +++++++++- 6 files changed, 336 insertions(+), 2 deletions(-) create mode 100644 docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml create mode 100644 docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs--detailed.puml create mode 100644 docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR--detailed.puml create mode 100644 docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml create mode 100644 docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-one-DTR--detailed.puml diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml new file mode 100644 index 0000000000..7775fc1e8f --- /dev/null +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml @@ -0,0 +1,84 @@ +@startuml + + +box IRS + participant DecentralDigitalTwinRegistryService as DTRS + participant EdcSubmodelClientImpl as EdcClient +end box + + +participant DiscoveryService +participant "EDC Provider 1" as EDCProvider1 +participant "EDC Provider 2" as EDCProvider2 +participant "EDC Provider 3" as EDCProvider3 +participant "DTR" as DTR + +' DigitalTwinDelegate.process +' DecentralDigitalTwinRegistryService.fetchShells +' ConnectorEndpointsService.fetchConnectorEndpoints(String bpn) -- cacheable +DTRS -> DiscoveryService: Get EDCs for BPN +' discoveryFinderClient.findDiscoveryEndpoints(DiscoveryFinderRequest request) +DiscoveryService -> DTRS: Return list of 3 EDCs + +' Turned into futures to get the EDR tokens by +' EndpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(List edcUrls) + +par + group CatalogRequestEDC1 + + == EDC Control Plane == + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider1: Query for DTR contract offer + EDCProvider1 -> EdcClient: No offer + EdcClient -> DTRS: No token + end + + else + + group CatalogRequestEDC2 + + == EDC Control Plane == + + ' this happens in DecentralDigitalTwinRegistryService.fetchShellDescriptorsForConnectorEndpoints + ' when each of List> is composed + ' with fetchShellDescriptorsForKey + DTRS -> EdcClient: Get EDR Token for asset + ' EdcSubmodelFacade.getEndpointReferenceForAsset + ' EdcSubmodelClientImpl.getEndpointReferenceForAsset + EdcClient -> EDCProvider2: Query for DTR contract offer + EDCProvider2 -> EdcClient: DTR contract offer + ' EdcSubmodelClientImpl.negotiateContract + EdcClient -> EDCProvider2: Negotiate contract + EDCProvider2 -> EdcClient: EDR Token callback + EdcClient -> DTRS: EDR token + + + == EDC Data Plane == + + ' DecentralDigitalTwinRegistryService + ' .fetchShellDescriptor(EndpointDataReference, DigitalTwinRegistryKey) + DTRS -> DTR: Query for DT + DTR -> DTRS: DT + ' result is AssetAdministrationShellDescriptor which is the actual data + end + + else + + group CatalogRequestEDC3 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider3: Query for DTR contract offer + EDCProvider3 -> EdcClient: DTR contract offer + EdcClient -> EDCProvider3: Negotiate contract + EDCProvider3 -> EdcClient: EDR Token callback + EdcClient -> DTRS: EDR token + + == EDC Data Plane == + + DTRS -> DTR: Query for DT + DTR -> DTRS: No DT + end +end +@enduml diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs--detailed.puml new file mode 100644 index 0000000000..53def896d5 --- /dev/null +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-no-DTRs--detailed.puml @@ -0,0 +1,58 @@ +@startuml + +box IRS + participant DecentralDigitalTwinRegistryService as DTRS + participant EdcSubmodelClientImpl as EdcClient +end box + +participant "Discovery Service" as DiscoveryService + +participant "EDC 1" as EDCProvider1 +participant "EDC 2" as EDCProvider2 +participant "EDC 3" as EDCProvider3 + + +' ConnectorEndpointsService.fetchConnectorEndpoints(String bpn) -- cacheable +DTRS -> DiscoveryService: Get EDCs for BPN +' discoveryFinderClient.findDiscoveryEndpoints(DiscoveryFinderRequest request) +DiscoveryService -> DTRS: Return list of 3 EDCs + +par + group Catalog Request to EDC 1 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider1: Query for DTR contract offer + EDCProvider1 -> EdcClient: No offer + EdcClient -> DTRS: No token + end + + else + + group Catalog Request to EDC 2 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider2: Query for DTR contract offer + EDCProvider2 -> EdcClient: No offer + EdcClient -> DTRS: No token + end + + else + + group Catalog Request to EDC 3 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider3: Query for DTR contract offer + EDCProvider3 -> EdcClient: No offer + EdcClient -> DTRS: No token + end +end + +DTRS -> DTRS: Tombstone + +@enduml diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR--detailed.puml new file mode 100644 index 0000000000..d2a2a9ca4d --- /dev/null +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-one-DTR--detailed.puml @@ -0,0 +1,61 @@ +@startuml + +box IRS + participant DecentralDigitalTwinRegistryService as DTRS + participant EdcSubmodelClientImpl as EdcClient +end box + +participant DiscoveryService +participant "EDC Provider 1" as EDCProvider1 +participant "EDC Provider 2" as EDCProvider2 +participant "EDC Provider 3" as EDCProvider3 +participant DTR + +' ConnectorEndpointsService.fetchConnectorEndpoints(String bpn) -- cacheable +DTRS -> DiscoveryService: Get EDCs for BPN +' discoveryFinderClient.findDiscoveryEndpoints(DiscoveryFinderRequest request) +DiscoveryService -> DTRS: Return list of 3 EDCs + +par + group CatalogRequestEDC1 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider1: Query for DTR contract offer + EDCProvider1 -> EdcClient: No offer + EdcClient -> DTRS: No token + end + + else + + group CatalogRequestEDC2 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider2: Query for DTR contract offer + EDCProvider2 -> EdcClient: No offer + EdcClient -> DTRS: No token + end + + else + + group CatalogRequestEDC3 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider3: Query for DTR contract offer + EDCProvider3 -> EdcClient: DTR contract offer + EdcClient -> EDCProvider3: Negotiate contract + EDCProvider3 -> EdcClient: EDR Token callback + EdcClient -> DTRS: EDR token + + == EDC Data Plane == + + DTRS -> DTR: Query for DT + DTR -> DTRS: DT + end +end +@enduml \ No newline at end of file diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml new file mode 100644 index 0000000000..f11c0f344b --- /dev/null +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml @@ -0,0 +1,49 @@ +@startuml + +box IRS + participant DecentralDigitalTwinRegistryService as DTRS + participant EdcSubmodelClientImpl as EdcClient +end box + +participant DiscoveryService +participant "EDC Provider" as EDCProvider +participant "DTR 1" as DTR1 +participant "DTR 2" as DTR2 + +' ConnectorEndpointsService.fetchConnectorEndpoints(String bpn) -- cacheable +DTRS -> DiscoveryService: Get EDCs for BPN +' discoveryFinderClient.findDiscoveryEndpoints(DiscoveryFinderRequest request) +DiscoveryService -> DTRS: Return list of 1 EDC + +== EDC Control Plane == + +DTRS -> EdcClient: Get EDR Token for asset +EdcClient ->> EDCProvider: Query for DTR contract offer +EDCProvider -> EdcClient: 2 DTR contract offers + +par + group Query DTR 1 + EdcClient -> EDCProvider: Negotiate contract + EDCProvider -> EdcClient: EDR Token callback + EdcClient -> DTRS: EDR token + + == EDC Data Plane == + + DTRS -> DTR1: Query for DT + DTR1 -> DTRS: no DT + end + + else + + group Query DTR 2 + EdcClient -> EDCProvider: Negotiate contract + EDCProvider -> EdcClient: EDR Token callback + EdcClient -> DTRS: EDR token + + == EDC Data Plane == + + DTRS -> DTR2: Query for DT + DTR2 -> DTRS: DT + end +end +@enduml \ No newline at end of file diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-one-DTR--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-one-DTR--detailed.puml new file mode 100644 index 0000000000..29ea1509b6 --- /dev/null +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-one-DTR--detailed.puml @@ -0,0 +1,41 @@ +@startuml + +box IRS + participant DecentralDigitalTwinRegistryService as DTRS + participant EdcSubmodelClientImpl as EdcClient +end box + +participant DiscoveryService +participant "EDC Provider 3" as EDCProvider3 +participant DTR + +' DigitalTwinDelegate.process +' ConnectorEndpointsService.fetchConnectorEndpoints(String bpn) -- cacheable +DTRS -> DiscoveryService: Get EDCs for BPN +' discoveryFinderClient.findDiscoveryEndpoints(DiscoveryFinderRequest request) +DiscoveryService -> DTRS: Return list of 1 EDC + +== EDC Control Plane == + +' see EdcSubmodelFacade.getEndpointReferenceForAsset, +' EdcSubmodelClient.getEndpointReferencesForAsset, +' EdcSubmodelClientImpl.getEndpointReferencesForAsset +DTRS -> EdcClient: Get EDR Token for asset +EdcClient -> EDCProvider3: Query for DTR contract offer +EDCProvider3 -> EdcClient: DTR contract offer +' Contract offer = CatalogItem +EdcClient -> EDCProvider3: Negotiate contract + +EDCProvider3 -> EdcClient: EDR Token callback +' EDR Token callback (this is the answer from pollingService) +EdcClient -> DTRS: EDR Token +' EDR Token = EndpointDataReference + +== EDC Data Plane == + +' mapToShellId +' DecentralDigitalTwinRegistryClient.getAssetAdministrationShellDescriptor +DTRS -> DTR: Query for DT +DTR -> DTRS: DT + +@enduml \ No newline at end of file diff --git a/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc b/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc index ba3876e482..a24c91b4e7 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc +++ b/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc @@ -1,8 +1,6 @@ The Dataspace Discovery Service handles multiple EDC-Urls received for BPN. This applies to the following scenarios. -__Please note that the expression "the first result" in the subsequent sections means the first successful answer.__ - ==== Scenario 1: EDC with multiple DTRs IRS queries all DTRs for the globalAssetId and will take the first result it gets. @@ -13,6 +11,15 @@ If none of the DTRs return a result, IRS will create a tombstone. include::discovery-DTR--one-EDC-with-multiple-DTRs.puml[] .... + +Same diagram with a little more detail on IRS side: + +[plantuml,target=discovery-DTR--one-EDC-with-multiple-DTRs--detailed,format=svg] +.... +include::discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml[] +.... + + ==== Scenario 2: Multiple EDCs with one DTR IRS starts a contract negotiation for all registry contract offers in parallel and queries the DTRs for all successful negotiations. @@ -23,6 +30,16 @@ The first registry which responds with a DT will be the one used by IRS. include::discovery-DTR--multiple-EDCs-with-one-DTR.puml[] .... + +Same diagram with a little more detail on IRS side: + +[plantuml,target=discovery-DTR--multiple-EDCs-with-one-DTR--detailed,format=svg] +.... +include::discovery-DTR--multiple-EDCs-with-one-DTR--detailed.puml[] +.... + + + ==== Scenario 3: One EDC with one DTR Only one EDC found for BPN and the catalog only contains one offer for the DTR. @@ -33,6 +50,14 @@ IRS will use this registry and will create a tombstone if no DT could be found f include::discovery-DTR--one-EDC-with-one-DTR.puml[] .... +Same diagram with a little more detail on IRS side: + +[plantuml,target=discovery-DTR--one-EDC-with-one-DTR--detailed,format=svg] +.... +include::discovery-DTR--one-EDC-with-one-DTR--detailed.puml[] +.... + + ==== Scenario 4: Multiple EDCs with multiple DTRs IRS starts a contract negotiation for all the registry offers. @@ -42,6 +67,15 @@ IRS starts a contract negotiation for all the registry offers. include::discovery-DTR--multiple-EDCs-with-multiple-DTRs.puml[] .... +Same diagram with a little more detail on IRS side: + +[plantuml,target=discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed,format=svg] +.... +include::discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml[] +.... + + + ==== Scenario 5: Multiple EDCs with no DTRs IRS starts a contract negotiation for all the registry offers and creates a tombstone since no DTR could be discovered. @@ -51,6 +85,13 @@ IRS starts a contract negotiation for all the registry offers and creates a tomb include::discovery-DTR--multiple-EDCs-with-no-DTRs.puml[] .... +Same diagram with a little more detail on IRS side: + +[plantuml,target=discovery-DTR--multiple-EDCs-with-no-DTRs--detailed,format=svg] +.... +include::discovery-DTR--multiple-EDCs-with-no-DTRs--detailed.puml[] +.... + ==== Special Scenario: Same DT in multiple DTRs IRS will use all registries to query for the globalAssetId and takes the first result which is returned. From 4bdd210c7b62bf2cced8f595ac499937ac011ecc Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 12 Feb 2024 18:12:42 +0100 Subject: [PATCH 10/51] feat(impl):[#395] EdcClientException: Add constructor with message and cause --- .../irs/edc/client/exceptions/EdcClientException.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java index 98ee3696b3..8066f5e431 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java @@ -28,6 +28,10 @@ */ public class EdcClientException extends Exception { + public EdcClientException(final String msg, final Throwable cause) { + super(msg, cause); + } + public EdcClientException(final Throwable cause) { super(cause); } From 9552b5b198be8b8bebbcc7bb3f12a2750bec853f Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 12 Feb 2024 19:37:08 +0100 Subject: [PATCH 11/51] feat(impl):[#395] Rename local variable --- .../decentral/DecentralDigitalTwinRegistryService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index 4473ea113a..78c9336137 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -270,11 +270,11 @@ private Collection lookupShellIds(final String bpn) throws RegistryServi try { - final var connectorEndpoints = connectorEndpointsService.fetchConnectorEndpoints(bpn); - log.info("Looking up shell ids for bpn '{}' with connector endpoints {}", bpn, connectorEndpoints); + final var edcUrls = connectorEndpointsService.fetchConnectorEndpoints(bpn); + log.info("Looking up shell ids for bpn '{}' with connector endpoints {}", bpn, edcUrls); final var endpointDataReferenceFutures = endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures( - connectorEndpoints); + edcUrls); log.debug("Created endpointDataReferenceFutures"); return lookupShellIds(bpn, endpointDataReferenceFutures); From 88cd1651c3ca2df82c4b8210cd0da9dcb9cf8341 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 12 Feb 2024 19:37:49 +0100 Subject: [PATCH 12/51] feat(impl):[#395] Remove duplicate log --- .../decentral/DecentralDigitalTwinRegistryService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index 78c9336137..e619b1f333 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -275,7 +275,6 @@ private Collection lookupShellIds(final String bpn) throws RegistryServi final var endpointDataReferenceFutures = endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures( edcUrls); - log.debug("Created endpointDataReferenceFutures"); return lookupShellIds(bpn, endpointDataReferenceFutures); From a0abc33387ba7158c86f2dcb55922455d4b23063 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 12 Feb 2024 22:41:52 +0100 Subject: [PATCH 13/51] feat(impl):[#395] Update detail diagrams --- ...ple-EDCs-with-multiple-DTRs--detailed.puml | 49 ++++++++++++++----- ...-one-EDC-with-multiple-DTRs--detailed.puml | 5 ++ .../cross-cutting/discovery-process-dtr.adoc | 2 +- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml index 7775fc1e8f..491c13e89b 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml @@ -11,7 +11,8 @@ participant DiscoveryService participant "EDC Provider 1" as EDCProvider1 participant "EDC Provider 2" as EDCProvider2 participant "EDC Provider 3" as EDCProvider3 -participant "DTR" as DTR +participant "DTR1" as DTR1 +participant "DTR2" as DTR2 ' DigitalTwinDelegate.process ' DecentralDigitalTwinRegistryService.fetchShells @@ -28,14 +29,14 @@ par == EDC Control Plane == DTRS -> EdcClient: Get EDR Token for asset - EdcClient -> EDCProvider1: Query for DTR contract offer + EdcClient -> EDCProvider1: Query for DTR1 contract offer EDCProvider1 -> EdcClient: No offer EdcClient -> DTRS: No token end else - group CatalogRequestEDC2 + group CatalogRequestEDC2 DTR1 == EDC Control Plane == @@ -45,11 +46,12 @@ par DTRS -> EdcClient: Get EDR Token for asset ' EdcSubmodelFacade.getEndpointReferenceForAsset ' EdcSubmodelClientImpl.getEndpointReferenceForAsset - EdcClient -> EDCProvider2: Query for DTR contract offer - EDCProvider2 -> EdcClient: DTR contract offer + EdcClient -> EDCProvider2: Query for DTR1 contract offer + EDCProvider2 -> EdcClient: DTR1 contract offer ' EdcSubmodelClientImpl.negotiateContract EdcClient -> EDCProvider2: Negotiate contract EDCProvider2 -> EdcClient: EDR Token callback + EdcClient -> DTRS: EDR token @@ -57,28 +59,53 @@ par ' DecentralDigitalTwinRegistryService ' .fetchShellDescriptor(EndpointDataReference, DigitalTwinRegistryKey) - DTRS -> DTR: Query for DT - DTR -> DTRS: DT + DTRS -> DTR1: Query for DT + DTR1 -> DTRS: DT ' result is AssetAdministrationShellDescriptor which is the actual data end else + group CatalogRequestEDC2 DTR2 + + == EDC Control Plane == + + DTRS -> EdcClient: Get EDR Token for asset + EdcClient -> EDCProvider2: Query for DTR1 contract offer + EDCProvider2 -> EdcClient: DTR1 contract offer + EdcClient -> EDCProvider2: Negotiate contract + EDCProvider2 -> EdcClient: EDR Token callback + + EdcClient -> DTRS: EDR token + + + == EDC Data Plane == + + DTRS -> DTR2: Query for DT + DTR2 -> DTRS: DT + end + + else + group CatalogRequestEDC3 == EDC Control Plane == DTRS -> EdcClient: Get EDR Token for asset - EdcClient -> EDCProvider3: Query for DTR contract offer - EDCProvider3 -> EdcClient: DTR contract offer + EdcClient -> EDCProvider3: Query for DTR1 contract offer + EDCProvider3 -> EdcClient: DTR1 contract offer EdcClient -> EDCProvider3: Negotiate contract EDCProvider3 -> EdcClient: EDR Token callback EdcClient -> DTRS: EDR token == EDC Data Plane == - DTRS -> DTR: Query for DT - DTR -> DTRS: No DT + DTRS -> DTR1: Query for DT + DTR1 -> DTRS: No DT end end + +' TODO(mfischer): #395: how do we visualize the following behaviour in the diagram?: +' fastest successful response from DTR will be returned + @enduml diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml index f11c0f344b..6bbf506d3e 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml @@ -17,9 +17,13 @@ DiscoveryService -> DTRS: Return list of 1 EDC == EDC Control Plane == +' see EdcSubmodelFacade.getEndpointReferenceForAsset, +' EdcSubmodelClient.getEndpointReferencesForAsset, +' EdcSubmodelClientImpl.getEndpointReferencesForAsset DTRS -> EdcClient: Get EDR Token for asset EdcClient ->> EDCProvider: Query for DTR contract offer EDCProvider -> EdcClient: 2 DTR contract offers +' TODO (mfischer) #395: Contract offer = CatalogItem? par group Query DTR 1 @@ -39,6 +43,7 @@ par EdcClient -> EDCProvider: Negotiate contract EDCProvider -> EdcClient: EDR Token callback EdcClient -> DTRS: EDR token + ' TODO (mfischer) #395: EDR token = EndpointDataReference? == EDC Data Plane == diff --git a/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc b/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc index a24c91b4e7..40c77d810e 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc +++ b/docs/src/docs/arc42/cross-cutting/discovery-process-dtr.adoc @@ -1,7 +1,7 @@ The Dataspace Discovery Service handles multiple EDC-Urls received for BPN. This applies to the following scenarios. -==== Scenario 1: EDC with multiple DTRs +==== Scenario 1: One EDC with multiple DTRs IRS queries all DTRs for the globalAssetId and will take the first result it gets. If none of the DTRs return a result, IRS will create a tombstone. From 66568e0d15ad6fd3f7b7b6e4d74adc226b2fdf56 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 12 Feb 2024 22:43:34 +0100 Subject: [PATCH 14/51] feat(impl):[#395] Add code comment for special scenario (with TODO for clarification) --- .../job/delegate/DigitalTwinDelegate.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java index 06c655afa6..9ae3afbdc5 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java @@ -68,9 +68,18 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai } try { - final Shell shell = digitalTwinRegistryService.fetchShells(List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn()))) - .stream() + final Shell shell = digitalTwinRegistryService.fetchShells( + List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn()))).stream() + // TODO (mfischer): #395: clarify whether this is correct + // Special Scenario: + // Multiple DTs with the same globalAssetId in one DTR: + // If there are multiple shells in this place this means + // that there were multiple DTs with the same globalAssetId + // in one DTR. + // Because there is no defined way which one to select + // the first is returned. .findFirst() + // No result should result in tombstone, therefore throw. .orElseThrow(); if (!expectedDepthOfTreeIsNotReached(jobData.getDepth(), aasTransferProcess.getDepth())) { From 70f61d5bef2a3a149e26e221f4fe117e8f66335c Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 12 Feb 2024 22:46:18 +0100 Subject: [PATCH 15/51] feat(impl):[#395] Add TODO for clarification --- .../irs/aaswrapper/job/delegate/RelationshipDelegate.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java index 231b6d5b31..98127ec15e 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java @@ -76,6 +76,8 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai itemContainerBuilder.build() .getShells() .stream() + // TODO (mfischer): #395 is this part of the story too? need to change? + // if yes, which step in the diagrams is this? .findFirst() .ifPresent(shell -> shell.payload().findRelationshipEndpointAddresses( AspectType.fromValue(relationshipAspect.getName())) From 3c615082aef5fc007762ac8db330c03e6bad0b1e Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 13 Feb 2024 00:46:17 +0100 Subject: [PATCH 16/51] feat(impl):[#395] Add TODO for clarification --- .../decentral/DecentralDigitalTwinRegistryClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java index 1c7a7ed5b3..4b2c1dfa4f 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java @@ -71,6 +71,7 @@ public AssetAdministrationShellDescriptor getAssetAdministrationShellDescriptor( final String descriptorEndpoint = endpointDataReference.getEndpoint() + shellDescriptorTemplate; final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(descriptorEndpoint); final Map values = Map.of(PLACEHOLDER_AAS_IDENTIFIER, encodeWithBase64(aasIdentifier)); + // TODO (mfischer): #395: clarify: shouldn't this be dtrRestTemplate?! return edcRestTemplate.exchange(uriBuilder.build(values), HttpMethod.GET, new HttpEntity<>(null, headers(endpointDataReference)), AssetAdministrationShellDescriptor.class) .getBody(); From c5f44619cc9e740602999bd830415a768f5bed3d Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 13 Feb 2024 00:46:55 +0100 Subject: [PATCH 17/51] feat(impl):[#395] Rename local variable --- .../decentral/DecentralDigitalTwinRegistryService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index e619b1f333..e8489a5be0 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -164,10 +164,10 @@ private CompletableFuture> fetchShellDescriptors(final Set c } private CompletableFuture> fetchShellDescriptorsForConnectorEndpoints( - final List keys, final List connectorEndpoints) { + final List keys, final List edcUrls) { final var service = endpointDataForConnectorsService; - final var shellsFuture = service.createFindEndpointDataForConnectorsFutures(connectorEndpoints) + final var shellsFuture = service.createFindEndpointDataForConnectorsFutures(edcUrls) .stream() .map(edrFuture -> edrFuture.thenCompose(edr -> CompletableFuture.supplyAsync( () -> fetchShellDescriptorsForKey(keys, edr)))) @@ -186,6 +186,7 @@ private List fetchShellDescriptorsForKey(final List new Shell(contractNegotiationId(endpointDataReference.getAuthCode()), From 38e82a333430864957750b381bdd535dabbc3ff5 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Thu, 15 Feb 2024 14:12:11 +0100 Subject: [PATCH 18/51] feat(impl):[#395] Correct code comments --- .../job/delegate/DigitalTwinDelegate.java | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java index 9ae3afbdc5..5601a2f3ad 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java @@ -68,26 +68,19 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai } try { - final Shell shell = digitalTwinRegistryService.fetchShells( - List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn()))).stream() - // TODO (mfischer): #395: clarify whether this is correct - // Special Scenario: - // Multiple DTs with the same globalAssetId in one DTR: - // If there are multiple shells in this place this means - // that there were multiple DTs with the same globalAssetId - // in one DTR. - // Because there is no defined way which one to select - // the first is returned. - .findFirst() - // No result should result in tombstone, therefore throw. - .orElseThrow(); + final var dtrKeys = List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn())); + final Shell shell = digitalTwinRegistryService.fetchShells(dtrKeys).stream() + // we use findFirst here, because we query only for one + // DigitalTwinRegistryKey here + .findFirst().orElseThrow(); if (!expectedDepthOfTreeIsNotReached(jobData.getDepth(), aasTransferProcess.getDepth())) { // filter submodel descriptors if next delegate will not be executed shell.payload().withFilteredSubmodelDescriptors(jobData.getAspects()); } - itemContainerBuilder.shell(jobData.isAuditContractNegotiation() ? shell : shell.withoutContractAgreementId()); + itemContainerBuilder.shell( + jobData.isAuditContractNegotiation() ? shell : shell.withoutContractAgreementId()); } catch (final RegistryServiceException | RuntimeException e) { // catching generic exception is intended here, // otherwise Jobs stay in state RUNNING forever From 06b1738ad00c6070b9b3082f996e6cd12ea8b412 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 16 Feb 2024 12:49:14 +0100 Subject: [PATCH 19/51] feat(impl):[#395] Remove obsolete todo this code place is not related to this story --- .../job/delegate/RelationshipDelegate.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java index 98127ec15e..aa5c3956fb 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java @@ -76,10 +76,9 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai itemContainerBuilder.build() .getShells() .stream() - // TODO (mfischer): #395 is this part of the story too? need to change? - // if yes, which step in the diagrams is this? .findFirst() - .ifPresent(shell -> shell.payload().findRelationshipEndpointAddresses( + .ifPresent(shell -> shell.payload() + .findRelationshipEndpointAddresses( AspectType.fromValue(relationshipAspect.getName())) .forEach(endpoint -> processEndpoint(endpoint, relationshipAspect, aasTransferProcess, itemContainerBuilder, itemId))); @@ -101,8 +100,8 @@ private void processEndpoint(final Endpoint endpoint, final RelationshipAspect r } try { - final String submodelRawPayload = requestSubmodel(submodelFacade, connectorEndpointsService, - endpoint, itemId.getBpn()).getPayload(); + final String submodelRawPayload = requestSubmodel(submodelFacade, connectorEndpointsService, endpoint, + itemId.getBpn()).getPayload(); final var relationships = jsonUtil.fromString(submodelRawPayload, relationshipAspect.getSubmodelClazz()) .asRelationships(); @@ -118,24 +117,28 @@ private void processEndpoint(final Endpoint endpoint, final RelationshipAspect r } catch (final UsagePolicyException e) { log.info("Encountered usage policy exception: {}. Creating Tombstone.", e.getMessage()); itemContainerBuilder.tombstone( - Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, - 0, ProcessStep.USAGE_POLICY_VALIDATION, jsonUtil.asMap(e.getPolicy()))); + Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, 0, + ProcessStep.USAGE_POLICY_VALIDATION, jsonUtil.asMap(e.getPolicy()))); } catch (final EdcClientException e) { log.info("Submodel Endpoint could not be retrieved for Endpoint: {}. Creating Tombstone.", endpoint.getProtocolInformation().getHref()); itemContainerBuilder.tombstone( - Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, - 0, ProcessStep.SUBMODEL_REQUEST)); + Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, 0, + ProcessStep.SUBMODEL_REQUEST)); } catch (final JsonParseException e) { log.info("Submodel payload did not match the expected AspectType. Creating Tombstone."); itemContainerBuilder.tombstone( - Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, - 0, ProcessStep.SUBMODEL_REQUEST)); + Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, 0, + ProcessStep.SUBMODEL_REQUEST)); } } private static List getBpnsFrom(final List relationships) { - return relationships.stream().map(Relationship::getBpn).filter(StringUtils::isNotBlank).map(Bpn::withManufacturerId).toList(); + return relationships.stream() + .map(Relationship::getBpn) + .filter(StringUtils::isNotBlank) + .map(Bpn::withManufacturerId) + .toList(); } private List getIdsToProcess(final List relationships, From 03737185b4587d11822edc9185ae2b43264ee9a4 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 16 Feb 2024 13:02:08 +0100 Subject: [PATCH 20/51] feat(impl):[#395] Add Contract Item and Contract Offer to glossary --- docs/src/docs/arc42/glossary.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/docs/arc42/glossary.adoc b/docs/src/docs/arc42/glossary.adoc index dbdb67a492..ee413011b2 100644 --- a/docs/src/docs/arc42/glossary.adoc +++ b/docs/src/docs/arc42/glossary.adoc @@ -7,6 +7,8 @@ |Aspect servers (submodel endpoints) | Companies participating in the interorganizational data exchange provides their data over aspect servers. The so called "submodel-descriptors" in the AAS shells are pointing to these AspectServers which provide the data-assets of the participating these companies in Catena-X. |Bill of Materials (BoM) | A Bill of Materials is a comprehensive list of materials, components, sub-assemblies, and the quantities of each needed to manufacture or build a product. It serves as a structured document that provides information about the raw materials, parts, and components required for the production process. |BPN | Business Partner Number +|CatalogItem| A "CatalogItem" from EDC is a synonym for "Contract Offer". +|Contract Offer| A "Contract Offer" is a synonym for "CatalogItem" from EDC. |Data Space|Data Spaces are the key concept for a large-scale, cross-border data economy. This is also the vision of the Gaia-X initiative for a data infrastructure in Europe. The International Data Space Association (IDSA) contributes significantly to this with the architectural model, interfaces, and standards. |DT | Digital Twin |DTR | Digital Twin Registry. The Digital Twin Registry is a registry which lists all digital twins and references their aspects including information about the underlying asset, asset manufacturer, and access options (e.g. aspect endpoints). From e3857a5692dfcfb7fd79474388662d03da945e47 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 16 Feb 2024 13:12:32 +0100 Subject: [PATCH 21/51] feat(impl):[#395] Improve glossary --- docs/src/docs/arc42/glossary.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/docs/arc42/glossary.adoc b/docs/src/docs/arc42/glossary.adoc index ee413011b2..70a78c4aa8 100644 --- a/docs/src/docs/arc42/glossary.adoc +++ b/docs/src/docs/arc42/glossary.adoc @@ -29,6 +29,7 @@ https://github.com/eclipse-tractusx/ssi-docu/blob/main/docs/architecture/cx-3-2/ |PRS | Formerly known Service Name: Parts Relationship Service |Self-Sovereign Identity (SSI) | For more information see: https://github.com/eclipse-tractusx/ssi-docu/tree/main/docs/architecture/cx-3-2[ssi-docu] +|Shell | see "Asset Administration Shell" |Traversal Aspect |aka Edge: Aspect which the IRS uses for traversal through the data chain. Identified by a parent-child or a child-parent relationship. Samples: SingleLevelBomAsPlanned, SingleLevelBomAsBuilt and SingleLevelUsageAsBuilt From 6f37a0a6349aad909e293714de81f686c4ef9e17 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 16 Feb 2024 13:15:50 +0100 Subject: [PATCH 22/51] feat(impl):[#395] Remove obsolete todo edcRestTemplate is correct here, because we communicate with a DTR via an EDC --- .../decentral/DecentralDigitalTwinRegistryClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java index 4b2c1dfa4f..1c7a7ed5b3 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryClient.java @@ -71,7 +71,6 @@ public AssetAdministrationShellDescriptor getAssetAdministrationShellDescriptor( final String descriptorEndpoint = endpointDataReference.getEndpoint() + shellDescriptorTemplate; final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(descriptorEndpoint); final Map values = Map.of(PLACEHOLDER_AAS_IDENTIFIER, encodeWithBase64(aasIdentifier)); - // TODO (mfischer): #395: clarify: shouldn't this be dtrRestTemplate?! return edcRestTemplate.exchange(uriBuilder.build(values), HttpMethod.GET, new HttpEntity<>(null, headers(endpointDataReference)), AssetAdministrationShellDescriptor.class) .getBody(); From d0d78a96a6b92d2d9bb04f2c64bf4906b1c2660f Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 16 Feb 2024 13:36:49 +0100 Subject: [PATCH 23/51] feat(impl):[#395] Improve comprehensibility - better variable/parameter naming - split up stream expression into multiple lines - add helpful code comments to each part - reference special scenario diagram --- .../DecentralDigitalTwinRegistryService.java | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index e8489a5be0..566f0fe3e5 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -225,14 +225,14 @@ private String contractNegotiationId(final String token) { * If the ID is a globalAssetId, the corresponding shellId will be returned. * * @param endpointDataReference the reference to access the digital twin registry - * @param key the ambiguous key (shellId or globalAssetId) - * @return the shellId + * @param providedId the ambiguous ID (shellId or globalAssetId) + * @return the corresponding asset administration shell ID */ @NotNull - private String mapToShellId(final EndpointDataReference endpointDataReference, final String key) { + private String mapToShellId(final EndpointDataReference endpointDataReference, final String providedId) { final var watch = new StopWatch(); - final String msg = "Mapping '%s' to shell ID for endpoint '%s'".formatted(key, + final String msg = "Mapping '%s' to shell ID for endpoint '%s'".formatted(providedId, endpointDataReference.getEndpoint()); watch.start(msg); log.info(msg); @@ -241,22 +241,27 @@ private String mapToShellId(final EndpointDataReference endpointDataReference, f final var identifierKeyValuePair = IdentifierKeyValuePair.builder() .name("globalAssetId") - .value(key) + .value(providedId) .build(); - final var aaShellIdentification = decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink( - endpointDataReference, List.of(identifierKeyValuePair)) - .getResult() - .stream() - .findFirst() - .orElse(key); - - if (key.equals(aaShellIdentification)) { - log.info("Found shell with shellId {} in registry", aaShellIdentification); + + // Try to map the provided ID to the corresponding asset administration shell ID + final var mappingResultStream = decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink( + endpointDataReference, List.of(identifierKeyValuePair)).getResult().stream(); + + // Special scenario: Multiple DTs with the same globalAssetId in one DTR: + // see docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml + final var mappingResult = mappingResultStream.findFirst(); + + // Empty Optional means that the ID is already a shellId + final var shellId = mappingResult.orElse(providedId); + + if (providedId.equals(shellId)) { + log.info("Found shell with shellId {} in registry", shellId); } else { - log.info("Retrieved shellId {} for globalAssetId {}", aaShellIdentification, key); + log.info("Retrieved shellId {} for globalAssetId {}", shellId, providedId); } - return aaShellIdentification; + return shellId; } finally { watch.stop(); From 1ece516ef2e3b9c3d1ebc68e5672296d75eaff0a Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 16 Feb 2024 13:43:14 +0100 Subject: [PATCH 24/51] feat(impl):[#395] Improve glossary --- docs/src/docs/arc42/glossary.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/docs/arc42/glossary.adoc b/docs/src/docs/arc42/glossary.adoc index 70a78c4aa8..b9e206f7b9 100644 --- a/docs/src/docs/arc42/glossary.adoc +++ b/docs/src/docs/arc42/glossary.adoc @@ -3,15 +3,15 @@ |=== |Term |Description -|AAS | Asset Administration Shell (Industry 4.0) +|Asset Administration Shell (AAS) | see "Digital Twin" |Aspect servers (submodel endpoints) | Companies participating in the interorganizational data exchange provides their data over aspect servers. The so called "submodel-descriptors" in the AAS shells are pointing to these AspectServers which provide the data-assets of the participating these companies in Catena-X. |Bill of Materials (BoM) | A Bill of Materials is a comprehensive list of materials, components, sub-assemblies, and the quantities of each needed to manufacture or build a product. It serves as a structured document that provides information about the raw materials, parts, and components required for the production process. |BPN | Business Partner Number |CatalogItem| A "CatalogItem" from EDC is a synonym for "Contract Offer". |Contract Offer| A "Contract Offer" is a synonym for "CatalogItem" from EDC. |Data Space|Data Spaces are the key concept for a large-scale, cross-border data economy. This is also the vision of the Gaia-X initiative for a data infrastructure in Europe. The International Data Space Association (IDSA) contributes significantly to this with the architectural model, interfaces, and standards. -|DT | Digital Twin -|DTR | Digital Twin Registry. The Digital Twin Registry is a registry which lists all digital twins and references their aspects including information about the underlying asset, asset manufacturer, and access options (e.g. aspect endpoints). +|Digital Twin (DT) | The Digital Twin is the key technology of Industry 4.0 and connects the physical world with the digital world and acts as an enabler of the Catena-X network. It is based on a standardized programming interface of the Industrial https://industrialdigitaltwin.org/[Digital Twin Association (IDTA)] and its Asset Administration Shell. +|Digital Twin Registry (DTR) | The Digital Twin Registry is a registry which lists all digital twins and references their aspects including information about the underlying asset, asset manufacturer, and access options (e.g. aspect endpoints). |Eclipse Dataspace Connector (EDC) | The Eclipse Data Space Connector (EDC) is a standard and policy-compliant connector that can be used within the scope of Catena-X, but also more generally as a connector for Data Spaces. It is split up into Control-Plane and Data-Plane, whereas the Control-Plane functions as administration layer and has responsibility of resource management, contract negotiation and administer data transfer. The Data-Plane does the heavy lifting of transferring and receiving data streams. For more information see: https://github.com/eclipse-edc/Connector[EDC Connector] , https://github.com/eclipse-tractusx/tractusx-edc[Tractus-X EDC (Eclipse Dataspace Connector)] |Edge | see Traversal Aspect From 8298522a2bee5cbbf42a5a1cf7153bc2d0bd9a6b Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 16 Feb 2024 14:10:22 +0100 Subject: [PATCH 25/51] feat(impl):[#395] Implementation (but tests still need to be adapted) --- .../configuration/RegistryConfiguration.java | 2 +- .../irs/edc/client/EdcSubmodelClientImpl.java | 99 ++++++++++++------- .../irs/edc/client/EdcSubmodelFacade.java | 16 +-- .../registryclient/DefaultConfiguration.java | 2 +- .../EdcEndpointReferenceRetriever.java | 9 +- .../EndpointDataForConnectorsService.java | 2 +- 6 files changed, 75 insertions(+), 55 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java index 7b398b26b0..900115745e 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java @@ -75,7 +75,7 @@ public DecentralDigitalTwinRegistryService decentralDigitalTwinRegistryService( return new DecentralDigitalTwinRegistryService(connectorEndpointsService, new EndpointDataForConnectorsService((edcConnectorEndpoint, assetType, assetValue) -> { try { - return facade.getEndpointReferenceForAsset(edcConnectorEndpoint, assetType, assetValue); + return facade.getEndpointReferencesForAsset(edcConnectorEndpoint, assetType, assetValue); } catch (EdcClientException e) { throw new EdcRetrieverException(e); } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java index fe6478a119..7c9763f442 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java @@ -30,7 +30,9 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; import io.github.resilience4j.retry.Retry; import io.github.resilience4j.retry.RetryRegistry; @@ -39,7 +41,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.validator.routines.UrlValidator; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; -import org.eclipse.tractusx.irs.common.util.concurrent.ResultFinder; import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceStatus; import org.eclipse.tractusx.irs.edc.client.exceptions.ContractNegotiationException; @@ -166,7 +167,6 @@ private EndpointDataReference getEndpointDataReference(final String connectorEnd log.info("Retrieving endpoint data reference from cache for asset id: {}", assetId); final EndpointDataReferenceStatus cachedEndpointDataReference = endpointDataReferenceCacheService.getEndpointDataReference( assetId); - EndpointDataReference endpointDataReference; if (cachedEndpointDataReference.tokenStatus() == TokenStatus.VALID) { @@ -184,19 +184,15 @@ private EndpointDataReference getEndpointDataReferenceAndAddToStorage(final Stri final String assetId, final EndpointDataReferenceStatus cachedEndpointDataReference) throws EdcClientException { try { - final List> endpointDataReferences = getEndpointReferencesForAsset( - connectorEndpoint, NAMESPACE_EDC_ID, assetId, cachedEndpointDataReference); - - // TODO (mfischer): #395 clarify if we need to use the fastest result here or return the list of futures - // in the latter case we need to move endpointDataReferenceStorage.put somewhere else - final EndpointDataReference fastest = new ResultFinder().getFastestResult(endpointDataReferences).get(); - endpointDataReferenceStorage.put(assetId, fastest); + final EndpointDataReference endpointDataReference = getEndpointReferenceForAsset(connectorEndpoint, + NAMESPACE_EDC_ID, assetId, cachedEndpointDataReference).get(); + endpointDataReferenceStorage.put(assetId, endpointDataReference); - return fastest; + return endpointDataReference; } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new EdcClientException(e); - } catch (ExecutionException e) { + } catch (CompletionException | ExecutionException e) { throw new EdcClientException(e); } } @@ -229,49 +225,82 @@ public List> getEndpointReferencesForAs stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + endpointAddress); final String providerWithSuffix = appendSuffix(endpointAddress, config.getControlplane().getProviderSuffix()); - final List items = catalogFacade.fetchCatalogByFilter(providerWithSuffix, filterKey, filterValue); - final List catalogItems = items.stream().toList(); - if (catalogItems.isEmpty()) { + // CatalogItem = contract offer + final List contractOffers = catalogFacade.fetchCatalogByFilter(providerWithSuffix, filterKey, + filterValue); + + if (contractOffers.isEmpty()) { throw new EdcClientException( "Catalog is empty for endpointAddress '%s' filterKey '%s', filterValue '%s'".formatted( endpointAddress, filterKey, filterValue)); } - return catalogItems.stream().map(catalogItem -> { - - final NegotiationResponse negotiationResponse = negotiateContract(endpointDataReferenceStatus, catalogItem, - providerWithSuffix); - - final String storageId = getStorageId(endpointDataReferenceStatus, negotiationResponse); - - return pollingService.createJob() - .action(() -> retrieveEndpointReference(storageId, stopWatch)) - .timeToLive(config.getSubmodel().getRequestTtl()) - .description("waiting for Endpoint Reference retrieval") - .build() - .schedule(); + // 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 -> { + + final NegotiationResponse negotiationResponse; + try { + negotiationResponse = negotiateContract(endpointDataReferenceStatus, contractOffer, providerWithSuffix); + + final String storageId = getStorageId(endpointDataReferenceStatus, negotiationResponse); + + return pollingService.createJob() + .action(() -> retrieveEndpointReference(storageId, stopWatch)) + .timeToLive(config.getSubmodel().getRequestTtl()) + .description("waiting for Endpoint Reference retrieval") + .build() + .schedule(); + } catch (EdcClientException e) { + log.warn(("Negotiate contract failed for " + + "endpointDataReferenceStatus = '%s', catalogItem = '%s', providerWithSuffix = '%s' ").formatted( + endpointDataReferenceStatus, contractOffer, providerWithSuffix)); + return (CompletableFuture) Stream.empty(); + } }).toList(); } private NegotiationResponse negotiateContract(final EndpointDataReferenceStatus endpointDataReferenceStatus, - final CatalogItem catalogItem, final String providerWithSuffix) { + final CatalogItem catalogItem, final String providerWithSuffix) throws EdcClientException { final NegotiationResponse response; try { response = contractNegotiationService.negotiate(providerWithSuffix, catalogItem, endpointDataReferenceStatus); - // TODO(mfischer): #395 how to handle? - } catch (ContractNegotiationException e) { - throw new RuntimeException(e); - } catch (UsagePolicyException e) { - throw new RuntimeException(e); - } catch (TransferProcessException e) { - throw new RuntimeException(e); + } catch (TransferProcessException | UsagePolicyException | ContractNegotiationException e) { + throw new EdcClientException(("Negotiation failed for endpoint '%s', " + "tokenStatus '%s', " + + "providerWithSuffix '%s', catalogItem '%s'").formatted( + endpointDataReferenceStatus.endpointDataReference(), endpointDataReferenceStatus.tokenStatus(), + providerWithSuffix, endpointDataReferenceStatus), e); } return response; } + public CompletableFuture getEndpointReferenceForAsset(final String endpointAddress, + final String filterKey, final String filterValue, + final EndpointDataReferenceStatus endpointDataReferenceStatus) throws EdcClientException { + final StopWatch stopWatch = new StopWatch(); + + stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + endpointAddress); + final String providerWithSuffix = appendSuffix(endpointAddress, config.getControlplane().getProviderSuffix()); + + final List items = catalogFacade.fetchCatalogByFilter(providerWithSuffix, filterKey, filterValue); + + final NegotiationResponse response = contractNegotiationService.negotiate(providerWithSuffix, + items.stream().findFirst().orElseThrow(), endpointDataReferenceStatus); + + final String storageId = getStorageId(endpointDataReferenceStatus, response); + + return pollingService.createJob() + .action(() -> retrieveEndpointReference(storageId, stopWatch)) + .timeToLive(config.getSubmodel().getRequestTtl()) + .description("waiting for Endpoint Reference retrieval") + .build() + .schedule(); + } + private static String getStorageId(final EndpointDataReferenceStatus endpointDataReferenceStatus, final NegotiationResponse response) { final String storageId; diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java index 8f53fa4683..9a1f747142 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java @@ -24,6 +24,7 @@ package org.eclipse.tractusx.irs.edc.client; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import lombok.RequiredArgsConstructor; @@ -83,20 +84,9 @@ public EdcNotificationResponse sendNotification(final String submodelEndpointAdd } @SuppressWarnings("PMD.PreserveStackTrace") - public List getEndpointReferenceForAsset(final String endpointAddress, + public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue) throws EdcClientException { - try { - return client.getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue).get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return null; - } catch (ExecutionException e) { - final Throwable cause = e.getCause(); - if (cause instanceof EdcClientException exceptionCause) { - throw exceptionCause; - } - throw new EdcClientException(cause); - } + return client.getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue); } } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java index 613c12db3c..7358def2f7 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java @@ -118,7 +118,7 @@ public ConnectorEndpointsService connectorEndpointsService(final DiscoveryFinder public EndpointDataForConnectorsService endpointDataForConnectorsService(final EdcSubmodelFacade facade) { return new EndpointDataForConnectorsService((edcConnectorEndpoint, assetType, assetValue) -> { try { - return facade.getEndpointReferenceForAsset(edcConnectorEndpoint, assetType, assetValue); + return facade.getEndpointReferencesForAsset(edcConnectorEndpoint, assetType, assetValue); } catch (EdcClientException e) { throw new EdcRetrieverException(e); } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java index ea0395647e..9a10d34792 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java @@ -24,6 +24,7 @@ package org.eclipse.tractusx.irs.registryclient.decentral; import java.util.List; +import java.util.concurrent.CompletableFuture; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; @@ -33,14 +34,14 @@ public interface EdcEndpointReferenceRetriever { /** - * Retrieves the EDC endpoint reference from the specified connector endpoint and asset combination + * Retrieves the EDC endpoint references from the specified connector endpoint and asset combination * * @param edcConnectorEndpoint the endpoint URL * @param assetType the asset type id * @param assetValue the asset type value - * @return the endpoint data reference + * @return the endpoint data references as {@link List>} * @throws EdcRetrieverException on any EDC errors */ - List getEndpointReferenceForAsset(String edcConnectorEndpoint, String assetType, - String assetValue) throws EdcRetrieverException; + List> getEndpointReferencesForAsset(String edcConnectorEndpoint, + String assetType, String assetValue) throws EdcRetrieverException; } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java index e7072bdb1e..ed5e5224ce 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java @@ -78,7 +78,7 @@ private List> createGetEndpointReferenc log.info(msg); try { - return edcSubmodelFacade.getEndpointReferenceForAsset(edcUrl, DT_REGISTRY_ASSET_TYPE, + return edcSubmodelFacade.getEndpointReferencesForAsset(edcUrl, DT_REGISTRY_ASSET_TYPE, DT_REGISTRY_ASSET_VALUE); } catch (EdcRetrieverException e) { log.warn("Exception occurred when retrieving EndpointDataReference from connector '{}'", edcUrl, e); From 0dbb8bbe35745cabc0388da517b923cd371f6342 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Sat, 17 Feb 2024 02:23:47 +0100 Subject: [PATCH 26/51] feat(impl):[#395] Adjust test --- .../irs/edc/client/EdcSubmodelClientTest.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index f69cb1eed1..b9d7470430 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -196,7 +196,8 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsBuil new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) - .get(5, TimeUnit.SECONDS).getPayload(); + .get(5, TimeUnit.SECONDS) + .getPayload(); assertThat(submodelResponse).contains(existingCatenaXId); } @@ -211,7 +212,8 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsPlan new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) - .get(5, TimeUnit.SECONDS).getPayload(); + .get(5, TimeUnit.SECONDS) + .getPayload(); assertThat(submodelResponse).contains("urn:uuid:e5c96ab5-896a-482c-8761-efd74777ca97"); } @@ -226,7 +228,8 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsSpec new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) - .get(5, TimeUnit.SECONDS).getPayload(); + .get(5, TimeUnit.SECONDS) + .getPayload(); assertThat(submodelResponse).contains("urn:uuid:2afbac90-a662-4f16-9058-4f030e692631"); } @@ -241,7 +244,8 @@ void shouldReturnEmptyRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelUsag new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) - .get(5, TimeUnit.SECONDS).getPayload(); + .get(5, TimeUnit.SECONDS) + .getPayload(); assertThat(submodelResponse).isNotEmpty(); } @@ -257,7 +261,8 @@ void shouldReturnEmptyRelationshipsWhenRequestingWithNotExistingCatenaXIdAndSing new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) - .get(5, TimeUnit.SECONDS).getPayload(); + .get(5, TimeUnit.SECONDS) + .getPayload(); assertThat(submodelResponse).isEqualTo("{}"); } @@ -272,8 +277,9 @@ void shouldReturnRawSerialPartWhenExisting() throws Exception { new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelPayload("https://connector.endpoint.com", - "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID) - .get(5, TimeUnit.SECONDS).getPayload(); + "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID) + .get(5, TimeUnit.SECONDS) + .getPayload(); assertThat(submodelResponse).startsWith( "{\"localIdentifiers\":[{\"value\":\"BPNL00000003AVTH\",\"key\":\"manufacturerId\"}"); @@ -290,8 +296,9 @@ void shouldUseDecodedTargetId() throws Exception { new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); final String submodelResponse = testee.getSubmodelPayload("https://connector.endpoint.com", - "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID) - .get(5, TimeUnit.SECONDS).getPayload(); + "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID) + .get(5, TimeUnit.SECONDS) + .getPayload(); assertThat(submodelResponse).startsWith( "{\"localIdentifiers\":[{\"value\":\"BPNL00000003AVTH\",\"key\":\"manufacturerId\"}"); @@ -348,7 +355,7 @@ void shouldRetrieveEndpointReferenceForAsset() throws Exception { // act final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue, new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); - final EndpointDataReference actual = result.get(5, TimeUnit.SECONDS); + final EndpointDataReference actual = result.get(0).get(5, TimeUnit.SECONDS); // assert assertThat(actual).isEqualTo(expected); @@ -370,7 +377,7 @@ void shouldRetrieveEndpointReferenceForAsset2() throws Exception { // act final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue); - final EndpointDataReference actual = result.get(5, TimeUnit.SECONDS); + final EndpointDataReference actual = result.get(0).get(5, TimeUnit.SECONDS); // assert assertThat(actual).isEqualTo(expected); @@ -381,8 +388,7 @@ void shouldUseCachedEndpointReferenceValueWhenTokenIsValid() throws EdcClientException, ExecutionException, InterruptedException { // given when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn( - new EndpointDataReferenceStatus(TestMother.endpointDataReference("assetId"), - TokenStatus.VALID)); + new EndpointDataReferenceStatus(TestMother.endpointDataReference("assetId"), TokenStatus.VALID)); final String value = "result"; when(edcDataPlaneClient.getData(any(), any())).thenReturn(value); From 1d2780380adcd2f8e39867ef32c90afa3ba11a41 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 12:24:39 +0100 Subject: [PATCH 27/51] feat(impl):[#395] Fix exception handling --- .../decentral/EndpointDataForConnectorsService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java index ed5e5224ce..7b2af22161 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java @@ -26,7 +26,6 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -82,7 +81,7 @@ private List> createGetEndpointReferenc DT_REGISTRY_ASSET_VALUE); } catch (EdcRetrieverException e) { log.warn("Exception occurred when retrieving EndpointDataReference from connector '{}'", edcUrl, e); - throw new CompletionException(e.getMessage(), e); + return List.of(CompletableFuture.failedFuture(e)); } finally { watch.stop(); log.info(TOOK_MS, watch.getLastTaskName(), watch.getLastTaskTimeMillis()); From 1e6cda4b205cb543b047148ae648bcb02b59c484 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 12:26:36 +0100 Subject: [PATCH 28/51] feat(impl):[#395] Add missing Thread.currentThread().interrupt() --- .../tractusx/irs/common/util/concurrent/ResultFinderTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java index 90c783f276..06e51406ad 100644 --- a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java +++ b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java @@ -155,6 +155,7 @@ private static void sleep(final int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); throw new RuntimeException(e); } } From dbf3066d792c87e2c9c6f2a4fb051f265fe6ced7 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 12:29:21 +0100 Subject: [PATCH 29/51] feat(impl):[#395] Fix tests And remove test concerning InterruptedException which is no longer relevant in this place. --- .../irs/edc/client/EdcSubmodelFacadeTest.java | 37 +++++++------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java index f5da7540c0..e5bc52abb3 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -158,8 +159,8 @@ void shouldThrowEdcClientExceptionForNotification() throws EdcClientException { } @Nested - @DisplayName("getEndpointReferenceForAsset") - class GetEndpointReferenceForAssetTests { + @DisplayName("getEndpointReferencesForAsset") + class GetEndpointReferencesForAssetTests { @Test void shouldThrowEdcClientExceptionForEndpointReference() throws EdcClientException { @@ -168,40 +169,28 @@ void shouldThrowEdcClientExceptionForEndpointReference() throws EdcClientExcepti when(client.getEndpointReferencesForAsset(any(), any(), any())).thenThrow(e); // act - ThrowableAssert.ThrowingCallable action = () -> testee.getEndpointReferenceForAsset("", "", ""); + ThrowableAssert.ThrowingCallable action = () -> testee.getEndpointReferencesForAsset("", "", ""); // assert assertThatThrownBy(action).isInstanceOf(EdcClientException.class); } @Test - void shouldThrowExecutionExceptionForEndpointReference() throws EdcClientException { - // arrange - final ExecutionException e = new ExecutionException(new EdcClientException("test")); - final CompletableFuture future = CompletableFuture.failedFuture(e); - when(client.getEndpointReferencesForAsset(any(), any(), any())).thenReturn(future); - - // act - ThrowableAssert.ThrowingCallable action = () -> testee.getEndpointReferenceForAsset("", "", ""); + void shouldReturnFailedFuture() throws EdcClientException { - // assert - assertThatThrownBy(action).isInstanceOf(EdcClientException.class); - } - - @Test - void shouldRestoreInterruptOnInterruptExceptionForEndpointReference() - throws EdcClientException, ExecutionException, InterruptedException { // arrange - final CompletableFuture future = mock(CompletableFuture.class); - final InterruptedException e = new InterruptedException(); - when(future.get()).thenThrow(e); - when(client.getEndpointReferencesForAsset(any(), any(), any())).thenReturn(future); + when(client.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + List.of(CompletableFuture.failedFuture(new EdcClientException("test")))); // act - testee.getEndpointReferenceForAsset("", "", ""); + final List> results = testee.getEndpointReferencesForAsset("", "", + ""); // assert - assertThat(Thread.currentThread().isInterrupted()).isTrue(); + assertThat(results).hasSize(1); + assertThatThrownBy(() -> results.get(0).get()).isInstanceOf(ExecutionException.class) + .extracting(Throwable::getCause) + .isInstanceOf(EdcClientException.class); } } From bb7c3a211509265760cd5579862a7b9599aecba9 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 12:38:36 +0100 Subject: [PATCH 30/51] feat(impl):[#395] Improve readability --- .../org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java index 5bd23a282a..eaadf11ab5 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java @@ -290,7 +290,6 @@ private void successfulRegistryAndDataRequest(final String globalAssetId, final final String singleLevelBomAsBuilt = WiremockSupport.submodelRequest(edcAssetId, "SingleLevelBomAsBuilt", "urn:bamm:io.catenax.single_level_bom_as_built:2.0.0#SingleLevelBomAsBuilt", sbomFileName); - successfulNegotiation(edcAssetId); final List submodelDescriptors = List.of(batch, singleLevelBomAsBuilt); final String shellId = WiremockSupport.randomUUIDwithPrefix(); @@ -300,6 +299,7 @@ private void successfulRegistryAndDataRequest(final String globalAssetId, final containing(globalAssetId))); stubFor(getShellDescriptor200(PUBLIC_SHELL_DESCRIPTORS_PATH + WiremockSupport.encodedId(shellId), bpn, submodelDescriptors, globalAssetId, shellId, idShort)); + successfulNegotiation(edcAssetId); } private void successfulNegotiation(final String edcAssetId) { From 97f6b55aee5148cc9a8b3ac17fbf72c6bd03c811 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 12:39:28 +0100 Subject: [PATCH 31/51] feat(impl):[#395] Assert interrupt --- .../decentral/DecentralDigitalTwinRegistryServiceTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java index 926b9de649..abf3eb481d 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java @@ -141,6 +141,8 @@ void whenInterruptedExceptionOccurs() throws ExecutionException, InterruptedExce .satisfies(e -> assertThat( ((ShellNotFoundException) e).getCalledEndpoints()).containsExactlyInAnyOrder( "address1", "address2")); + + assertThat(Thread.currentThread().isInterrupted()).isTrue(); } @Test From d9b08f7f5c7a5739d393d6a71a1e10cf69ce66d0 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 13:21:46 +0100 Subject: [PATCH 32/51] feat(impl):[#395] Fix test --- .../registryclient/DefaultConfigurationTest.java | 13 +++++++++---- .../EndpointDataForConnectorsServiceTest.java | 14 ++++++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java index 4a3b67fd5f..274d8387b2 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.when; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; @@ -82,7 +83,8 @@ void endpointDataForConnectorsService() throws EdcClientException { final var mock = mock(EdcSubmodelFacade.class); final var endpointAddress = "endpointaddress"; final var endpointDataReference = EndpointDataReference.Builder.newInstance().endpoint(endpointAddress).build(); - when(mock.getEndpointReferenceForAsset(eq(endpointAddress), any(), any())).thenReturn(endpointDataReference); + when(mock.getEndpointReferencesForAsset(eq(endpointAddress), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference))); // ACT final var endpointDataForConnectorsService = testee.endpointDataForConnectorsService(mock); @@ -91,19 +93,22 @@ void endpointDataForConnectorsService() throws EdcClientException { .forEach(future -> { try { future.get(); - } catch (InterruptedException | ExecutionException e) { + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } catch (ExecutionException e) { throw new RuntimeException(e); } }); // ASSERT - verify(mock).getEndpointReferenceForAsset(eq(endpointAddress), any(), any()); + verify(mock).getEndpointReferencesForAsset(eq(endpointAddress), any(), any()); } @Test void endpointDataForConnectorsService_withException() throws EdcClientException { final var mock = mock(EdcSubmodelFacade.class); - when(mock.getEndpointReferenceForAsset(any(), any(), any())).thenThrow(new EdcClientException("test")); + when(mock.getEndpointReferencesForAsset(any(), any(), any())).thenThrow(new EdcClientException("test")); final var endpointDataForConnectorsService = testee.endpointDataForConnectorsService(mock); final var dummyEndpoints = List.of("test"); diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java index 085b015d8b..b4a8b9f922 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java @@ -62,8 +62,9 @@ class EndpointDataForConnectorsServiceTest { void shouldReturnExpectedEndpointDataReference() throws EdcRetrieverException { // GIVEN - when(edcSubmodelFacade.getEndpointReferenceForAsset(connectionOneAddress, DT_REGISTRY_ASSET_TYPE, - DT_REGISTRY_ASSET_VALUE)).thenReturn(CONNECTION_ONE_DATA_REF); + when(edcSubmodelFacade.getEndpointReferencesForAsset(connectionOneAddress, DT_REGISTRY_ASSET_TYPE, + DT_REGISTRY_ASSET_VALUE)).thenReturn( + List.of(CompletableFuture.completedFuture(CONNECTION_ONE_DATA_REF))); // WHEN final List> endpointDataReferences = sut.createFindEndpointDataForConnectorsFutures( @@ -83,13 +84,14 @@ void shouldReturnExpectedEndpointDataReferenceFromSecondConnectionEndpoint() thr // GIVEN // a first endpoint failing (1) - when(edcSubmodelFacade.getEndpointReferenceForAsset(connectionOneAddress, DT_REGISTRY_ASSET_TYPE, + when(edcSubmodelFacade.getEndpointReferencesForAsset(connectionOneAddress, DT_REGISTRY_ASSET_TYPE, DT_REGISTRY_ASSET_VALUE)).thenThrow( new EdcRetrieverException(new EdcClientException("EdcClientException"))); // and a second endpoint returning successfully (2) - when(edcSubmodelFacade.getEndpointReferenceForAsset(connectionTwoAddress, DT_REGISTRY_ASSET_TYPE, - DT_REGISTRY_ASSET_VALUE)).thenReturn(CONNECTION_TWO_DATA_REF); + when(edcSubmodelFacade.getEndpointReferencesForAsset(connectionTwoAddress, DT_REGISTRY_ASSET_TYPE, + DT_REGISTRY_ASSET_VALUE)).thenReturn( + List.of(CompletableFuture.completedFuture(CONNECTION_TWO_DATA_REF))); // WHEN final List> dataRefFutures = // @@ -123,7 +125,7 @@ private static EndpointDataReference executeFutureMappingErrorsToNull( void shouldThrowExceptionWhenConnectorEndpointsNotReachable() throws EdcRetrieverException { // GIVEN - when(edcSubmodelFacade.getEndpointReferenceForAsset(anyString(), eq(DT_REGISTRY_ASSET_TYPE), + when(edcSubmodelFacade.getEndpointReferencesForAsset(anyString(), eq(DT_REGISTRY_ASSET_TYPE), eq(DT_REGISTRY_ASSET_VALUE))).thenThrow( new EdcRetrieverException(new EdcClientException("EdcClientException"))); From b34ffcd953068708efba8d9499de03b49c646e29 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 13:28:03 +0100 Subject: [PATCH 33/51] feat(impl):[#395] Add some wiremock tests --- ...igitalTwinRegistryServiceWiremockTest.java | 84 +++++++++++++++---- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java index 044a55b7b0..e2b6f69fc4 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java @@ -56,6 +56,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; @@ -70,7 +71,6 @@ import org.eclipse.tractusx.irs.registryclient.exceptions.RegistryServiceException; import org.eclipse.tractusx.irs.registryclient.exceptions.ShellNotFoundException; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; @@ -92,20 +92,22 @@ void setUp(WireMockRuntimeInfo wireMockRuntimeInfo) throws EdcRetrieverException SHELL_DESCRIPTORS_TEMPLATE, LOOKUP_SHELLS_TEMPLATE); decentralDigitalTwinRegistryService = new DecentralDigitalTwinRegistryService(connectorEndpointsService, endpointDataForConnectorsService, decentralDigitalTwinRegistryClient); - final var endpointDataReference = endpointDataReference("assetId"); - when(edcSubmodelFacadeMock.getEndpointReferenceForAsset(any(), any(), any())).thenReturn(endpointDataReference); } @Nested class FetchShellsTests { @Test - void shouldDiscoverEDCAndRequestRegistry() throws RegistryServiceException { + void shouldDiscoverEDCAndRequestRegistry() throws RegistryServiceException, EdcRetrieverException { // Arrange givenThat(postDiscoveryFinder200()); givenThat(postEdcDiscovery200()); givenThat(getLookupShells200()); givenThat(getShellDescriptor200()); + final var endpointDataReference = endpointDataReference("assetId"); + when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference))); + // Act final Collection shells = decentralDigitalTwinRegistryService.fetchShells( List.of(new DigitalTwinRegistryKey("testId", TEST_BPN))); @@ -146,10 +148,15 @@ void shouldThrowInCaseOfEdcDiscoveryError() { } @Test - void shouldThrowInCaseOfLookupShellsError() { + void shouldThrowInCaseOfLookupShellsError() throws EdcRetrieverException { // Arrange givenThat(postDiscoveryFinder200()); givenThat(postEdcDiscovery200()); + + final var endpointDataReference = endpointDataReference("assetId"); + when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference))); + givenThat(getLookupShells404()); final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); @@ -162,10 +169,15 @@ void shouldThrowInCaseOfLookupShellsError() { } @Test - void shouldThrowInCaseOfShellDescriptorsError() { + void shouldThrowInCaseOfShellDescriptorsError() throws EdcRetrieverException { // Arrange givenThat(postDiscoveryFinder200()); givenThat(postEdcDiscovery200()); + + final var endpointDataReference = endpointDataReference("assetId"); + when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference))); + givenThat(getLookupShells200()); givenThat(getShellDescriptor404()); final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); @@ -180,10 +192,15 @@ void shouldThrowInCaseOfShellDescriptorsError() { } @Test - void shouldThrowExceptionOnEmptyShells() { + void shouldThrowExceptionOnEmptyShells() throws EdcRetrieverException { // Arrange givenThat(postDiscoveryFinder200()); givenThat(postEdcDiscovery200()); + + final var endpointDataReference = endpointDataReference("assetId"); + when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference))); + givenThat(getLookupShells200Empty()); givenThat(getShellDescriptor404()); final List testId = List.of(new DigitalTwinRegistryKey("testId", TEST_BPN)); @@ -202,16 +219,55 @@ void shouldThrowExceptionOnEmptyShells() { class LookupShellIdentifiersTests { @Test - // TODO(mfischer): add tests for lookupShellIdentifiers - @Disabled("not yet implemented") - void test() { + void lookupShellIdentifiers_oneEDC_oneDTR() throws RegistryServiceException, EdcRetrieverException { // Arrange - // ... + givenThat(postDiscoveryFinder200()); + final List edcUrls = List.of("https://test.edc.io"); + givenThat(postEdcDiscovery200(TEST_BPN, edcUrls)); + givenThat(getLookupShells200()); + + // simulate endpoint data reference + final var endpointDataReference = endpointDataReference("assetId"); + when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference))); // Act & Assert - assertThatThrownBy(() -> decentralDigitalTwinRegistryService.lookupShellIdentifiers(TEST_BPN)).isInstanceOf( - ShellNotFoundException.class); - // ... + final Collection digitalTwinRegistryKeys = decentralDigitalTwinRegistryService.lookupShellIdentifiers( + TEST_BPN); + + // Assert + assertThat(digitalTwinRegistryKeys).hasSize(1); + assertThat(digitalTwinRegistryKeys.stream().findFirst().get().shellId()).isEqualTo( + "urn:uuid:21f7ebea-fa8a-410c-a656-bd9082e67dcf"); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + verify(exactly(edcUrls.size()), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); + } + + @Test + void lookupShellIdentifiers_multipleEDCs_oneDTR() throws RegistryServiceException, EdcRetrieverException { + // Arrange + givenThat(postDiscoveryFinder200()); + final List edcUrls = List.of("https://test.edc1.io", "https://test.edc2.io"); + givenThat(postEdcDiscovery200(TEST_BPN, edcUrls)); + givenThat(getLookupShells200()); + + // simulate endpoint data reference + final var endpointDataReference = endpointDataReference("assetId"); + when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference))); + + // Act & Assert + final Collection digitalTwinRegistryKeys = decentralDigitalTwinRegistryService.lookupShellIdentifiers( + TEST_BPN); + + // Assert + assertThat(digitalTwinRegistryKeys).hasSize(1); + assertThat(digitalTwinRegistryKeys.stream().findFirst().get().shellId()).isEqualTo( + "urn:uuid:21f7ebea-fa8a-410c-a656-bd9082e67dcf"); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + verify(exactly(edcUrls.size()), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); } } From 1cfd3e52ead4dcc5fd0acc6fb9844f69effc686d Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 13:29:56 +0100 Subject: [PATCH 34/51] feat(impl):[#395] Cleanup --- .../DecentralDigitalTwinRegistryServiceWiremockTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java index e2b6f69fc4..019b2c8cba 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java @@ -82,7 +82,7 @@ class DecentralDigitalTwinRegistryServiceWiremockTest { private DecentralDigitalTwinRegistryService decentralDigitalTwinRegistryService; @BeforeEach - void setUp(WireMockRuntimeInfo wireMockRuntimeInfo) throws EdcRetrieverException { + void setUp(WireMockRuntimeInfo wireMockRuntimeInfo) { final RestTemplate restTemplate = restTemplateProxy(PROXY_SERVER_HOST, wireMockRuntimeInfo.getHttpPort()); final var discoveryFinderClient = new DiscoveryFinderClientImpl(DISCOVERY_FINDER_URL, restTemplate); From cacf29fbdbf5eb5085873192c6d2c3e9abb2ddfd Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 13:46:44 +0100 Subject: [PATCH 35/51] feat(impl):[#395] Fix javadoc --- .../registryclient/decentral/EdcEndpointReferenceRetriever.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java index 9a10d34792..d27f5748c7 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java @@ -39,7 +39,7 @@ public interface EdcEndpointReferenceRetriever { * @param edcConnectorEndpoint the endpoint URL * @param assetType the asset type id * @param assetValue the asset type value - * @return the endpoint data references as {@link List>} + * @return the endpoint data references as list of futures * @throws EdcRetrieverException on any EDC errors */ List> getEndpointReferencesForAsset(String edcConnectorEndpoint, From 090a26523eb7e36b75054b1658a1860e36334dc7 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 13:49:34 +0100 Subject: [PATCH 36/51] feat(impl):[#395] Fix long line --- .../decentral/DecentralDigitalTwinRegistryService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index 566f0fe3e5..a16823225e 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -248,8 +248,8 @@ private String mapToShellId(final EndpointDataReference endpointDataReference, f final var mappingResultStream = decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink( endpointDataReference, List.of(identifierKeyValuePair)).getResult().stream(); - // Special scenario: Multiple DTs with the same globalAssetId in one DTR: - // see docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml + // Special scenario: Multiple DTs with the same globalAssetId in one DTR, see: + // docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml final var mappingResult = mappingResultStream.findFirst(); // Empty Optional means that the ID is already a shellId From 45d069d03a59cd7956738fa0138c968a4fefe7e8 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 14:03:48 +0100 Subject: [PATCH 37/51] feat(impl):[#395] Fix long line --- .../decentral/DecentralDigitalTwinRegistryService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index a16823225e..1dae81a70f 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -249,7 +249,7 @@ private String mapToShellId(final EndpointDataReference endpointDataReference, f endpointDataReference, List.of(identifierKeyValuePair)).getResult().stream(); // Special scenario: Multiple DTs with the same globalAssetId in one DTR, see: - // docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml + // docs/arc42/cross-cutting/discovery-DTR--multiple-DTs-with-the-same-globalAssedId-in-one-DTR.puml final var mappingResult = mappingResultStream.findFirst(); // Empty Optional means that the ID is already a shellId From 3aedb0d2dda157b3bab5c1a1ff9e37a965e93eaf Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 15:27:43 +0100 Subject: [PATCH 38/51] feat(impl):[#395] Inline short method --- .../irs/edc/client/EdcSubmodelClientImpl.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java index 7c9763f442..5c0bfeada7 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java @@ -69,7 +69,9 @@ public class EdcSubmodelClientImpl implements EdcSubmodelClient { private final EdcConfiguration config; private final ContractNegotiationService contractNegotiationService; private final EdcDataPlaneClient edcDataPlaneClient; + private final EndpointDataReferenceStorage endpointDataReferenceStorage; + private final AsyncPollingService pollingService; private final RetryRegistry retryRegistry; private final EDCCatalogFacade catalogFacade; @@ -115,16 +117,18 @@ private String getContractAgreementId(final String authCode) { private Optional retrieveEndpointReference(final String storageId, final StopWatch stopWatch) { - final Optional dataReference = retrieveEndpointDataReferenceByContractAgreementId( - storageId); + + log.info("Retrieving dataReference from storage for storageId (assetId or contractAgreementId): {}", + Masker.mask(storageId)); + final Optional dataReference = endpointDataReferenceStorage.get(storageId); if (dataReference.isPresent()) { final EndpointDataReference ref = dataReference.get(); log.info("Retrieving Endpoint Reference data from EDC data plane with id: {}", ref.getId()); stopWatchOnEdcTask(stopWatch); - return Optional.of(ref); } + return Optional.empty(); } @@ -328,12 +332,6 @@ private String appendSuffix(final String endpointAddress, final String providerS return addressWithSuffix; } - private Optional retrieveEndpointDataReferenceByContractAgreementId(final String storageId) { - log.info("Retrieving dataReference from storage for storageId (assetId or contractAgreementId): {}", - Masker.mask(storageId)); - return endpointDataReferenceStorage.get(storageId); - } - @SuppressWarnings({ "PMD.AvoidRethrowingException", "PMD.AvoidCatchingGenericException" }) From 5725012f09f668e7b9f897b99bb3a287abad2760 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 17:01:04 +0100 Subject: [PATCH 39/51] feat(impl):[#395] Reduce number of dependencies of EdcSubmodelClientImpl by accessing EndpointDataReferenceStorage via EndpointDataReferenceCacheService only --- .../irs/configuration/JobConfiguration.java | 8 +++----- .../irs/edc/client/EdcSubmodelClientImpl.java | 7 ++----- .../EndpointDataReferenceCacheService.java | 10 ++++++++++ .../irs/edc/client/EdcSubmodelClientTest.java | 6 +++--- .../edc/client/SubmodelFacadeWiremockTest.java | 9 ++++----- .../irs/edc/client/SubmodelRetryerTest.java | 18 +++++++++--------- .../registryclient/DefaultConfiguration.java | 9 ++++----- 7 files changed, 35 insertions(+), 32 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/JobConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/JobConfiguration.java index 94d61c09eb..8857e26c5c 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/JobConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/JobConfiguration.java @@ -59,7 +59,6 @@ import org.eclipse.tractusx.irs.edc.client.EdcSubmodelClientImpl; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelClientLocalStub; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; -import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; import org.eclipse.tractusx.irs.registryclient.DigitalTwinRegistryService; import org.eclipse.tractusx.irs.registryclient.central.DigitalTwinRegistryClient; @@ -184,11 +183,10 @@ public EdcSubmodelClient edcLocalSubmodelClient(final CxTestDataContainer cxTest @Bean public EdcSubmodelClient edcSubmodelClient(final EdcConfiguration edcConfiguration, final ContractNegotiationService contractNegotiationService, final EdcDataPlaneClient edcDataPlaneClient, - final EndpointDataReferenceStorage endpointDataReferenceStorage, final AsyncPollingService pollingService, - final RetryRegistry retryRegistry, final EDCCatalogFacade catalogFacade, + final AsyncPollingService pollingService, final RetryRegistry retryRegistry, + final EDCCatalogFacade catalogFacade, final EndpointDataReferenceCacheService endpointDataReferenceCacheService) { return new EdcSubmodelClientImpl(edcConfiguration, contractNegotiationService, edcDataPlaneClient, - endpointDataReferenceStorage, pollingService, retryRegistry, catalogFacade, - endpointDataReferenceCacheService); + pollingService, retryRegistry, catalogFacade, endpointDataReferenceCacheService); } } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java index 5c0bfeada7..44c5fef93c 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java @@ -69,9 +69,6 @@ public class EdcSubmodelClientImpl implements EdcSubmodelClient { private final EdcConfiguration config; private final ContractNegotiationService contractNegotiationService; private final EdcDataPlaneClient edcDataPlaneClient; - - private final EndpointDataReferenceStorage endpointDataReferenceStorage; - private final AsyncPollingService pollingService; private final RetryRegistry retryRegistry; private final EDCCatalogFacade catalogFacade; @@ -120,7 +117,7 @@ private Optional retrieveEndpointReference(final String s log.info("Retrieving dataReference from storage for storageId (assetId or contractAgreementId): {}", Masker.mask(storageId)); - final Optional dataReference = endpointDataReferenceStorage.get(storageId); + final var dataReference = endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(storageId); if (dataReference.isPresent()) { final EndpointDataReference ref = dataReference.get(); @@ -190,7 +187,7 @@ private EndpointDataReference getEndpointDataReferenceAndAddToStorage(final Stri try { final EndpointDataReference endpointDataReference = getEndpointReferenceForAsset(connectorEndpoint, NAMESPACE_EDC_ID, assetId, cachedEndpointDataReference).get(); - endpointDataReferenceStorage.put(assetId, endpointDataReference); + endpointDataReferenceCacheService.putEndpointDataReferenceIntoStorage(assetId, endpointDataReference); return endpointDataReference; } catch (InterruptedException e) { diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java index 264f080339..a1d91211f8 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java @@ -81,6 +81,15 @@ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId return new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW); } + public Optional getEndpointDataReferenceFromStorage(final String storageId) { + return endpointDataReferenceStorage.get(storageId); + } + + public void putEndpointDataReferenceIntoStorage(final String assetId, + final EndpointDataReference endpointDataReference) { + endpointDataReferenceStorage.put(assetId, endpointDataReference); + } + private Optional retrieveEndpointReferenceByAssetId(final String assetId) { log.info("Retrieving dataReference from storage for assetId {}", assetId); return endpointDataReferenceStorage.get(assetId); @@ -94,6 +103,7 @@ private static boolean isTokenExpired(final @NotNull String authCode) { private static Instant extractTokenExpiration(final String token) { return Instant.ofEpochSecond(EDRAuthCode.fromAuthCodeToken(token).getExp()); } + } diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index b9d7470430..ad24a70cdf 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -125,9 +125,9 @@ void setUp() { config.setSubmodel(new EdcConfiguration.SubmodelConfig()); config.getSubmodel().setUrnPrefix("/urn"); config.getSubmodel().setRequestTtl(Duration.ofMinutes(10)); - testee = new EdcSubmodelClientImpl(config, contractNegotiationService, edcDataPlaneClient, - endpointDataReferenceStorage, pollingService, retryRegistry, catalogFacade, - endpointDataReferenceCacheService); + + testee = new EdcSubmodelClientImpl(config, contractNegotiationService, edcDataPlaneClient, pollingService, + retryRegistry, catalogFacade, endpointDataReferenceCacheService); } @Test diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java index f96987c366..c61a44b162 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java @@ -128,15 +128,15 @@ void configureSystemUnderTest(WireMockRuntimeInfo wireMockRuntimeInfo) { when(acceptedPoliciesProvider.getAcceptedPolicies()).thenReturn(List.of(new AcceptedPolicy(policy("IRS Policy", List.of(new Permission(PolicyType.USE, new Constraints( List.of(new Constraint("Membership", new Operator(OperatorType.EQ), "active"), - new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), "active")), - new ArrayList<>())))), OffsetDateTime.now().plusYears(1)))); + new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), + "active")), new ArrayList<>())))), OffsetDateTime.now().plusYears(1)))); final PolicyCheckerService policyCheckerService = new PolicyCheckerService(acceptedPoliciesProvider, new ConstraintCheckerService()); final ContractNegotiationService contractNegotiationService = new ContractNegotiationService(controlPlaneClient, policyCheckerService, config); final RetryRegistry retryRegistry = RetryRegistry.ofDefaults(); - this.edcSubmodelClient = new EdcSubmodelClientImpl(config, contractNegotiationService, dataPlaneClient, storage, + this.edcSubmodelClient = new EdcSubmodelClientImpl(config, contractNegotiationService, dataPlaneClient, pollingService, retryRegistry, catalogFacade, endpointDataReferenceCacheService); } @@ -193,8 +193,7 @@ void shouldThrowExceptionWhenPoliciesAreNotAccepted() { final List andConstraints = List.of( new Constraint("Membership", new Operator(OperatorType.EQ), "active")); final ArrayList orConstraints = new ArrayList<>(); - final Permission permission = new Permission(PolicyType.USE, - new Constraints(andConstraints, orConstraints)); + final Permission permission = new Permission(PolicyType.USE, new Constraints(andConstraints, orConstraints)); final AcceptedPolicy acceptedPolicy = new AcceptedPolicy(policy("IRS Policy", List.of(permission)), OffsetDateTime.now().plusYears(1)); diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java index 7758811e42..2e77ca8da2 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java @@ -82,7 +82,6 @@ void setUp() { Duration.ofMinutes(1)); final EdcSubmodelClient client = new EdcSubmodelClientImpl(config, negotiationService, dataPlaneClient, - endpointDataReferenceStorage, pollingService, retryRegistry, catalogFacade, endpointDataReferenceCacheService); testee = new EdcSubmodelFacade(client); } @@ -94,14 +93,14 @@ void shouldRetryExecutionOfGetSubmodelOnClientMaxAttemptTimes() { eq(String.class))).willThrow( new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, "EDC remote exception")); - when(endpointDataReferenceCacheService.getEndpointDataReference("9300395e-c0a5-4e88-bc57-a3973fec4c26")).thenReturn(new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); + when(endpointDataReferenceCacheService.getEndpointDataReference( + "9300395e-c0a5-4e88-bc57-a3973fec4c26")).thenReturn( + new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); // Act - assertThatThrownBy(() -> testee.getSubmodelPayload( - "https://connector.endpoint.com", + assertThatThrownBy(() -> testee.getSubmodelPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", - "9300395e-c0a5-4e88-bc57-a3973fec4c26")).hasCauseInstanceOf( - HttpServerErrorException.class); + "9300395e-c0a5-4e88-bc57-a3973fec4c26")).hasCauseInstanceOf(HttpServerErrorException.class); // Assert verify(restTemplate, times(retryRegistry.getDefaultConfig().getMaxAttempts())).exchange(any(String.class), @@ -113,11 +112,12 @@ void shouldRetryOnAnyRuntimeException() { // Arrange given(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))).willThrow(new RuntimeException("EDC remote exception")); - when(endpointDataReferenceCacheService.getEndpointDataReference("9300395e-c0a5-4e88-bc57-a3973fec4c26")).thenReturn(new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); + when(endpointDataReferenceCacheService.getEndpointDataReference( + "9300395e-c0a5-4e88-bc57-a3973fec4c26")).thenReturn( + new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); // Act - assertThatThrownBy(() -> testee.getSubmodelPayload( - "https://connector.endpoint.com", + assertThatThrownBy(() -> testee.getSubmodelPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", "9300395e-c0a5-4e88-bc57-a3973fec4c26")).hasCauseInstanceOf(RuntimeException.class); diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java index 7358def2f7..307a80fac5 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java @@ -36,7 +36,6 @@ import org.eclipse.tractusx.irs.edc.client.EdcSubmodelClient; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelClientImpl; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; -import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; import org.eclipse.tractusx.irs.edc.client.cache.endpointdatareference.EndpointDataReferenceCacheService; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; import org.eclipse.tractusx.irs.registryclient.central.CentralDigitalTwinRegistryService; @@ -134,12 +133,12 @@ public EdcSubmodelFacade edcSubmodelFacade(final EdcSubmodelClient client) { @ConditionalOnProperty(prefix = CONFIG_PREFIX, name = CONFIG_FIELD_TYPE, havingValue = CONFIG_VALUE_DECENTRAL) public EdcSubmodelClient edcSubmodelClient(final EdcConfiguration edcConfiguration, final ContractNegotiationService contractNegotiationService, final EdcDataPlaneClient edcDataPlaneClient, - final EndpointDataReferenceStorage endpointDataReferenceStorage, final AsyncPollingService pollingService, - final RetryRegistry retryRegistry, final EDCCatalogFacade catalogFacade, + final AsyncPollingService pollingService, final RetryRegistry retryRegistry, + final EDCCatalogFacade catalogFacade, final EndpointDataReferenceCacheService endpointDataReferenceCacheService) { + return new EdcSubmodelClientImpl(edcConfiguration, contractNegotiationService, edcDataPlaneClient, - endpointDataReferenceStorage, pollingService, retryRegistry, catalogFacade, - endpointDataReferenceCacheService); + pollingService, retryRegistry, catalogFacade, endpointDataReferenceCacheService); } @Bean From db6b13a7566f0e5ad30bf5503ceaa0c25598a750 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Mon, 19 Feb 2024 17:08:28 +0100 Subject: [PATCH 40/51] feat(impl):[#395] Inline short method --- .../EndpointDataReferenceCacheService.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java index a1d91211f8..4fefed5726 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/cache/endpointdatareference/EndpointDataReferenceCacheService.java @@ -56,8 +56,9 @@ public class EndpointDataReferenceCacheService { * describing token status */ public EndpointDataReferenceStatus getEndpointDataReference(final String assetId) { - final Optional endpointDataReferenceOptional = retrieveEndpointReferenceByAssetId( - assetId); + + log.info("Retrieving dataReference from storage for assetId {}", assetId); + final Optional endpointDataReferenceOptional = endpointDataReferenceStorage.get(assetId); if (endpointDataReferenceOptional.isPresent()) { final String authCode = endpointDataReferenceOptional.get().getAuthCode(); @@ -90,11 +91,6 @@ public void putEndpointDataReferenceIntoStorage(final String assetId, endpointDataReferenceStorage.put(assetId, endpointDataReference); } - private Optional retrieveEndpointReferenceByAssetId(final String assetId) { - log.info("Retrieving dataReference from storage for assetId {}", assetId); - return endpointDataReferenceStorage.get(assetId); - } - private static boolean isTokenExpired(final @NotNull String authCode) { final Instant tokenExpirationInstant = extractTokenExpiration(authCode); return Instant.now().isAfter(tokenExpirationInstant); From 880a0533cb161491ff76f99d73f99d1f18fd08bb Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 20 Feb 2024 00:15:23 +0100 Subject: [PATCH 41/51] feat(impl):[#395] Cleanup --- ...covery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml index 491c13e89b..c0d6659f8c 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--multiple-EDCs-with-multiple-DTRs--detailed.puml @@ -105,7 +105,4 @@ par end end -' TODO(mfischer): #395: how do we visualize the following behaviour in the diagram?: -' fastest successful response from DTR will be returned - @enduml From 9f88251da7be939f8982db4ab5edd403934c42d4 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 20 Feb 2024 00:18:28 +0100 Subject: [PATCH 42/51] feat(impl):[#395] Cleanup --- .../irs/testing/wiremock/SubmodelFacadeWiremockSupport.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java b/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java index cd38948422..10fe132070 100644 --- a/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java +++ b/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java @@ -56,14 +56,14 @@ private SubmodelFacadeWiremockSupport() { public static String prepareNegotiation() { final String contractAgreementId = "7681f966-36ea-4542-b5ea-0d0db81967de:5a7ab616-989f-46ae-bdf2-32027b9f6ee6-31b614f5-ec14-4ed2-a509-e7b7780083e7:a6144a2e-c1b1-4ec6-96e1-a221da134e4f"; prepareNegotiation("1bbaec6e-c316-4e1e-8258-c07a648cc43c", "1b21e963-0bc5-422a-b30d-fd3511861d88", - contractAgreementId, - "5a7ab616-989f-46ae-bdf2-32027b9f6ee6-31b614f5-ec14-4ed2-a509-e7b7780083e7"); + contractAgreementId, "5a7ab616-989f-46ae-bdf2-32027b9f6ee6-31b614f5-ec14-4ed2-a509-e7b7780083e7"); return contractAgreementId; } @SuppressWarnings("PMD.UseObjectForClearerAPI") // used only for testing public static void prepareNegotiation(final String negotiationId, final String transferProcessId, final String contractAgreementId, final String edcAssetId) { + stubFor(post(urlPathEqualTo(PATH_CATALOG)).willReturn(WireMockConfig.responseWithStatus(STATUS_CODE_OK) .withBody(getCatalogResponse(edcAssetId, "USE", EDC_PROVIDER_BPN)))); From 5fdbd0b8eb787fbe9f49996d46e264313eb4fabb Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 23 Feb 2024 19:29:46 +0100 Subject: [PATCH 43/51] feat(impl):[#395] fix test setup --- .../irs/edc/client/EdcSubmodelClientTest.java | 48 +++++++++++-------- .../client/SubmodelFacadeWiremockTest.java | 12 +++-- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index ad24a70cdf..d1c282fa63 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -92,8 +93,6 @@ class EdcSubmodelClientTest extends LocalTestDataConfigurationAware { private final static String CONNECTOR_ENDPOINT = "https://connector.endpoint.com"; private final static String SUBMODEL_SUFIX = "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel"; - private final EndpointDataReferenceStorage endpointDataReferenceStorage = new EndpointDataReferenceStorage( - Duration.ofMinutes(1)); private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); private final TimeMachine clock = new TimeMachine(); private final AsyncPollingService pollingService = new AsyncPollingService(clock, scheduler); @@ -133,13 +132,15 @@ void setUp() { @Test void shouldRetrieveValidRelationship() throws Exception { // arrange + final String agreementId = "agreementId"; when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); when(contractNegotiationService.negotiate(any(), any(), eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( - NegotiationResponse.builder().contractAgreementId("agreementId").build()); - final EndpointDataReference ref = TestMother.endpointDataReference("agreementId"); - endpointDataReferenceStorage.put("agreementId", ref); + NegotiationResponse.builder().contractAgreementId(agreementId).build()); + final EndpointDataReference ref = TestMother.endpointDataReference(agreementId); + when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( + Optional.ofNullable(ref)); final String singleLevelBomAsBuiltJson = readSingleLevelBomAsBuiltData(); when(edcDataPlaneClient.getData(eq(ref), any())).thenReturn(singleLevelBomAsBuiltJson); when(endpointDataReferenceCacheService.getEndpointDataReference("assetId")).thenReturn( @@ -156,13 +157,15 @@ void shouldRetrieveValidRelationship() throws Exception { @Test void shouldSendNotificationSuccessfully() throws Exception { // arrange + final String agreementId = "agreementId"; final EdcNotification notification = EdcNotification.builder().build(); when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); when(contractNegotiationService.negotiate(any(), any(), any())).thenReturn( - NegotiationResponse.builder().contractAgreementId("agreementId").build()); + NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference ref = mock(EndpointDataReference.class); - endpointDataReferenceStorage.put("agreementId", ref); + when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( + Optional.ofNullable(ref)); when(edcDataPlaneClient.sendData(ref, notification)).thenReturn(() -> true); when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn( new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); @@ -350,7 +353,8 @@ void shouldRetrieveEndpointReferenceForAsset() throws Exception { eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference expected = mock(EndpointDataReference.class); - endpointDataReferenceStorage.put(agreementId, expected); + when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( + Optional.ofNullable(expected)); // act final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue, @@ -373,7 +377,8 @@ void shouldRetrieveEndpointReferenceForAsset2() throws Exception { eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference expected = mock(EndpointDataReference.class); - endpointDataReferenceStorage.put(agreementId, expected); + when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( + Optional.ofNullable(expected)); // act final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue); @@ -403,33 +408,38 @@ void shouldUseCachedEndpointReferenceValueWhenTokenIsValid() @Test void shouldCreateCacheRecordWhenTokenIsNotValid() throws EdcClientException { - // given + // arrange + final String agreementId = "agreementId"; when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); when(contractNegotiationService.negotiate(any(), any(), eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( - NegotiationResponse.builder().contractAgreementId("agreementId").build()); + NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference ref = mock(EndpointDataReference.class); - endpointDataReferenceStorage.put("agreementId", ref); + when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( + Optional.ofNullable(ref)); when(endpointDataReferenceCacheService.getEndpointDataReference(any())).thenReturn( new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); - // when + // act testee.getSubmodelPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); - // then - final Optional referenceFromStorage = endpointDataReferenceStorage.get("assetId"); - assertThat(referenceFromStorage).isPresent(); + // assert + verify(endpointDataReferenceCacheService, times(1)).putEndpointDataReferenceIntoStorage("assetId", ref); } private void prepareTestdata(final String catenaXId, final String submodelDataSuffix) throws ContractNegotiationException, IOException, UsagePolicyException, TransferProcessException { + final String agreementId = "agreementId"; when(contractNegotiationService.negotiate(any(), any(), eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( - NegotiationResponse.builder().contractAgreementId("agreementId").build()); - final EndpointDataReference ref = TestMother.endpointDataReference("agreementId"); - endpointDataReferenceStorage.put("agreementId", ref); + NegotiationResponse.builder().contractAgreementId(agreementId).build()); + + final EndpointDataReference ref = TestMother.endpointDataReference(agreementId); + when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( + Optional.ofNullable(ref)); + final SubmodelTestdataCreator submodelTestdataCreator = new SubmodelTestdataCreator( localTestDataConfiguration.cxTestDataContainer()); final String data = StringMapper.mapToString( diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java index c61a44b162..23510866e6 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java @@ -81,20 +81,24 @@ @WireMockTest class SubmodelFacadeWiremockTest { + private static final String PROXY_SERVER_HOST = "127.0.0.1"; private final static String CONNECTOR_ENDPOINT_URL = "https://connector.endpoint.com"; private final static String SUBMODEL_DATAPLANE_PATH = "/api/public/shells/12345/submodels/5678/submodel"; private final static String SUBMODEL_DATAPLANE_URL = "http://dataplane.test" + SUBMODEL_DATAPLANE_PATH; private final static String ASSET_ID = "12345"; - private final EdcConfiguration config = new EdcConfiguration(); - private final EndpointDataReferenceStorage storage = new EndpointDataReferenceStorage(Duration.ofMinutes(1)); + + private EndpointDataReferenceStorage storage; + private EdcSubmodelClient edcSubmodelClient; private AcceptedPoliciesProvider acceptedPoliciesProvider; @BeforeEach void configureSystemUnderTest(WireMockRuntimeInfo wireMockRuntimeInfo) { + final RestTemplate restTemplate = restTemplateProxy(PROXY_SERVER_HOST, wireMockRuntimeInfo.getHttpPort()); + final EdcConfiguration config = new EdcConfiguration(); config.getControlplane().getEndpoint().setData("http://controlplane.test"); config.getControlplane().getEndpoint().setCatalog("/catalog/request"); config.getControlplane().getEndpoint().setContractNegotiation("/contractnegotiations"); @@ -121,8 +125,10 @@ void configureSystemUnderTest(WireMockRuntimeInfo wireMockRuntimeInfo) { final EdcDataPlaneClient dataPlaneClient = new EdcDataPlaneClient(restTemplate); final EDCCatalogFacade catalogFacade = new EDCCatalogFacade(controlPlaneClient, config); + + storage = new EndpointDataReferenceStorage(Duration.ofMinutes(1)); final EndpointDataReferenceCacheService endpointDataReferenceCacheService = new EndpointDataReferenceCacheService( - new EndpointDataReferenceStorage(Duration.ofMinutes(1))); + storage); acceptedPoliciesProvider = mock(AcceptedPoliciesProvider.class); when(acceptedPoliciesProvider.getAcceptedPolicies()).thenReturn(List.of(new AcceptedPolicy(policy("IRS Policy", From 9a435fec32d1aa7f953d598493b4ce14812a54b9 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 23 Feb 2024 20:05:43 +0100 Subject: [PATCH 44/51] feat(impl):[#395] ignore PMD warning Already removed dependency to EndpointDataReferenceStorage in previous commits. In order to reduce more imports more refactoring would be required which is far beyond the scope of the current story. --- .../tractusx/irs/edc/client/EdcSubmodelClientImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java index 44c5fef93c..c5560a4d15 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java @@ -63,7 +63,9 @@ */ @Slf4j @RequiredArgsConstructor -@SuppressWarnings("PMD.TooManyMethods") +@SuppressWarnings({ "PMD.TooManyMethods", + "PMD.ExcessiveImports" +}) public class EdcSubmodelClientImpl implements EdcSubmodelClient { private final EdcConfiguration config; From 031e3d418e20911fd216cfce7cabf27b462703af Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 23 Feb 2024 21:08:49 +0100 Subject: [PATCH 45/51] feat(impl):[#395] Changelog updated --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 671abfac4a..f31bea02b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - DigitalTwinRegistryCreateShellService in irs-registry-client for creating shells in DTR directly +### Changed +- EDC client handles multiple DTRs and DTs now + ## [4.6.0] - 2024-02-20 ### Added From 46eeeef64b82db1e0171a075f59921d1b3934055 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 27 Feb 2024 23:42:42 +0100 Subject: [PATCH 46/51] feat(impl):[#395] Remove .cache_ggshield this file had been committed accidently --- .cache_ggshield | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .cache_ggshield diff --git a/.cache_ggshield b/.cache_ggshield deleted file mode 100644 index 422a0a9f81..0000000000 --- a/.cache_ggshield +++ /dev/null @@ -1 +0,0 @@ -{"last_found_secrets": [{"match": "ef452ab38b8bc9b84b6535c86a97c267d477b37f81c7421bcdf92e591a24eb33", "name": "Generic High Entropy Secret - commit://staged/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java"}]} \ No newline at end of file From 06460860e6ec446a7544671713c25f0bff706b96 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 27 Feb 2024 23:52:46 +0100 Subject: [PATCH 47/51] feat(impl):[#395] Remove obsolete SuppressWarnings --- .../org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java index 9a1f747142..16040d640e 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java @@ -82,8 +82,7 @@ public EdcNotificationResponse sendNotification(final String submodelEndpointAdd throw new EdcClientException(cause); } } - - @SuppressWarnings("PMD.PreserveStackTrace") + public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue) throws EdcClientException { return client.getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue); From fc4275193baf73c0b03d09376f4fab32d28c0850 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Tue, 27 Feb 2024 23:56:51 +0100 Subject: [PATCH 48/51] feat(impl):[#395] Remove obsolete TODOs --- .../discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml index 6bbf506d3e..353e2db879 100644 --- a/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml +++ b/docs/src/docs/arc42/cross-cutting/discovery-DTR--one-EDC-with-multiple-DTRs--detailed.puml @@ -23,7 +23,6 @@ DiscoveryService -> DTRS: Return list of 1 EDC DTRS -> EdcClient: Get EDR Token for asset EdcClient ->> EDCProvider: Query for DTR contract offer EDCProvider -> EdcClient: 2 DTR contract offers -' TODO (mfischer) #395: Contract offer = CatalogItem? par group Query DTR 1 @@ -43,7 +42,6 @@ par EdcClient -> EDCProvider: Negotiate contract EDCProvider -> EdcClient: EDR Token callback EdcClient -> DTRS: EDR token - ' TODO (mfischer) #395: EDR token = EndpointDataReference? == EDC Data Plane == From 17cea3de81c7ddbdff6644f1c8a2ac7aa23818e4 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Wed, 28 Feb 2024 00:20:52 +0100 Subject: [PATCH 49/51] feat(impl):[#395] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af9226fee2..1d825f5843 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - DigitalTwinRegistryCreateShellService in irs-registry-client for creating shells in DTR directly ### Changed -- EDC client handles multiple DTRs and DTs now +- EDC client handles multiple Digital Twin Registries and Digital Twins now - Change logo of irs ## [4.6.0] - 2024-02-20 From 18a62390697553ac8c07938111a3526a3967fb70 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 1 Mar 2024 14:49:12 +0100 Subject: [PATCH 50/51] feature(impl):[#395] Corrected / improved test according to review session --- ...igitalTwinRegistryServiceWiremockTest.java | 87 ++++++++++++++++--- 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java index 019b2c8cba..31418299ee 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java @@ -48,15 +48,18 @@ import static org.eclipse.tractusx.irs.testing.wiremock.DtrWiremockSupport.getShellDescriptor404; import static org.eclipse.tractusx.irs.testing.wiremock.WireMockConfig.restTemplateProxy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; @@ -64,6 +67,7 @@ import org.eclipse.tractusx.irs.component.Shell; import org.eclipse.tractusx.irs.data.StringMapper; import org.eclipse.tractusx.irs.edc.client.configuration.JsonLdConfiguration; +import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; import org.eclipse.tractusx.irs.edc.client.model.EDRAuthCode; import org.eclipse.tractusx.irs.registryclient.DigitalTwinRegistryKey; import org.eclipse.tractusx.irs.registryclient.discovery.ConnectorEndpointsService; @@ -73,12 +77,18 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; import org.springframework.web.client.RestTemplate; @WireMockTest class DecentralDigitalTwinRegistryServiceWiremockTest { private static final String PROXY_SERVER_HOST = "127.0.0.1"; - private final EdcEndpointReferenceRetriever edcSubmodelFacadeMock = mock(EdcEndpointReferenceRetriever.class); + private final EdcEndpointReferenceRetriever edcEndpointReferenceRetrieverMock = mock( + EdcEndpointReferenceRetriever.class); private DecentralDigitalTwinRegistryService decentralDigitalTwinRegistryService; @BeforeEach @@ -87,7 +97,8 @@ void setUp(WireMockRuntimeInfo wireMockRuntimeInfo) { final var discoveryFinderClient = new DiscoveryFinderClientImpl(DISCOVERY_FINDER_URL, restTemplate); final var connectorEndpointsService = new ConnectorEndpointsService(discoveryFinderClient); - final var endpointDataForConnectorsService = new EndpointDataForConnectorsService(edcSubmodelFacadeMock); + final var endpointDataForConnectorsService = new EndpointDataForConnectorsService( + edcEndpointReferenceRetrieverMock); final var decentralDigitalTwinRegistryClient = new DecentralDigitalTwinRegistryClient(restTemplate, SHELL_DESCRIPTORS_TEMPLATE, LOOKUP_SHELLS_TEMPLATE); decentralDigitalTwinRegistryService = new DecentralDigitalTwinRegistryService(connectorEndpointsService, @@ -105,7 +116,7 @@ void shouldDiscoverEDCAndRequestRegistry() throws RegistryServiceException, EdcR givenThat(getShellDescriptor200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); // Act @@ -154,7 +165,7 @@ void shouldThrowInCaseOfLookupShellsError() throws EdcRetrieverException { givenThat(postEdcDiscovery200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); givenThat(getLookupShells404()); @@ -175,7 +186,7 @@ void shouldThrowInCaseOfShellDescriptorsError() throws EdcRetrieverException { givenThat(postEdcDiscovery200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); givenThat(getLookupShells200()); @@ -198,7 +209,7 @@ void shouldThrowExceptionOnEmptyShells() throws EdcRetrieverException { givenThat(postEdcDiscovery200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); givenThat(getLookupShells200Empty()); @@ -228,10 +239,10 @@ void lookupShellIdentifiers_oneEDC_oneDTR() throws RegistryServiceException, Edc // simulate endpoint data reference final var endpointDataReference = endpointDataReference("assetId"); - when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); - // Act & Assert + // Act final Collection digitalTwinRegistryKeys = decentralDigitalTwinRegistryService.lookupShellIdentifiers( TEST_BPN); @@ -244,18 +255,69 @@ void lookupShellIdentifiers_oneEDC_oneDTR() throws RegistryServiceException, Edc verify(exactly(edcUrls.size()), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); } - @Test - void lookupShellIdentifiers_multipleEDCs_oneDTR() throws RegistryServiceException, EdcRetrieverException { + @ParameterizedTest(name = "{0}") + @ArgumentsSource(NoOrFailedEndpointDataReferenceProvider.class) + void lookupShellIdentifiers_multipleEDCs_oneDTR(String title, + List> endpointDataReferenceForAssetFutures) + throws RegistryServiceException, EdcRetrieverException { // Arrange givenThat(postDiscoveryFinder200()); - final List edcUrls = List.of("https://test.edc1.io", "https://test.edc2.io"); + final String edc1Url = "https://test.edc1.io"; + final String edc2Url = "https://test.edc2.io"; + final List edcUrls = List.of(edc1Url, edc2Url); givenThat(postEdcDiscovery200(TEST_BPN, edcUrls)); givenThat(getLookupShells200()); // simulate endpoint data reference final var endpointDataReference = endpointDataReference("assetId"); - when(edcSubmodelFacadeMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc1Url), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc2Url), any(), any())).thenReturn( + endpointDataReferenceForAssetFutures); + + // Act + final Collection digitalTwinRegistryKeys = decentralDigitalTwinRegistryService.lookupShellIdentifiers( + TEST_BPN); + + // Assert + assertThat(digitalTwinRegistryKeys).hasSize(1); + assertThat(digitalTwinRegistryKeys.stream().findFirst().get().shellId()).isEqualTo( + "urn:uuid:21f7ebea-fa8a-410c-a656-bd9082e67dcf"); + verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); + verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + // because just one DTR + verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); + } + + public static class NoOrFailedEndpointDataReferenceProvider implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext extensionContext) { + return Stream.of( + // failed future + Arguments.of("given failed future", List.of(CompletableFuture.failedFuture( + new EdcRetrieverException(new EdcClientException(new RuntimeException("test")))))), + // no result + Arguments.of("given no result", Collections.emptyList())); + } + } + + @Test + void lookupShellIdentifiers_multipleEDCs_multipleDTRs() throws RegistryServiceException, EdcRetrieverException { + // Arrange + givenThat(postDiscoveryFinder200()); + final String edc1Url = "https://test.edc1.io"; + final String edc2Url = "https://test.edc2.io"; + final List edcUrls = List.of(edc1Url, edc2Url); + givenThat(postEdcDiscovery200(TEST_BPN, edcUrls)); + givenThat(getLookupShells200()); + + // simulate endpoint data reference + final var endpointDataReference1 = endpointDataReference("dtr1-assetId"); + final var endpointDataReference2 = endpointDataReference("dtr2-assetId"); + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc1Url), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference1))); + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc2Url), any(), any())).thenReturn( + List.of(CompletableFuture.completedFuture(endpointDataReference2))); // Act & Assert final Collection digitalTwinRegistryKeys = decentralDigitalTwinRegistryService.lookupShellIdentifiers( @@ -267,6 +329,7 @@ void lookupShellIdentifiers_multipleEDCs_oneDTR() throws RegistryServiceExceptio "urn:uuid:21f7ebea-fa8a-410c-a656-bd9082e67dcf"); verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); + // multiple DTR (one per EDC) verify(exactly(edcUrls.size()), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); } } From bf8263b45d1f462b113efbbfedbc1e92d9bfe888 Mon Sep 17 00:00:00 2001 From: Matthias Fischer Date: Fri, 1 Mar 2024 15:38:16 +0100 Subject: [PATCH 51/51] feat(impl):[#395] Add GitHub issue number to CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6208310b25..33ec8a983e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - POST /management/v2/contractagreements/request and GET /management/v2/contractagreements/{contractAgreementId}/negotiation to irs-edc-client lib ### Changed -- EDC client handles multiple Digital Twin Registries and Digital Twins now +- EDC client handles multiple Digital Twin Registries and Digital Twins now #395 - Change logo of irs - Added 'businessPartnerNumber' field to Tombstone model. This will be filled only when UsagePolicyValidation tombstone is being created.