diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/GetTransferProcessAssetApiServiceTest.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/GetTransferProcessAssetApiServiceTest.java new file mode 100644 index 000000000..316c2508e --- /dev/null +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/GetTransferProcessAssetApiServiceTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.client; + +import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.spi.asset.AssetService; +import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.junit.extensions.EdcExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.text.ParseException; +import java.util.Map; + +import static de.sovity.edc.client.TransferProcessTestUtils.createConsumingTransferProcesses; +import static de.sovity.edc.client.TransferProcessTestUtils.createProvidingTransferProcesses; +import static org.assertj.core.api.Assertions.assertThat; + +@ApiTest +@ExtendWith(EdcExtension.class) +class GetTransferProcessAssetApiServiceTest { + + @BeforeEach + void setUp(EdcExtension extension) { + extension.setConfiguration(TestUtils.createConfiguration(Map.of())); + } + + @Test + void testProviderTransferProcess(ContractNegotiationStore negotiationStore, + TransferProcessStore transferProcessStore, + AssetService assetStore) throws ParseException { + + var client = TestUtils.edcClient(); + + //arrange data + createProvidingTransferProcesses(negotiationStore, transferProcessStore, assetStore); + + //act + var providerAssetResult = client.uiApi().getTransferProcessAsset(TransferProcessTestUtils.PROVIDING_TRANSFER_PROCESS_ID); + + //assert + assertThat(providerAssetResult.getAssetId()).isEqualTo(TransferProcessTestUtils.VALID_ASSET_ID); + assertThat(providerAssetResult.getProperties().get("asset:prop:name")).isEqualTo(TransferProcessTestUtils.ASSET_NAME); + } + + @Test + void testConsumerTransferProcess(ContractNegotiationStore negotiationStore, + TransferProcessStore transferProcessStore) throws ParseException { + + var client = TestUtils.edcClient(); + + //arrange data + createConsumingTransferProcesses(negotiationStore, transferProcessStore); + + //act + var consumerAssetResult = client.uiApi().getTransferProcessAsset(TransferProcessTestUtils.CONSUMING_TRANSFER_PROCESS_ID); + + //assert + assertThat(consumerAssetResult.getAssetId()).isEqualTo(TransferProcessTestUtils.UNKNOWN_ASSET_ID); + assertThat(consumerAssetResult.getProperties().get("asset:prop:name")).isNull(); + } + +} diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferHistoryPageApiServiceTest.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferHistoryPageApiServiceTest.java new file mode 100644 index 000000000..fc846e7d0 --- /dev/null +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferHistoryPageApiServiceTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.client; + +import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.spi.asset.AssetService; +import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.junit.extensions.EdcExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.text.ParseException; +import java.util.Map; + +import static de.sovity.edc.client.TransferProcessTestUtils.createConsumingTransferProcesses; +import static de.sovity.edc.client.TransferProcessTestUtils.createProvidingTransferProcesses; +import static de.sovity.edc.client.gen.model.TransferHistoryEntry.DirectionEnum.CONSUMING; +import static de.sovity.edc.client.gen.model.TransferHistoryEntry.DirectionEnum.PROVIDING; +import static org.assertj.core.api.Assertions.assertThat; + +@ApiTest +@ExtendWith(EdcExtension.class) +class TransferHistoryPageApiServiceTest { + + @BeforeEach + void setUp(EdcExtension extension) { + extension.setConfiguration(TestUtils.createConfiguration(Map.of())); + } + + @Test + void startTransferProcessForAgreement( + ContractNegotiationStore negotiationStore, + TransferProcessStore transferProcessStore, + AssetService assetStore + ) throws ParseException { + var client = TestUtils.edcClient(); + + // arrange + createProvidingTransferProcesses(negotiationStore, transferProcessStore, assetStore); + createConsumingTransferProcesses(negotiationStore, transferProcessStore); + + // act + var result = client.uiApi().transferHistoryPageEndpoint(); + + // get + var transferProcess = result.getTransferEntries(); + + // assert for the order of entries + assertThat(transferProcess.get(1).getTransferProcessId()).isEqualTo(TransferProcessTestUtils.PROVIDING_TRANSFER_PROCESS_ID); + + // assert for consuming request entry + var consumingProcess = transferProcess.get(0); + assertThat(consumingProcess.getTransferProcessId()).isEqualTo(TransferProcessTestUtils.CONSUMING_TRANSFER_PROCESS_ID); + assertThat(consumingProcess.getAssetId()).isEqualTo(TransferProcessTestUtils.UNKNOWN_ASSET_ID); + assertThat(consumingProcess.getCounterPartyConnectorEndpoint()).isEqualTo(TransferProcessTestUtils.COUNTER_PARTY_ADDRESS); + assertThat(consumingProcess.getContractAgreementId()).isEqualTo(TransferProcessTestUtils.CONSUMING_CONTRACT_ID); + assertThat(consumingProcess.getDirection()).isEqualTo(CONSUMING); + assertThat(consumingProcess.getState().getCode()).isEqualTo(800); + assertThat(consumingProcess.getAssetName()).isEqualTo(TransferProcessTestUtils.UNKNOWN_ASSET_ID); + assertThat(consumingProcess.getErrorMessage()).isEqualTo(""); + + // assert for providing request entry + var providingProcess = transferProcess.get(1); + assertThat(providingProcess.getTransferProcessId()).isEqualTo(TransferProcessTestUtils.PROVIDING_TRANSFER_PROCESS_ID); + assertThat(providingProcess.getAssetId()).isEqualTo(TransferProcessTestUtils.VALID_ASSET_ID); + assertThat(providingProcess.getCounterPartyConnectorEndpoint()).isEqualTo(TransferProcessTestUtils.COUNTER_PARTY_ADDRESS); + assertThat(providingProcess.getContractAgreementId()).isEqualTo(TransferProcessTestUtils.PROVIDING_CONTRACT_ID); + assertThat(providingProcess.getDirection()).isEqualTo(PROVIDING); + assertThat(providingProcess.getState().getCode()).isEqualTo(800); + assertThat(providingProcess.getAssetName()).isEqualTo(TransferProcessTestUtils.ASSET_NAME); + assertThat(providingProcess.getErrorMessage()).isEqualTo("TransferProcessManager: attempt #8 failed to send transfer"); + } +} diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferProcessTestUtils.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferProcessTestUtils.java new file mode 100644 index 000000000..4f64c790d --- /dev/null +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferProcessTestUtils.java @@ -0,0 +1,142 @@ +package de.sovity.edc.client; + +import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.spi.asset.AssetService; +import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.connector.transfer.spi.types.DataRequest; +import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.types.domain.DataAddress; +import org.eclipse.edc.spi.types.domain.asset.Asset; +import org.jetbrains.annotations.NotNull; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.UUID; + +public class TransferProcessTestUtils { + public static final String DATA_SINK = "http://my-data-sink/api/stuff"; + public static final String COUNTER_PARTY_ADDRESS = "http://some-other-connector/api/v1/ids/data"; + public static final String PROVIDING_CONTRACT_ID = "provider-contract:eb934d1f-6582-4bab-85e6-af19a76f7e2b"; + public static final String CONSUMING_CONTRACT_ID = "consumer-contract:f52a5d30-6356-4a55-a75a-3c45d7a88c3e"; + public static final String VALID_ASSET_ID = "urn:artifact:asset"; + public static final String UNKNOWN_ASSET_ID = "urn:junk"; + public static final String ASSET_NAME = "Test asset"; + public static final String PROVIDING_TRANSFER_PROCESS_ID = "81cdf4cf-8427-480f-9662-8a29d66ddd3b"; + public static final String CONSUMING_TRANSFER_PROCESS_ID = "be0cac12-bb43-420e-aa29-d66bb3d0e0ac"; + + @NotNull + public static void createProvidingTransferProcesses(ContractNegotiationStore store, TransferProcessStore transferProcessStore, AssetService assetStore) throws ParseException { + DataAddress dataAddress = getDataAddress(); + createAsset(assetStore, dataAddress, VALID_ASSET_ID, ASSET_NAME); + + // preparing providing transfer process + var providerAgreement = createContractAgreement(PROVIDING_CONTRACT_ID, VALID_ASSET_ID); + createContractNegotiation(store, COUNTER_PARTY_ADDRESS, providerAgreement, ContractNegotiation.Type.PROVIDER); + createTransferProcess(VALID_ASSET_ID, + PROVIDING_CONTRACT_ID, + dataAddress, + TransferProcess.Type.PROVIDER, + PROVIDING_TRANSFER_PROCESS_ID, + "2023-07-08", + "TransferProcessManager: attempt #8 failed to send transfer", + transferProcessStore); + } + + @NotNull + public static void createConsumingTransferProcesses(ContractNegotiationStore store, TransferProcessStore transferProcessStore) throws ParseException { + DataAddress dataAddress = getDataAddress(); + + // preparing consuming transfer process + var consumerAgreement = createContractAgreement(CONSUMING_CONTRACT_ID, UNKNOWN_ASSET_ID); + createContractNegotiation(store, COUNTER_PARTY_ADDRESS, consumerAgreement, ContractNegotiation.Type.CONSUMER); + createTransferProcess(UNKNOWN_ASSET_ID, + CONSUMING_CONTRACT_ID, + dataAddress, + TransferProcess.Type.CONSUMER, + CONSUMING_TRANSFER_PROCESS_ID, + "2023-07-10", + "", + transferProcessStore); + } + + private static DataAddress getDataAddress() { + var dataAddress = DataAddress.Builder.newInstance() + .type("HttpData") + .property("baseUrl", DATA_SINK) + .build(); + return dataAddress; + } + + private static void createAsset(AssetService assetStore, DataAddress dataAddress, String assetId, String assetName) throws ParseException { + var asset = Asset.Builder.newInstance() + .id(assetId) + .property("asset:prop:name", assetName) + .createdAt(dateFormatterToLong("2023-06-01")) + .build(); + + assetStore.create(asset, dataAddress); + } + + private static ContractAgreement createContractAgreement( + String agreementId, + String assetId + ) { + var agreement = ContractAgreement.Builder.newInstance() + .id(agreementId) + .providerAgentId(UUID.randomUUID().toString()) + .consumerAgentId(UUID.randomUUID().toString()) + .assetId(assetId) + .policy(Policy.Builder.newInstance().build()) + .build(); + + return agreement; + } + + private static void createContractNegotiation( + ContractNegotiationStore store, + String counterPartyAddress, + ContractAgreement agreement, + ContractNegotiation.Type type + ) { + var negotiation = ContractNegotiation.Builder.newInstance() + .id(UUID.randomUUID().toString()) + .counterPartyId(UUID.randomUUID().toString()) + .counterPartyAddress(counterPartyAddress) + .protocol("protocol") + .contractAgreement(agreement) + .type(type) + .correlationId(UUID.randomUUID().toString()) + .build(); + + store.save(negotiation); + } + + private static void createTransferProcess(String assetId, String contractId, DataAddress dataAddress, TransferProcess.Type type, String transferProcessId, String lastUpdateDateForTransferProcess, String errorMessage, TransferProcessStore transferProcessStore) throws ParseException { + + var dataRequestForTransfer = DataRequest.Builder.newInstance() + .assetId(assetId) + .contractId(contractId) + .dataDestination(dataAddress) + .build(); + + var transferProcess = TransferProcess.Builder.newInstance() + .id(transferProcessId) + .type(type) + .dataRequest(dataRequestForTransfer) + .createdAt(dateFormatterToLong("2023-07-08")) + .updatedAt(dateFormatterToLong(lastUpdateDateForTransferProcess)) + .state(800) + .errorDetail(errorMessage) + .build(); + + transferProcessStore.save(transferProcess); + } + + private static long dateFormatterToLong(String date) throws ParseException { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.parse(date).getTime(); + } +} diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java index 34b237dd5..43b96f7bb 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java @@ -19,6 +19,7 @@ import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; +import org.eclipse.edc.connector.spi.asset.AssetService; import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService; import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; @@ -37,6 +38,8 @@ public class WrapperExtension implements ServiceExtension { @Inject private AssetIndex assetIndex; @Inject + private AssetService assetService; + @Inject private ContractAgreementService contractAgreementService; @Inject private ContractDefinitionStore contractDefinitionStore; @@ -72,6 +75,7 @@ public void initialize(ServiceExtensionContext context) { var wrapperExtensionContext = WrapperExtensionContextBuilder.buildContext( assetIndex, + assetService, contractAgreementService, contractDefinitionStore, contractNegotiationService, diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java index b29f79ec6..c06ee6147 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java @@ -27,6 +27,7 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractNegotiationUtils; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.TransformerRegistryUtils; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageApiService; +import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageAssetFetcherService; import de.sovity.edc.ext.wrapper.api.usecase.UseCaseResource; import de.sovity.edc.ext.wrapper.api.usecase.services.KpiApiService; import de.sovity.edc.ext.wrapper.api.usecase.services.OfferingService; @@ -37,6 +38,7 @@ import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; +import org.eclipse.edc.connector.spi.asset.AssetService; import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService; import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; @@ -61,6 +63,7 @@ public class WrapperExtensionContextBuilder { public static WrapperExtensionContext buildContext( AssetIndex assetIndex, + AssetService assetService, ContractAgreementService contractAgreementService, ContractDefinitionStore contractDefinitionStore, ContractNegotiationService contractNegotiationService, @@ -85,7 +88,9 @@ public static WrapperExtensionContext buildContext( contractAgreementDataFetcher, contractAgreementPageCardBuilder ); - var transferHistoryPageApiService = new TransferHistoryPageApiService(); + var transferHistoryPageApiService = new TransferHistoryPageApiService(assetService, contractAgreementService, contractNegotiationStore, + transferProcessService, transferProcessStateService); + var transferHistoryPageAssetFetcherService = new TransferHistoryPageAssetFetcherService(assetService, transferProcessService); var transformerRegistryUtils = new TransformerRegistryUtils(dtoTransformerRegistry); var contractNegotiationUtils = new ContractNegotiationUtils(contractNegotiationService); var contractAgreementUtils = new ContractAgreementUtils(contractAgreementService); @@ -102,8 +107,9 @@ public static WrapperExtensionContext buildContext( ); var uiResource = new UiResource( contractAgreementApiService, + contractAgreementTransferApiService, transferHistoryPageApiService, - contractAgreementTransferApiService + transferHistoryPageAssetFetcherService ); // Use Case API diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java index e53518c14..f5e8917e9 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java @@ -14,19 +14,17 @@ package de.sovity.edc.ext.wrapper.api.ui; +import de.sovity.edc.ext.wrapper.api.common.model.AssetDto; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementPage; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTransferRequest; import de.sovity.edc.ext.wrapper.api.ui.model.TransferHistoryPage; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.ContractAgreementPageApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.ContractAgreementTransferApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageApiService; +import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageAssetFetcherService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; +import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import lombok.RequiredArgsConstructor; import org.eclipse.edc.api.model.IdResponseDto; @@ -35,9 +33,11 @@ @Tag(name = "UI", description = "EDC UI API Endpoints") @RequiredArgsConstructor public class UiResource { + private final ContractAgreementPageApiService contractAgreementApiService; - private final TransferHistoryPageApiService transferHistoryPageApiService; private final ContractAgreementTransferApiService contractAgreementTransferApiService; + private final TransferHistoryPageApiService transferHistoryPageApiService; + private final TransferHistoryPageAssetFetcherService transferHistoryPageAssetFetcherService; @GET @Path("pages/contract-agreement-page") @@ -64,6 +64,13 @@ public IdResponseDto initiateTransfer( @Path("pages/transfer-history-page") @Produces(MediaType.APPLICATION_JSON) public TransferHistoryPage transferHistoryPageEndpoint() { - return transferHistoryPageApiService.transferHistoryPage(); + return new TransferHistoryPage(transferHistoryPageApiService.getTransferHistoryEntries()); + } + + @GET + @Path("pages/transfer-history-page/transfer-processes/{transferProcessId}/asset") + @Produces(MediaType.APPLICATION_JSON) + public AssetDto getTransferProcessAsset(@PathParam("transferProcessId") String transferProcessId) { + return transferHistoryPageAssetFetcherService.getAssetForTransferHistoryPage(transferProcessId); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/TransferHistoryEntry.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/TransferHistoryEntry.java index c36de171c..4dff40d29 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/TransferHistoryEntry.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/TransferHistoryEntry.java @@ -16,7 +16,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; - import java.time.OffsetDateTime; @Data diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java index 4a8aeb72a..c8ee1a147 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java @@ -14,14 +14,112 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; -import de.sovity.edc.ext.wrapper.api.ui.model.TransferHistoryPage; +import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementDirection; +import de.sovity.edc.ext.wrapper.api.ui.model.TransferHistoryEntry; +import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.TransferProcessStateService; import lombok.RequiredArgsConstructor; +import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.spi.asset.AssetService; +import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; +import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.spi.entity.Entity; +import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.edc.spi.types.domain.asset.Asset; +import org.jetbrains.annotations.NotNull; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import static de.sovity.edc.ext.wrapper.utils.EdcDateUtils.utcMillisToOffsetDateTime; +import static java.util.stream.Collectors.*; @RequiredArgsConstructor public class TransferHistoryPageApiService { - public TransferHistoryPage transferHistoryPage() { - // TODO: Implement - throw new IllegalStateException("Not yet implemented"); + private final AssetService assetService; + private final ContractAgreementService contractAgreementService; + private final ContractNegotiationStore contractNegotiationStore; + private final TransferProcessService transferProcessService; + private final TransferProcessStateService transferProcessStateService; + + /** + * Fetches all Transfer History entries as {@link TransferHistoryEntry}s. + * + * @return {@link TransferHistoryEntry}s + */ + @NotNull + public List getTransferHistoryEntries() { + + var negotiationsById = getAllContractNegotiations().stream() + .filter(negotiation -> negotiation.getContractAgreement() != null) + .collect(groupingBy( + it -> it.getContractAgreement().getId(), + collectingAndThen(maxBy(Comparator.comparing(Entity::getCreatedAt)), Optional::get) + )); + + var agreementsById = getAllContractAgreements().stream().collect(toMap( + ContractAgreement::getId, Function.identity() + )); + + var assetsById = getAllAssets().stream() + .collect(toMap(Asset::getId, Function.identity())); + + var transferStream = getAllTransferProcesses().stream(); + + return transferStream.map(process -> { + var agreement = agreementsById.get(process.getDataRequest().getContractId()); + var negotiation = negotiationsById.get(process.getDataRequest().getContractId()); + var asset = assetLookup(assetsById, process); + var direction = ContractAgreementDirection.fromType(negotiation.getType()); + var transferHistoryEntry = new TransferHistoryEntry(); + transferHistoryEntry.setAssetId(asset.getId()); + if (direction == ContractAgreementDirection.CONSUMING) { + transferHistoryEntry.setAssetName(asset.getId()); + } else { + transferHistoryEntry.setAssetName(asset.getName() == null ? asset.getId() : asset.getName()); + } + transferHistoryEntry.setContractAgreementId(agreement.getId()); + transferHistoryEntry.setCounterPartyConnectorEndpoint(negotiation.getCounterPartyAddress()); + transferHistoryEntry.setCreatedDate(utcMillisToOffsetDateTime(negotiation.getCreatedAt())); + transferHistoryEntry.setDirection(direction); + transferHistoryEntry.setErrorMessage(process.getErrorDetail()); + transferHistoryEntry.setLastUpdatedDate(utcMillisToOffsetDateTime(process.getUpdatedAt())); + transferHistoryEntry.setState(transferProcessStateService.buildTransferProcessState(process.getState())); + transferHistoryEntry.setTransferProcessId(process.getId()); + return transferHistoryEntry; + }).sorted(Comparator.comparing(TransferHistoryEntry::getLastUpdatedDate).reversed()).toList(); + } + + private Asset assetLookup(Map assetsById, TransferProcess process) { + var assetId = process.getDataRequest().getAssetId(); + var asset = assetsById.get(assetId); + if (asset == null) { + return Asset.Builder.newInstance().id(assetId).build(); + } + return asset; + } + + @NotNull + private List getAllContractNegotiations() { + return contractNegotiationStore.queryNegotiations(QuerySpec.max()).toList(); + } + + @NotNull + private List getAllContractAgreements() { + return contractAgreementService.query(QuerySpec.max()).getContent().toList(); + } + + @NotNull + private List getAllTransferProcesses() { + return transferProcessService.query(QuerySpec.max()).getContent().toList(); + } + + @NotNull + private List getAllAssets() { + return assetService.query(QuerySpec.max()).getContent().toList(); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java new file mode 100644 index 000000000..f775b7919 --- /dev/null +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java @@ -0,0 +1,47 @@ +package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; + +import de.sovity.edc.ext.wrapper.api.common.model.AssetDto; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.eclipse.edc.connector.spi.asset.AssetService; +import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.types.domain.asset.Asset; +import org.jetbrains.annotations.NotNull; + +import static de.sovity.edc.ext.wrapper.utils.EdcDateUtils.utcMillisToOffsetDateTime; +import static de.sovity.edc.ext.wrapper.utils.MapUtils.mapValues; + +@RequiredArgsConstructor +public class TransferHistoryPageAssetFetcherService { + private final AssetService assetService; + private final TransferProcessService transferProcessService; + + public AssetDto getAssetForTransferHistoryPage(String transferProcessId) { + + var transferProcessById = transferProcessService.findById(transferProcessId); + if (transferProcessById == null) { + throw new EdcException("Could not find transfer process with ID %s.".formatted(transferProcessId)); + } + return getAssetFromTransferProcess(transferProcessById); + } + + @NotNull + private AssetDto getAssetFromTransferProcess(TransferProcess process) { + var assetId = process.getDataRequest().getAssetId(); + var asset = assetService.findById(process.getDataRequest().getAssetId()); + if (asset == null) { + asset = Asset.Builder.newInstance().id(assetId).build(); + } + return buildAssetDto(asset); + } + + @NotNull + private AssetDto buildAssetDto(@NonNull Asset asset) { + var createdAt = utcMillisToOffsetDateTime(asset.getCreatedAt()); + var properties = mapValues(asset.getProperties(), Object::toString); + return new AssetDto(asset.getId(), createdAt, properties); + } + +}