diff --git a/backend/pom.xml b/backend/pom.xml index 1c23ab12..85cb0e63 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/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..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,17 +134,18 @@ 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. * * @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/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index d80ff8d5..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; @@ -178,7 +177,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 +226,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 +474,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 { @@ -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); } @@ -568,13 +567,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 +602,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 +746,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 +761,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 +782,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 +830,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 +840,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 +859,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 +876,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) { + JsonNode responseObject = 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; } /** 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..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 @@ -22,15 +22,11 @@ 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; 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; @@ -39,6 +35,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Optional; + @Service @Slf4j /** @@ -68,22 +66,41 @@ 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) { + 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) { log.error("Unknown Material " + materialNumberCx); return null; } - if (material == null) { - material = mpr.getMaterial(); + + var mpr = mprService.find(material,partner); + if (mpr == null || !mpr.isPartnerSuppliesMaterial()) { + // only send an answer if partner is registered as supplier + 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) { 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/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..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 @@ -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 /** @@ -65,17 +64,39 @@ 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; } + var mpr = mprService.find(material,partner); + if (mpr == null || !mpr.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) { 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 8f75ee15..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 @@ -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; @@ -86,23 +82,45 @@ 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"); 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 = 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(); + // 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) { + } + } @@ -144,7 +162,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 +260,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 { @@ -268,9 +286,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 != null && registrationResult < 400) { + completedProductRegistration = true; + } } } } else { @@ -351,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); } 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..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 @@ -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,21 +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) { - var currentStocks = materialItemStockService.findByPartnerAndMaterial(partner, material); - return sammMapper.materialItemStocksToItemStockSamm(currentStocks); + 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(); } - // 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; + + 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 + 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; @@ -136,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); 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); diff --git a/charts/puris/Chart.yaml b/charts/puris/Chart.yaml index b6880ece..1292ec74 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.6.0 +version: 2.6.1 # 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 ef810be3..d345bb9c 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -1,12 +1,13 @@ # puris -![Version: 2.6.0](https://img.shields.io/badge/Version-2.6.0-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.6.1](https://img.shields.io/badge/Version-2.6.1-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+