From b58efa1111a9415d21f0335051a12fbf682188ac Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Tue, 21 May 2024 10:46:06 +0200 Subject: [PATCH 01/10] fix: initial commit --- .../edc/logic/service/EdcAdapterService.java | 87 ++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index d80ff8d5..8f94cd9a 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -178,7 +178,7 @@ public boolean registerAssetsInitially() { * Utility method to register policy- and contract-definitions for both the * REQUEST and the RESPONSE-Api specifically for the given partner. * - * @param partner the partner + * @param partner The partner * @return true, if all registrations ran successfully */ public boolean createPolicyAndContractDefForPartner(Partner partner) { @@ -227,7 +227,7 @@ private boolean createDtrContractDefinitionForPartner(Partner partner) { * 1. The BPNL of the requesting connector is equal to the BPNL of the partner * 2. There's a CX membership credential present * - * @param partner the partner to create the policy for + * @param partner The partner to create the policy for * @return true, if registration ran successfully */ private boolean createBpnlAndMembershipPolicyDefinitionForPartner(Partner partner) { @@ -475,8 +475,8 @@ public Response getAllTransfers() throws IOException { * Sends a request to the own control plane in order to receive * the contract agreement with the given contractAgreementId * - * @param contractAgreementId the contractAgreement's Id - * @return the contractAgreement + * @param contractAgreementId The contractAgreement's Id + * @return The contractAgreement * @throws IOException If the connection to your control plane fails */ public String getContractAgreement(String contractAgreementId) throws IOException { @@ -568,13 +568,6 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp String transferId = transferResp.get("@id").asText(); // try proxy pull and terminate request try { - for (int i = 0; i < 100; i++) { - Thread.sleep(100); - transferResp = getTransferState(transferId); - if ("STARTED".equals(transferResp.get("state").asText())) { - break; - } - } EdrDto edrDto = getAndAwaitEdrDto(transferId); log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); if (edrDto == null) { @@ -610,17 +603,24 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp } /** - * get the EDR via edr api and retry multiple times in case the EDR has not yet been available + * Get the EDR via edr api and retry multiple times in case the EDR has not yet been available * * @param transferProcessId to get the EDR for, not null * @return edr received, or null if not yet available * @throws InterruptedException if thread was not able to sleep */ - private @Nullable EdrDto getAndAwaitEdrDto(String transferProcessId) throws InterruptedException { + private @Nullable EdrDto getAndAwaitEdrDto(String transferProcessId) throws InterruptedException, IOException { + for (int i = 0; i < 100; i++) { + Thread.sleep(100); + JsonNode transferResp = getTransferState(transferProcessId); + if ("STARTED".equals(transferResp.get("state").asText())) { + break; + } + } EdrDto edrDto = null; // retry, if Data Space Protocol / Data Plane Provisioning communication needs time to prepare for (int i = 0; i < 100; i++) { - edrDto = getEdrForTransferProcessId(transferProcessId); + edrDto = getEdrForTransferProcessId(transferProcessId, 2); if (edrDto != null) { break; } @@ -747,7 +747,7 @@ private SubmodelData fetchSubmodelData(MaterialPartnerRelation mpr, String seman } /** - * quries the dtr of a pratner for the given mpr / material and returns submodel descriptors + * Queries the dtr of a partner for the given mpr / material and returns submodel descriptors *

* Method assumes that the query at dtr only finds one shell (else take first entry) * @@ -762,7 +762,11 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man log.error("AasSubmodelDescriptors Request failed for " + manufacturerPartId + " and " + manufacturerId); return null; } - boolean failed = true; + + // A criticalFailure indicates that the connection to the partner's DTR could not be established at all + // or delivers a completely unexpected response. This is assumed to be true at first, and will be set to false + // if a response was received that contains the expected answer or at least an empty result. + boolean criticalFailure = true; Partner partner = mpr.getPartner(); try { var dtrContractData = edcContractMappingService.getDtrAssetAndContractId(partner); @@ -779,13 +783,6 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man var transferResp = initiateProxyPullTransfer(partner, contractId, assetId); String transferId = transferResp.get("@id").asText(); try { - for (int i = 0; i < 100; i++) { - Thread.sleep(100); - transferResp = getTransferState(transferId); - if ("STARTED".equals(transferResp.get("state").asText())) { - break; - } - } EdrDto edrDto = getAndAwaitEdrDto(transferId); if (edrDto == null) { log.error("Failed to obtain EDR data for " + assetId + " with " + partner.getEdcUrl()); @@ -834,7 +831,7 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man var aasJson = objectMapper.readTree(body2String); var submodelDescriptors = aasJson.get("submodelDescriptors"); if (submodelDescriptors != null) { - failed = false; + criticalFailure = false; return submodelDescriptors; } else { log.warn("No SubmodelDescriptors found in DTR shell-descriptors response:\n" + aasJson.toPrettyString()); @@ -844,6 +841,7 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man if (resultArray != null) { if (resultArray.isArray() && resultArray.isEmpty()) { log.warn("Empty Result array received"); + criticalFailure = false; } else { log.warn("Unexpected Response for DTR lookup with query " + query + "\n" + resultArray.toPrettyString()); } @@ -862,7 +860,7 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man log.error("Error in AasSubmodelDescriptor Request for " + mpr + " and manufacturerPartId " + manufacturerPartId, e); return getAasSubmodelDescriptors(manufacturerPartId, manufacturerId, mpr, --retries); } finally { - if (failed) { + if (criticalFailure) { log.warn("Invalidating DTR contract data"); edcContractMappingService.putDtrContractData(partner, null, null); } @@ -879,27 +877,38 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man * @param transferProcessId to get the EDR for * @return unpersisted EdrDto. */ - private EdrDto getEdrForTransferProcessId(String transferProcessId) { - + private EdrDto getEdrForTransferProcessId(String transferProcessId, int retries) { + if (retries < 0) return null; + boolean failed = true; try (Response response = sendGetRequest( List.of("v2", "edrs", transferProcessId, "dataaddress"), Map.of("auto_refresh", "true")) ) { - ObjectNode responseObject = (ObjectNode) objectMapper.readTree(response.body().string()); - - String dataPlaneEndpoint = responseObject.get("endpoint").asText(); - String authToken = responseObject.get("authorization").asText(); - - EdrDto edr = new EdrDto("Authorization", authToken, dataPlaneEndpoint); - log.debug("Requested EDR successfully: {}", edr); - - return edr; - - } catch (IOException e) { + if (response.isSuccessful() && response.body() != null) { + ObjectNode responseObject = (ObjectNode) objectMapper.readTree(response.body().string()); + + String dataPlaneEndpoint = responseObject.get("endpoint").asText(); + String authToken = responseObject.get("authorization").asText(); + if (dataPlaneEndpoint != null && authToken != null) { + EdrDto edr = new EdrDto("Authorization", authToken, dataPlaneEndpoint); + log.debug("Requested EDR successfully: {}", edr); + failed = false; + return edr; + } + } + } catch (Exception e) { log.error("EDR token for transfer process with ID {} could not be obtained", transferProcessId); + } finally { + if (failed && --retries >=0) { + try { + Thread.sleep(100); + } catch (Exception e1){ + log.error("Sleep interrupted", e1); + } + } } + return getEdrForTransferProcessId(transferProcessId, retries); - return null; } /** From 5098efc2bf6f71f94be520cdf38e9a8d3ac0e2a1 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Tue, 21 May 2024 10:59:34 +0200 Subject: [PATCH 02/10] fix: minor edits --- .../common/edc/logic/service/EdcAdapterService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 8f94cd9a..e3d278fe 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -22,7 +22,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.eclipse.tractusx.puris.backend.common.edc.domain.model.SubmodelType; @@ -558,7 +557,7 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp } } if (!partner.getEdcUrl().equals(partnerDspUrl)) { - log.warn("Divering Edc Urls for Partner: " + partner.getBpnl() + " and type " + type); + log.warn("Diverging Edc Urls for Partner: " + partner.getBpnl() + " and type " + type); log.warn("General Partner EdcUrl: " + partner.getEdcUrl()); log.warn("URL from AAS: " + partnerDspUrl); } @@ -885,7 +884,7 @@ private EdrDto getEdrForTransferProcessId(String transferProcessId, int retries) Map.of("auto_refresh", "true")) ) { if (response.isSuccessful() && response.body() != null) { - ObjectNode responseObject = (ObjectNode) objectMapper.readTree(response.body().string()); + JsonNode responseObject = objectMapper.readTree(response.body().string()); String dataPlaneEndpoint = responseObject.get("endpoint").asText(); String authToken = responseObject.get("authorization").asText(); @@ -899,10 +898,10 @@ private EdrDto getEdrForTransferProcessId(String transferProcessId, int retries) } catch (Exception e) { log.error("EDR token for transfer process with ID {} could not be obtained", transferProcessId); } finally { - if (failed && --retries >=0) { + if (failed && --retries >= 0) { try { Thread.sleep(100); - } catch (Exception e1){ + } catch (Exception e1) { log.error("Sleep interrupted", e1); } } From d1ec5c34976f4f11a345229a43410092e3431e4e Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Wed, 22 May 2024 09:08:15 +0200 Subject: [PATCH 03/10] fix: samm mappers now able to return empty responses --- .../adapter/DeliveryInformationSammMapper.java | 9 ++------- .../logic/service/DeliveryRequestApiService.java | 12 ++++++++---- .../ShortTermMaterialDemandSammMapper.java | 8 +------- .../logic/services/DemandRequestApiService.java | 13 +++++++++---- .../adapter/PlannedProductionSammMapper.java | 8 +------- .../service/ProductionRequestApiService.java | 11 +++++++---- .../stock/logic/adapter/ItemStockSammMapper.java | 16 +++++----------- .../service/ItemStockRequestApiService.java | 10 ++++++---- .../logic/adapter/ItemStockSammMapperTest.java | 2 +- 9 files changed, 40 insertions(+), 49 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java index 46629942..60e51a18 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java @@ -53,17 +53,12 @@ public class DeliveryInformationSammMapper { @Autowired private MaterialService materialService; - public DeliveryInformation ownDeliveryToSamm(List deliveryList) { - if (deliveryList == null || deliveryList.isEmpty()) { - log.warn("Can't map empty list"); - return null; - } - Partner partner = deliveryList.get(0).getPartner(); + public DeliveryInformation ownDeliveryToSamm(List deliveryList, Partner partner, Material material) { if (deliveryList.stream().anyMatch(deli -> !deli.getPartner().equals(partner))) { log.warn("Can't map delivery list with different partners"); return null; } - Material material = deliveryList.get(0).getMaterial(); + if (deliveryList.stream().anyMatch(deli -> !deli.getMaterial().equals(material))) { log.warn("Can't map delivery list with different materials"); return null; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java index c4c9b1da..918ed5dc 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java @@ -22,9 +22,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; - -import java.util.Optional; - import org.eclipse.tractusx.puris.backend.common.edc.domain.model.SubmodelType; import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EdcAdapterService; import org.eclipse.tractusx.puris.backend.delivery.logic.adapter.DeliveryInformationSammMapper; @@ -39,6 +36,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Optional; + @Service @Slf4j /** @@ -77,8 +76,13 @@ public DeliveryInformation handleDeliverySubmodelRequest(String bpnl, String mat if (material == null) { material = mpr.getMaterial(); } + if (!mprService.find(material, partner).isPartnerBuysMaterial()) { + // only send an answer if partner is registered as customer + return null; + } + var currentDeliveries = ownDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl())); - return sammMapper.ownDeliveryToSamm(currentDeliveries); + return sammMapper.ownDeliveryToSamm(currentDeliveries, partner, material); } public void doReportedDeliveryRequest(Partner partner, Material material) { diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/adapter/ShortTermMaterialDemandSammMapper.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/adapter/ShortTermMaterialDemandSammMapper.java index 1454aca0..7deea4d8 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/adapter/ShortTermMaterialDemandSammMapper.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/adapter/ShortTermMaterialDemandSammMapper.java @@ -50,13 +50,7 @@ public class ShortTermMaterialDemandSammMapper { @Autowired private MaterialService materialService; - public ShortTermMaterialDemand ownDemandToSamm(List demandList) { - if (demandList == null || demandList.isEmpty()) { - log.warn("Can't map empty list"); - return null; - } - Partner partner = demandList.get(0).getPartner(); - Material material = demandList.get(0).getMaterial(); + public ShortTermMaterialDemand ownDemandToSamm(List demandList,Partner partner, Material material) { if (demandList.stream().anyMatch(dem -> !dem.getPartner().equals(partner))) { log.warn("Can't map demand list with different partners"); return null; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java index 840460b7..a6175e21 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java @@ -22,9 +22,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; - -import java.util.Optional; - import org.eclipse.tractusx.puris.backend.common.edc.domain.model.SubmodelType; import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EdcAdapterService; import org.eclipse.tractusx.puris.backend.demand.logic.adapter.ShortTermMaterialDemandSammMapper; @@ -37,6 +34,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Optional; + @Service @Slf4j /** @@ -69,8 +68,14 @@ public ShortTermMaterialDemand handleDemandSubmodelRequest(String bpnl, String m log.error("Unknown Material"); return null; } + + if (!mprService.find(material,partner).isPartnerSuppliesMaterial()) { + // only send an answer if partner is registered as supplier + return null; + } + var currentDemands = ownDemandService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty()); - return sammMapper.ownDemandToSamm(currentDemands); + return sammMapper.ownDemandToSamm(currentDemands, partner, material); } public void doReportedDemandRequest(Partner partner, Material material) { diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/adapter/PlannedProductionSammMapper.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/adapter/PlannedProductionSammMapper.java index 3d1b8f9d..42e3a5e8 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/adapter/PlannedProductionSammMapper.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/adapter/PlannedProductionSammMapper.java @@ -42,13 +42,7 @@ public class PlannedProductionSammMapper { @Autowired private MaterialPartnerRelationService mprService; - public PlannedProductionOutput ownProductionToSamm(List production) { - if (production == null || production.isEmpty()) { - log.warn("Can't map empty list"); - return null; - } - Partner partner = production.get(0).getPartner(); - Material material = production.get(0).getMaterial(); + public PlannedProductionOutput ownProductionToSamm(List production, Partner partner, Material material) { if (production.stream().anyMatch(prod -> !prod.getPartner().equals(partner))) { log.warn("Can't map production list with different partners"); return null; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java index 4f31b837..3aa173b6 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java @@ -22,9 +22,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; - -import java.util.Optional; - import org.eclipse.tractusx.puris.backend.common.edc.domain.model.SubmodelType; import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EdcAdapterService; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; @@ -38,6 +35,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Optional; + @Service @Slf4j /** @@ -70,8 +69,12 @@ public PlannedProductionOutput handleProductionSubmodelRequest(String bpnl, Stri if (material == null) { return null; } + if (!mprService.find(material, partner).isPartnerBuysMaterial()) { + // only send an answer if partner is registered as customer + return null; + } var currentProduction = ownProductionService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty()); - return sammMapper.ownProductionToSamm(currentProduction); + return sammMapper.ownProductionToSamm(currentProduction, partner, material); } public void doReportedProductionRequest(Partner partner, Material material) { diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapper.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapper.java index 496d7814..d8ea0471 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapper.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapper.java @@ -45,21 +45,15 @@ public class ItemStockSammMapper { @Autowired private MaterialPartnerRelationService mprService; - public ItemStockSamm materialItemStocksToItemStockSamm(List materialItemStocks) { - return listToItemStockSamm(materialItemStocks, DirectionCharacteristic.INBOUND); + public ItemStockSamm materialItemStocksToItemStockSamm(List materialItemStocks, Partner partner, Material material) { + return listToItemStockSamm(materialItemStocks, DirectionCharacteristic.INBOUND, partner, material); } - public ItemStockSamm productItemStocksToItemStockSamm(List productItemStocks) { - return listToItemStockSamm(productItemStocks, DirectionCharacteristic.OUTBOUND); + public ItemStockSamm productItemStocksToItemStockSamm(List productItemStocks, Partner partner, Material material) { + return listToItemStockSamm(productItemStocks, DirectionCharacteristic.OUTBOUND, partner, material); } - private ItemStockSamm listToItemStockSamm(List itemStocks, DirectionCharacteristic directionCharacteristic) { - if (itemStocks == null || itemStocks.isEmpty()) { - log.warn("Can't map empty list"); - return null; - } - Partner partner = itemStocks.get(0).getPartner(); - Material material = itemStocks.get(0).getMaterial(); + private ItemStockSamm listToItemStockSamm(List itemStocks, DirectionCharacteristic directionCharacteristic, Partner partner, Material material) { if (itemStocks.stream().anyMatch(stock -> !stock.getPartner().equals(partner))) { log.warn("Can't map item stock list with different partners"); return null; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java index 95d20f62..33f7f35a 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java @@ -73,9 +73,10 @@ public ItemStockSamm handleItemStockSubmodelRequest(String bpnl, String material // Partner is customer, requesting our ProductItemStocks for him // materialNumber is own CX id: Material material = materialService.findByMaterialNumberCx(materialNumber); - if (material != null) { + if (material != null && mprService.find(material, partner).isPartnerBuysMaterial()) { + // only send an answer if partner is registered as customer var currentStocks = productItemStockService.findByPartnerAndMaterial(partner, material); - return sammMapper.productItemStocksToItemStockSamm(currentStocks); + return sammMapper.productItemStocksToItemStockSamm(currentStocks, partner, material); } return null; } @@ -83,9 +84,10 @@ public ItemStockSamm handleItemStockSubmodelRequest(String bpnl, String material // Partner is supplier, requesting our MaterialItemStocks from him // materialNumber is partner's CX id: Material material = mprService.findByPartnerAndPartnerCXNumber(partner, materialNumber).getMaterial(); - if (material != null) { + if (material != null && mprService.find(material, partner).isPartnerSuppliesMaterial()) { + // only send an answer if partner is registered as supplier var currentStocks = materialItemStockService.findByPartnerAndMaterial(partner, material); - return sammMapper.materialItemStocksToItemStockSamm(currentStocks); + return sammMapper.materialItemStocksToItemStockSamm(currentStocks, partner, material); } // Could not identify partner cx number. I.e. we do not have that partner's // CX id in one of our MaterialPartnerRelation entities. Try to fix this by diff --git a/backend/src/test/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapperTest.java b/backend/src/test/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapperTest.java index a161adad..9ded3672 100644 --- a/backend/src/test/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapperTest.java +++ b/backend/src/test/java/org/eclipse/tractusx/puris/backend/stock/logic/adapter/ItemStockSammMapperTest.java @@ -145,7 +145,7 @@ void map_WhenSingleMaterialItemStock_ReturnsItemStockSamm() { // These should result in two positions // - one WITHOUT orderPositionReference AND two allocatedStocks // - one WITH orderPosition AND one allocatedStocks - ItemStockSamm materialItemStockSamm = itemStockSammMapper.materialItemStocksToItemStockSamm(List.of(materialItemStock)); + ItemStockSamm materialItemStockSamm = itemStockSammMapper.materialItemStocksToItemStockSamm(List.of(materialItemStock), supplierPartner, semiconductorMaterial); // Then assertNotNull(materialItemStockSamm); From 1fac26531efc7ffbe4381c3c2dd75b0e049f7262 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Wed, 22 May 2024 09:13:11 +0200 Subject: [PATCH 04/10] chore: update frontend dependencies --- DEPENDENCIES_FRONTEND | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPENDENCIES_FRONTEND b/DEPENDENCIES_FRONTEND index cc86c023..2969757a 100644 --- a/DEPENDENCIES_FRONTEND +++ b/DEPENDENCIES_FRONTEND @@ -19,7 +19,7 @@ npm/npmjs/-/base64-js/1.5.1, MIT, approved, clearlydefined npm/npmjs/-/binary-extensions/2.2.0, MIT, approved, clearlydefined npm/npmjs/-/brace-expansion/1.1.11, MIT, approved, clearlydefined npm/npmjs/-/brace-expansion/2.0.1, MIT, approved, clearlydefined -npm/npmjs/-/braces/3.0.2, MIT, approved, clearlydefined +npm/npmjs/-/braces/3.0.2, MIT, approved, #14866 npm/npmjs/-/browserslist/4.22.2, MIT, approved, #10780 npm/npmjs/-/buffer/6.0.3, MIT, approved, clearlydefined npm/npmjs/-/callsites/3.1.0, MIT, approved, clearlydefined From f88d805c4f32a4313e62da8f8dbd967e6ff47d59 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Thu, 23 May 2024 08:42:41 +0200 Subject: [PATCH 05/10] fix: added customerList to productcreation method --- .../puris/backend/common/ddtr/logic/DtrAdapterService.java | 5 +++-- .../logic/service/MaterialPartnerRelationServiceImpl.java | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java index 10348574..bd534167 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java @@ -140,11 +140,12 @@ public Integer updateProduct(Material material, List mp * A new AAS will be registered for this Material at your dDTR. * * @param material The Material + * @param mprs The list of all MaterialProductRelations that exist with customers of the given Material * @return The HTTP response code from the DTR, or null if none was received */ - public Integer registerProductAtDtr(Material material) { + public Integer registerProductAtDtr(Material material, List mprs) { String twinId = digitalTwinMappingService.get(material).getProductTwinId(); - var body = dtrRequestBodyBuilder.createProductRegistrationRequestBody(material, twinId, List.of()); + var body = dtrRequestBodyBuilder.createProductRegistrationRequestBody(material, twinId, mprs); try (var response = sendDtrPostRequest(body, List.of("api", "v3", "shell-descriptors"))) { return response.code(); } catch (Exception e) { diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java index 8f75ee15..d2233a82 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java @@ -268,9 +268,12 @@ public Boolean call() throws Exception { completedProductRegistration = true; } else { if (result == 404) { - Integer registrationResult = dtrAdapterService.registerProductAtDtr(materialPartnerRelation.getMaterial()); + Integer registrationResult = dtrAdapterService.registerProductAtDtr(materialPartnerRelation.getMaterial(), allCustomers); log.info("Tried to create product AAS for " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + ", result: " + registrationResult); + if (registrationResult < 400) { + completedMaterialRegistration = true; + } } } } else { From 883d79f879b424d14f893dbf4e069d550fe35d22 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Thu, 23 May 2024 08:49:34 +0200 Subject: [PATCH 06/10] chore: increased version number --- backend/pom.xml | 2 +- charts/puris/Chart.yaml | 4 +- charts/puris/README.md | 361 ++++++++++++++++++++-------------------- 3 files changed, 179 insertions(+), 188 deletions(-) diff --git a/backend/pom.xml b/backend/pom.xml index 1b026611..5194fe36 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -33,7 +33,7 @@ org.eclipse.tractusx.puris puris-backend - 2.0.0 + 2.0.1 puris-backend PURIS Backend diff --git a/charts/puris/Chart.yaml b/charts/puris/Chart.yaml index d0f0c11f..d7fd15bc 100644 --- a/charts/puris/Chart.yaml +++ b/charts/puris/Chart.yaml @@ -35,10 +35,10 @@ dependencies: # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.5.1 +version: 2.5.2 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "2.0.0" +appVersion: "2.0.1" diff --git a/charts/puris/README.md b/charts/puris/README.md index e36d3220..01a1ad01 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -1,18 +1,16 @@ # puris -![Version: 2.5.1](https://img.shields.io/badge/Version-2.5.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.0.0](https://img.shields.io/badge/AppVersion-2.0.0-informational?style=flat-square) +![Version: 2.5.2](https://img.shields.io/badge/Version-2.5.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.0.1](https://img.shields.io/badge/AppVersion-2.0.1-informational?style=flat-square) A helm chart for Kubernetes deployment of PURIS **Homepage:** ## Prerequisites - - Kubernetes 1.19+ - Helm 3.2.0+ ## TL;DR - ```shell $ helm install puris --namespace puris --create-namespace . ``` @@ -23,190 +21,183 @@ $ helm install puris --namespace puris --create-namespace . ## Requirements -| Repository | Name | Version | -|------------------------------------|------------|---------| +| Repository | Name | Version | +|------------|------|---------| | https://charts.bitnami.com/bitnami | postgresql | 12.12.x | ## Values -| Key | Type | Default | Description | -|-------------------------------------------------------------------------------------------------------------------------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | -| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | -| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | -| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| backend.imagePullSecrets | list | `[]` | List of used secrets | -| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | -| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | -| backend.ingress.enabled | bool | `false` | Enable the Ingress | -| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | -| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | -| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| backend.nameOverride | string | `""` | Possibility to override the name | -| backend.nodeSelector | object | `{}` | Constrains for the node selector | -| backend.podAnnotations | object | `{}` | Annotations added to a running pod | -| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | -| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | -| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | -| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | -| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | -| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | -| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | -| backend.puris.deliverysubmodel.apiassetid | string | `"deliverysubmodel-api-asset"` | Asset ID for DeliverySubmodel API | -| backend.puris.demandsubmodel.apiassetid | string | `"demandsubmodel-api-asset"` | Asset ID for DemandSubmodel API | -| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | -| backend.puris.dtr.idp.clients.edc.id | string | `"FOSS-EDC-CLIENT"` | id of the client that has a service account with roles to view the DTR. Used by the application to create DTR asset in the edc with read only access. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.clients.edc.secret.alias | string | `"path/secret-name"` | alias for the vault used by the EDC in which the secret is stored. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.clients.puris.id | string | `"FOSS-PURIS-CLIENT"` | id of the client that has a service account with roles to manage the DTR. Used by the application to create and update digital twins. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.clients.puris.secret | string | `nil` | secret of the client with write access (no vault alias). No default value will be created if empty. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.idp.enabled | bool | `true` | enables the usage of the IDP for the DTR. | -| backend.puris.dtr.idp.tokenurl | string | `"https://keycloak-service.com/realms/your-realm/openid-connect/token"` | token url of the idp for your specific realm. May be different to other idp token url in this config. Mandatory if backend.puris.dtr.idp.enabled = true. | -| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | -| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | -| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | -| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | -| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | -| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | -| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | -| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | -| backend.puris.frameworkagreement.credential | string | `"Puris"` | The name of the framework agreement. Starting with Uppercase and using CamelCase. | -| backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | -| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | -| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | -| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | -| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | -| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | -| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | -| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | -| backend.puris.own.country | string | `"Germany"` | Own country | -| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | -| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | -| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | -| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | -| backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | -| backend.puris.purpose.name | string | `"cx.puris.base"` | The name of the purpose to use for submodel contracts | -| backend.puris.purpose.version | string | `"1"` | The version of the purpose to use for submodel contracts. NEEDS TO BE PUT AS "STRING"! | -| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | -| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | -| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | -| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | -| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | -| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | -| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | -| backend.service.port | int | `8081` | The port of the service | -| backend.service.type | string | `"ClusterIP"` | Type of the service | -| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| backend.tolerations | list | `[]` | Constrains for tolerations | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | -| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | -| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | -| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | -| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | -| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | -| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| frontend.imagePullSecrets | list | `[]` | List of used secrets | -| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | -| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | -| frontend.ingress.enabled | bool | `false` | Enable the Ingress | -| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | -| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | -| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| frontend.nameOverride | string | `""` | Possibility to override the name | -| frontend.nodeSelector | object | `{}` | Constrains for the node selector | -| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | -| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | -| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | -| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointDelivery | string | `"delivery"` | The endpoint for the delivery submodel | -| frontend.puris.endpointDemand | string | `"demand"` | The endpoint for the demand submodel | -| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | -| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | -| frontend.puris.endpointPartner | string | `"partner"` | The endpoint for the partners BPNS | -| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | -| frontend.puris.endpointProduction | string | `"production"` | The endpoint for the production submodel | -| frontend.puris.endpointProductionRange | string | `"production/range"` | The endpoint for the production range of the production submodel | -| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | -| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | -| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | -| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | -| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | -| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | -| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | -| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | -| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | -| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | -| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | -| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | -| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | -| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | -| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | -| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| frontend.replicaCount | int | `1` | | -| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | -| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | -| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | -| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | -| frontend.service.port | int | `8080` | The port of the service | -| frontend.service.type | string | `"ClusterIP"` | Type of the service | -| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| frontend.tolerations | list | `[]` | Constrains for tolerations | -| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | -| postgresql.auth.database | string | `"postgres"` | Name of the database. | -| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | -| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | -| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | -| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | -| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | -| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | -| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | - -## NOTICE - -This work is licensed under the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | +| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | +| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | +| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| backend.imagePullSecrets | list | `[]` | List of used secrets | +| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | +| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | +| backend.ingress.enabled | bool | `false` | Enable the Ingress | +| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | +| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | +| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| backend.nameOverride | string | `""` | Possibility to override the name | +| backend.nodeSelector | object | `{}` | Constrains for the node selector | +| backend.podAnnotations | object | `{}` | Annotations added to a running pod | +| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | +| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | +| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | +| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | +| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | +| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | +| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | +| backend.puris.deliverysubmodel.apiassetid | string | `"deliverysubmodel-api-asset"` | Asset ID for DeliverySubmodel API | +| backend.puris.demandsubmodel.apiassetid | string | `"demandsubmodel-api-asset"` | Asset ID for DemandSubmodel API | +| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | +| backend.puris.dtr.idp.clients.edc.id | string | `"FOSS-EDC-CLIENT"` | id of the client that has a service account with roles to view the DTR. Used by the application to create DTR asset in the edc with read only access. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.clients.edc.secret.alias | string | `"path/secret-name"` | alias for the vault used by the EDC in which the secret is stored. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.clients.puris.id | string | `"FOSS-PURIS-CLIENT"` | id of the client that has a service account with roles to manage the DTR. Used by the application to create and update digital twins. See Admin Guide. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.clients.puris.secret | string | `nil` | secret of the client with write access (no vault alias). No default value will be created if empty. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.idp.enabled | bool | `true` | enables the usage of the IDP for the DTR. | +| backend.puris.dtr.idp.tokenurl | string | `"https://keycloak-service.com/realms/your-realm/openid-connect/token"` | token url of the idp for your specific realm. May be different to other idp token url in this config. Mandatory if backend.puris.dtr.idp.enabled = true. | +| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | +| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | +| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | +| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | +| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | +| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | +| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | +| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | +| backend.puris.frameworkagreement.credential | string | `"Puris"` | The name of the framework agreement. Starting with Uppercase and using CamelCase. | +| backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | +| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | +| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | +| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | +| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | +| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | +| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | +| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | +| backend.puris.own.country | string | `"Germany"` | Own country | +| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | +| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | +| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | +| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | +| backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | +| backend.puris.purpose.name | string | `"cx.puris.base"` | The name of the purpose to use for submodel contracts | +| backend.puris.purpose.version | string | `"1"` | The version of the purpose to use for submodel contracts. NEEDS TO BE PUT AS "STRING"! | +| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | +| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | +| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | +| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | +| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | +| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | +| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | +| backend.service.port | int | `8081` | The port of the service | +| backend.service.type | string | `"ClusterIP"` | Type of the service | +| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| backend.tolerations | list | `[]` | Constrains for tolerations | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | +| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | +| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | +| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | +| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | +| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | +| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| frontend.imagePullSecrets | list | `[]` | List of used secrets | +| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | +| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | +| frontend.ingress.enabled | bool | `false` | Enable the Ingress | +| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | +| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | +| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| frontend.nameOverride | string | `""` | Possibility to override the name | +| frontend.nodeSelector | object | `{}` | Constrains for the node selector | +| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | +| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | +| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | +| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointDelivery | string | `"delivery"` | The endpoint for the delivery submodel | +| frontend.puris.endpointDemand | string | `"demand"` | The endpoint for the demand submodel | +| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | +| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | +| frontend.puris.endpointPartner | string | `"partner"` | The endpoint for partner information | +| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | +| frontend.puris.endpointProduction | string | `"production"` | The endpoint for the production submodel | +| frontend.puris.endpointProductionRange | string | `"production/range"` | The endpoint for the production range of the production submodel | +| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | +| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | +| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | +| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | +| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | +| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | +| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | +| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | +| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | +| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | +| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | +| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | +| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | +| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | +| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | +| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| frontend.replicaCount | int | `1` | | +| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | +| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | +| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | +| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | +| frontend.service.port | int | `8080` | The port of the service | +| frontend.service.type | string | `"ClusterIP"` | Type of the service | +| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| frontend.tolerations | list | `[]` | Constrains for tolerations | +| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | +| postgresql.auth.database | string | `"postgres"` | Name of the database. | +| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | +| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | +| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | +| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | +| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | +| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | +| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | -- SPDX-License-Identifier: Apache-2.0 -- SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation -- Source URL: https://github.com/eclipse-tractusx/puris From 81e1b07ace80ce2c510e08cd4f6163a516971d82 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Thu, 23 May 2024 08:52:09 +0200 Subject: [PATCH 07/10] fix: updated Javadocs --- .../puris/backend/common/ddtr/logic/DtrAdapterService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java index bd534167..13442207 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/DtrAdapterService.java @@ -134,8 +134,8 @@ public Integer updateProduct(Material material, List mp } /** - * Call this method when a new Material with a product flag was created in your MaterialService - or if a product - * flag was later added to an existing Material. + * Call this method when you need to register a product at the DTR for which there was no product AAS registered + * previously. *

* A new AAS will be registered for this Material at your dDTR. * From 5786f7f31773e0f5b86eae7a6054fe1f2d102d49 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Thu, 23 May 2024 09:19:27 +0200 Subject: [PATCH 08/10] fix: added null check --- .../logic/service/MaterialPartnerRelationServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java index d2233a82..62b8d089 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java @@ -271,7 +271,7 @@ public Boolean call() throws Exception { Integer registrationResult = dtrAdapterService.registerProductAtDtr(materialPartnerRelation.getMaterial(), allCustomers); log.info("Tried to create product AAS for " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + ", result: " + registrationResult); - if (registrationResult < 400) { + if (registrationResult != null && registrationResult < 400) { completedMaterialRegistration = true; } } From f3cc706dd550f3072c2fac0ec75afce378632962 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Thu, 23 May 2024 11:19:08 +0200 Subject: [PATCH 09/10] fix: added/improved emergency cx-id fetch --- .../service/DeliveryRequestApiService.java | 29 +++++++++---- .../services/DemandRequestApiService.java | 20 ++++++++- .../MaterialPartnerRelationService.java | 2 +- .../MaterialPartnerRelationServiceImpl.java | 29 +++++++++---- .../service/ItemStockRequestApiService.java | 41 ++++++++++++------- 5 files changed, 87 insertions(+), 34 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java index 918ed5dc..11eb0919 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java @@ -27,7 +27,6 @@ import org.eclipse.tractusx.puris.backend.delivery.logic.adapter.DeliveryInformationSammMapper; import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.DeliveryInformation; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; -import org.eclipse.tractusx.puris.backend.masterdata.domain.model.MaterialPartnerRelation; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialPartnerRelationService; import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialService; @@ -67,17 +66,27 @@ public DeliveryInformation handleDeliverySubmodelRequest(String bpnl, String mat log.error("Unknown Partner BPNL " + bpnl); return null; } - MaterialPartnerRelation mpr = mprService.findByPartnerAndPartnerCXNumber(partner, materialNumberCx); + Material material = materialService.findByMaterialNumberCx(materialNumberCx); - if (material == null && mpr == null) { - log.error("Unknown Material " + materialNumberCx); - return null; + if (material == null) { + // Could not identify partner cx number. I.e. we do not have that partner's + // CX id in one of our MaterialPartnerRelation entities. Try to fix this by + // looking for MPR's, where that partner is a supplier and where we don't have + // a partnerCXId yet. Of course this can only work if there was previously an MPR + // created, but for some unforeseen reason, the initial PartTypeRetrieval didn't succeed. + log.warn("Could not find " + materialNumberCx + " from partner " + partner.getBpnl()); + mprService.triggerPartTypeRetrievalTask(partner); + material = materialService.findByMaterialNumberCx(materialNumberCx); } + if (material == null) { - material = mpr.getMaterial(); + log.error("Unknown Material " + materialNumberCx); + return null; } - if (!mprService.find(material, partner).isPartnerBuysMaterial()) { - // only send an answer if partner is registered as customer + + var mpr = mprService.find(material,partner); + if (mpr == null || !mpr.isPartnerSuppliesMaterial()) { + // only send an answer if partner is registered as supplier return null; } @@ -88,6 +97,10 @@ public DeliveryInformation handleDeliverySubmodelRequest(String bpnl, String mat public void doReportedDeliveryRequest(Partner partner, Material material) { try { var mpr = mprService.find(material, partner); + if (mpr.getPartnerCXNumber() == null) { + mprService.triggerPartTypeRetrievalTask(partner); + mpr = mprService.find(material, partner); + } var direction = material.isMaterialFlag() ? DirectionCharacteristic.OUTBOUND : DirectionCharacteristic.INBOUND; var data = edcAdapterService.doSubmodelRequest(SubmodelType.DELIVERY, mpr, direction, 1); var samm = objectMapper.treeToValue(data, DeliveryInformation.class); diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java index a6175e21..c3811da1 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java @@ -64,12 +64,24 @@ public ShortTermMaterialDemand handleDemandSubmodelRequest(String bpnl, String m return null; } Material material = mprService.findByPartnerAndPartnerCXNumber(partner, materialNumberCx).getMaterial(); + + if (material == null) { + // Could not identify partner cx number. I.e. we do not have that partner's + // CX id in one of our MaterialPartnerRelation entities. Try to fix this by + // looking for MPR's, where that partner is a supplier and where we don't have + // a partnerCXId yet. Of course this can only work if there was previously an MPR + // created, but for some unforeseen reason, the initial PartTypeRetrieval didn't succeed. + log.warn("Could not find " + materialNumberCx + " from partner " + partner.getBpnl()); + mprService.triggerPartTypeRetrievalTask(partner); + material = mprService.findByPartnerAndPartnerCXNumber(partner, materialNumberCx).getMaterial(); + } + if (material == null) { log.error("Unknown Material"); return null; } - - if (!mprService.find(material,partner).isPartnerSuppliesMaterial()) { + var mpr = mprService.find(material,partner); + if (mpr == null || !mpr.isPartnerSuppliesMaterial()) { // only send an answer if partner is registered as supplier return null; } @@ -81,6 +93,10 @@ public ShortTermMaterialDemand handleDemandSubmodelRequest(String bpnl, String m public void doReportedDemandRequest(Partner partner, Material material) { try { var mpr = mprService.find(material, partner); + if (mpr.getPartnerCXNumber() == null) { + mprService.triggerPartTypeRetrievalTask(partner); + mpr = mprService.find(material, partner); + } var data = edcAdapterService.doSubmodelRequest(SubmodelType.DEMAND, mpr, DirectionCharacteristic.INBOUND, 1); var samm = objectMapper.treeToValue(data, ShortTermMaterialDemand.class); var demands = sammMapper.sammToReportedDemand(samm, partner); diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationService.java index c8d3e7a2..df03d0d7 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationService.java @@ -33,7 +33,7 @@ public interface MaterialPartnerRelationService { MaterialPartnerRelation create(MaterialPartnerRelation materialPartnerRelation); - void triggerPartTypeRetrievalTask(MaterialPartnerRelation mpr); + void triggerPartTypeRetrievalTask(Partner supplierPartner); MaterialPartnerRelation update(MaterialPartnerRelation materialPartnerRelation); diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java index 62b8d089..94e1e21f 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java @@ -23,7 +23,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.tractusx.puris.backend.common.ddtr.logic.DigitalTwinMappingService; import org.eclipse.tractusx.puris.backend.common.ddtr.logic.DtrAdapterService; import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EdcAdapterService; import org.eclipse.tractusx.puris.backend.common.util.PatternStore; @@ -54,9 +53,6 @@ public class MaterialPartnerRelationServiceImpl implements MaterialPartnerRelati @Autowired private VariablesService variablesService; - @Autowired - private DigitalTwinMappingService dtmService; - @Autowired private DtrAdapterService dtrAdapterService; @@ -98,10 +94,25 @@ public MaterialPartnerRelation create(MaterialPartnerRelation materialPartnerRel return null; } + /** + * Call this method when a partnerCXId for a Material was needed but not found. + * This method will trigger a new PartTypeInformation Task for any material that + * the given partner supplies, but still misses a partnerCXId. + * + * This method will block until all tasks have finished, if any. + * + * @param supplierPartner The supplier partner + */ @Override - public void triggerPartTypeRetrievalTask(MaterialPartnerRelation mpr) { - if (!currentPartTypeFetches.contains(mpr)) { - executorService.submit(new PartTypeInformationRetrievalTask(mpr, 1)); + public void triggerPartTypeRetrievalTask(Partner supplierPartner) { + List> futures = findAllMaterialsThatPartnerSupplies(supplierPartner).stream() + .map(mat -> find(mat, supplierPartner)) + .filter(mpr -> mpr.isPartnerSuppliesMaterial() && mpr.getPartnerCXNumber() == null) + .map(mpr -> executorService.submit(new PartTypeInformationRetrievalTask(mpr, 1))).toList(); + boolean allDone = futures.isEmpty(); + while (!allDone) { + Thread.yield(); + allDone = futures.stream().allMatch(Future::isDone); } } @@ -144,7 +155,7 @@ private class PartTypeInformationRetrievalTask implements Callable { /** * This method contains all the duties which the PartTypeInformationRetrievalTask is trying to fulfill. * - * @return true, if the task finished successfully + * @return true, if the task finished successfully */ @Override public Boolean call() { @@ -242,7 +253,7 @@ public DtrRegistrationTask(MaterialPartnerRelation materialPartnerRelation, int /** * This method contains all the duties which the DtrRegistrationTask is trying to fulfill. * - * @return true, if the task finished successfully + * @return true, if the task finished successfully */ @Override public Boolean call() throws Exception { diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java index 33f7f35a..1007a949 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockRequestApiService.java @@ -84,22 +84,31 @@ public ItemStockSamm handleItemStockSubmodelRequest(String bpnl, String material // Partner is supplier, requesting our MaterialItemStocks from him // materialNumber is partner's CX id: Material material = mprService.findByPartnerAndPartnerCXNumber(partner, materialNumber).getMaterial(); - if (material != null && mprService.find(material, partner).isPartnerSuppliesMaterial()) { + if (material == null) { + // Could not identify partner cx number. I.e. we do not have that partner's + // CX id in one of our MaterialPartnerRelation entities. Try to fix this by + // looking for MPR's, where that partner is a supplier and where we don't have + // a partnerCXId yet. Of course this can only work if there was previously an MPR + // created, but for some unforeseen reason, the initial PartTypeRetrieval didn't succeed. + log.warn("Could not find " + materialNumber + " from partner " + partner.getBpnl()); + mprService.triggerPartTypeRetrievalTask(partner); + material = mprService.findByPartnerAndPartnerCXNumber(partner, materialNumber).getMaterial(); + } + + if (material == null) { + log.error("Unknown Material"); + return null; + } + var mpr = mprService.find(material, partner); + if (mpr == null || !mpr.isPartnerSuppliesMaterial()) { // only send an answer if partner is registered as supplier - var currentStocks = materialItemStockService.findByPartnerAndMaterial(partner, material); - return sammMapper.materialItemStocksToItemStockSamm(currentStocks, partner, material); + return null; } - // Could not identify partner cx number. I.e. we do not have that partner's - // CX id in one of our MaterialPartnerRelation entities. Try to fix this by - // looking for MPR's, where that partner is a supplier and where we don't have - // a partnerCXId yet. Of course this can only work if there was previously an MPR - // created, but for some unforeseen reason, the initial PartTypeRetrieval didn't succeed. - log.warn("Could not find " + materialNumber + " from partner " + partner.getBpnl()); - mprService.findAllMaterialsThatPartnerSupplies(partner).stream() - .map(mat -> mprService.find(mat, partner)) - .filter(mpr -> mpr.isPartnerSuppliesMaterial() && mpr.getPartnerCXNumber() == null) - .forEach(mpr -> mprService.triggerPartTypeRetrievalTask(mpr)); - return null; + + // only send an answer if partner is registered as supplier + var currentStocks = materialItemStockService.findByPartnerAndMaterial(partner, material); + return sammMapper.materialItemStocksToItemStockSamm(currentStocks, partner, material); + } default -> { return null; @@ -138,6 +147,10 @@ public void doItemStockSubmodelReportedMaterialItemStockRequest(Partner partner, public void doItemStockSubmodelReportedProductItemStockRequest(Partner partner, Material material) { try { var mpr = mprService.find(material, partner); + if (mpr.getPartnerCXNumber() == null) { + mprService.triggerPartTypeRetrievalTask(partner); + mpr = mprService.find(material, partner); + } var data = edcAdapterService.doSubmodelRequest(SubmodelType.ITEM_STOCK ,mpr, DirectionCharacteristic.INBOUND, 1); var samm = objectMapper.treeToValue(data, ItemStockSamm.class); var stocks = sammMapper.itemStockSammToReportedProductItemStock(samm, partner); From 7fddfb0c084626b0cd691b54f990caa01ad89c9a Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Thu, 23 May 2024 12:42:47 +0200 Subject: [PATCH 10/10] fix: bug in parttypefetch/dtrregistration --- .../MaterialPartnerRelationServiceImpl.java | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java index 94e1e21f..fcb1c900 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/logic/service/MaterialPartnerRelationServiceImpl.java @@ -82,12 +82,6 @@ public MaterialPartnerRelation create(MaterialPartnerRelation materialPartnerRel var searchResult = find(materialPartnerRelation.getMaterial(), materialPartnerRelation.getPartner()); if (searchResult == null) { executorService.submit(new DtrRegistrationTask(materialPartnerRelation, 3)); - if (materialPartnerRelation.getMaterial().isMaterialFlag() && materialPartnerRelation.isPartnerSuppliesMaterial() - && materialPartnerRelation.getPartnerCXNumber() == null) { - log.info("Attempting CX-Id fetch for Material " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + - " from Supplier-Partner " + materialPartnerRelation.getPartner().getBpnl()); - executorService.submit(new PartTypeInformationRetrievalTask(materialPartnerRelation, 1)); - } return mprRepository.save(materialPartnerRelation); } log.error("Could not create MaterialPartnerRelation, " + materialPartnerRelation.getKey() + " already exists"); @@ -105,15 +99,28 @@ public MaterialPartnerRelation create(MaterialPartnerRelation materialPartnerRel */ @Override public void triggerPartTypeRetrievalTask(Partner supplierPartner) { - List> futures = findAllMaterialsThatPartnerSupplies(supplierPartner).stream() - .map(mat -> find(mat, supplierPartner)) - .filter(mpr -> mpr.isPartnerSuppliesMaterial() && mpr.getPartnerCXNumber() == null) - .map(mpr -> executorService.submit(new PartTypeInformationRetrievalTask(mpr, 1))).toList(); - boolean allDone = futures.isEmpty(); - while (!allDone) { + List> futures = mprRepository + .findAllByPartner_UuidAndPartnerSuppliesMaterialIsTrue(supplierPartner.getUuid()) + .stream() + .filter(mpr -> mpr.getPartnerCXNumber() == null) + .filter(mpr -> !currentPartTypeFetches.contains(mpr)) + .map(mpr -> executorService.submit(new PartTypeInformationRetrievalTask(mpr, 1))) + .toList(); + if (futures.isEmpty()) { + return; + } + + do { Thread.yield(); - allDone = futures.stream().allMatch(Future::isDone); + // wait until all triggered tasks have returned + } while (!futures.stream().allMatch(Future::isDone)); + + // give the database a little bit of time to handle the updates + try { + Thread.sleep(400); + } catch (InterruptedException ignored) { } + } @@ -283,7 +290,7 @@ public Boolean call() throws Exception { log.info("Tried to create product AAS for " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + ", result: " + registrationResult); if (registrationResult != null && registrationResult < 400) { - completedMaterialRegistration = true; + completedProductRegistration = true; } } } @@ -365,12 +372,6 @@ public MaterialPartnerRelation update(MaterialPartnerRelation materialPartnerRel flagConsistencyTest(materialPartnerRelation); var foundEntity = mprRepository.findById(materialPartnerRelation.getKey()); if (foundEntity.isPresent()) { - if (materialPartnerRelation.getMaterial().isMaterialFlag() && materialPartnerRelation.isPartnerSuppliesMaterial() - && materialPartnerRelation.getPartnerCXNumber() == null) { - log.info("Attempting CX-Id fetch for Material " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + - " from Supplier-Partner " + materialPartnerRelation.getPartner().getBpnl()); - executorService.submit(new PartTypeInformationRetrievalTask(materialPartnerRelation, 3)); - } executorService.submit(new DtrRegistrationTask(materialPartnerRelation, 3)); return mprRepository.save(materialPartnerRelation); }