From 40965ea575f884fb1064d87f1f33086843e41988 Mon Sep 17 00:00:00 2001 From: Ernst-Christoph Schrewe Date: Thu, 14 Mar 2024 12:11:48 +0100 Subject: [PATCH] feat: added retreival of parttypeinformation for materials --- .../DataInjectionCommandLineRunner.java | 6 +- .../logic/util/DtrRequestBodyBuilder.java | 4 +- .../edc/logic/service/EdcAdapterService.java | 150 +++++++++++++++++- .../edc/logic/util/EdcRequestBodyBuilder.java | 46 ++++++ .../common/security/SecurityConfig.java | 2 +- .../backend/common/util/VariablesService.java | 3 + .../PartTypeInformationController.java | 57 +++++++ .../MaterialPartnerRelationServiceImpl.java | 76 ++++++++- .../src/main/resources/application.properties | 1 + .../src/test/resources/application.properties | 1 + .../config/customer/puris-backend.properties | 1 + .../config/supplier/puris-backend.properties | 1 + 12 files changed, 336 insertions(+), 12 deletions(-) create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/controller/PartTypeInformationController.java diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java index 6c83c59b..878123de 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java @@ -162,7 +162,7 @@ private void setupCustomerRole() throws JsonProcessingException { MaterialPartnerRelation semiconductorPartnerRelation = new MaterialPartnerRelation(semiconductorMaterial, supplierPartner, semiconductorMatNbrSupplier, true, false); - semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX); +// semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX); mprService.create(semiconductorPartnerRelation); semiconductorPartnerRelation = mprService.find(semiconductorMaterial, supplierPartner); log.info("Found Relation: " + semiconductorPartnerRelation); @@ -248,7 +248,7 @@ private void setupSupplierRole() { MaterialPartnerRelation semiconductorPartnerRelation = new MaterialPartnerRelation(semiconductorMaterial, customerPartner, semiconductorMatNbrCustomer, false, true); - semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX); +// semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX); semiconductorPartnerRelation = mprService.create(semiconductorPartnerRelation); log.info("Created Relation " + semiconductorPartnerRelation); @@ -411,7 +411,7 @@ private Material getNewSemiconductorMaterialForSupplier() { private Material getNewSemiconductorMaterialForCustomer() { Material material = new Material(); material.setOwnMaterialNumber(semiconductorMatNbrCustomer); - material.setMaterialNumberCx(semiconductorMatNbrCatenaX); +// material.setMaterialNumberCx(semiconductorMatNbrCatenaX); material.setMaterialFlag(true); material.setName("Semiconductor"); return material; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java index 90839bcf..73f648f6 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java @@ -89,7 +89,7 @@ public JsonNode createMaterialRegistrationRequestBody(MaterialPartnerRelation ma var itemStockRequestSubmodelObject = createItemStockSubmodelObject(); submodelDescriptorsArray.add(itemStockRequestSubmodelObject); - log.info("Created body for material " + material.getOwnMaterialNumber() + "\n" + body.toPrettyString()); + log.debug("Created body for material " + material.getOwnMaterialNumber() + "\n" + body.toPrettyString()); return body; } @@ -131,7 +131,7 @@ public JsonNode createProductRegistrationRequestBody(Material material, String p var itemStockRequestSubmodelObject = createItemStockSubmodelObject(); submodelDescriptorsArray.add(itemStockRequestSubmodelObject); - log.info("Created body for product " + material.getOwnMaterialNumber() + "\n" + body.toPrettyString()); + log.debug("Created body for product " + material.getOwnMaterialNumber() + "\n" + body.toPrettyString()); return body; } 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 4d49fb37..c70b6e9c 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 @@ -139,6 +139,8 @@ public boolean registerAssetsInitially() { public boolean createPolicyAndContractDefForPartner(Partner partner) { boolean result = createPolicyDefinitionForPartner(partner); result &= createDtrContractDefinitionForPartner(partner); + result &= registerPartTypeAssetForPartner(partner); + result &= createPartTypeInfoContractDefForPartner(partner); result &= createContractDefinitionForPartner(partner, DT_ApiMethodEnum.REQUEST); result &= createContractDefinitionForPartner(partner, DT_ApiMethodEnum.STATUS_REQUEST); return result & createContractDefinitionForPartner(partner, DT_ApiMethodEnum.RESPONSE); @@ -186,6 +188,21 @@ private boolean createDtrContractDefinitionForPartner(Partner partner) { } } + private boolean createPartTypeInfoContractDefForPartner(Partner partner) { + var body = edcRequestBodyBuilder.buildPartTypeInfoContractDefinitionForPartner(partner); + try (var response = sendPostRequest(body, List.of("v2", "contractdefinitions"))) { + if (!response.isSuccessful()) { + log.warn("Contract definition registration failed for partner " + partner.getBpnl() + " and PartTypeInfo asset"); + return false; + } + log.info("Contract definition successful for PartTypeAsset and partner " + partner.getBpnl()); + return true; + } catch (Exception e) { + log.error("Contract definition registration failed for partner " + partner.getBpnl() + " and PartTypeInfo asset", e); + return false; + } + } + /** * Registers a policy definition that allows only the given partner's @@ -242,6 +259,7 @@ private boolean registerDtrAsset() { if (response.body() != null) { log.warn("Response: \n" + response.body().string()); } + return false; } return true; } catch (Exception e) { @@ -250,6 +268,24 @@ private boolean registerDtrAsset() { } } + private boolean registerPartTypeAssetForPartner(Partner partner) { + var body = edcRequestBodyBuilder.buildPartTypeInfoRegistrationBody(partner); + try (var response = sendPostRequest(body, List.of("v3", "assets"))) { + if (!response.isSuccessful()) { + log.warn("Asset registration failed for PartTypeAsset and partner " + partner.getBpnl()); + if (response.body() != null) { + log.warn("Response: \n" + response.body().string()); + } + return false; + } + log.info("Asset registration successful for PartTypeAsset and partner " + partner.getBpnl()); + return true; + } catch (Exception e) { + log.error("Failed to register PartTypeAsset for partner " + partner.getBpnl()); + return false; + } + } + /** * Util method to register an API asset to your control plane. * @@ -277,11 +313,12 @@ private boolean registerApiAsset(DT_ApiMethodEnum apiMethod) { /** * Retrieve the response to an unfiltered catalog request from the partner * with the given dspUrl - * @param dspUrl The dspUrl of your partner - * @return The response containing the full catalog, if successful + * + * @param dspUrl The dspUrl of your partner + * @return The response containing the full catalog, if successful */ public Response getCatalogResponse(String dspUrl) throws IOException { - return sendPostRequest(edcRequestBodyBuilder.buildBasicCatalogRequestBody(dspUrl, null), List.of("v2", "catalog", "request")); + return sendPostRequest(edcRequestBodyBuilder.buildBasicCatalogRequestBody(dspUrl, null), List.of("v2", "catalog", "request")); } /** @@ -432,6 +469,113 @@ public Response postProxyPullRequest(String url, String authKey, String authCode } } + public Response getProxyPullRequest(String url, String authKey, String authCode, String[] pathParams) { + HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); + for (var pathSegment : pathParams) { + urlBuilder.addPathSegment(pathSegment); + } + try { + var request = new Request.Builder() + .get() + .url(urlBuilder.build()) + .header(authKey, authCode) + .build(); + return CLIENT.newCall(request).execute(); + } catch (Exception e) { + log.error("ProxyPull GET Request failed ", e); + return null; + } + } + + /** + * Tries to negotiate for the PartTypeInfo-Api with the given partner + * and also tries to initiate the transfer of the edr token to the given endpoint. + *

+ * It will return a String array of length 4. The authKey is stored under index 0, the + * authCode under index 1, the endpoint under index 2 and the contractId under index 3. + * + * @param partner the partner + * @return A String array or null, if negotiation or transfer have failed or the authCode did not arrive + */ + public String[] getContractForPartTypeInfoApi(Partner partner) { + try { + var responseNode = getCatalog(partner.getEdcUrl()); + var catalogArray = responseNode.get("dcat:dataset"); + // If there is exactly one asset, the catalogContent will be a JSON object. + // In all other cases catalogContent will be a JSON array. + // For the sake of uniformity we will embed a single object in an array. + if (catalogArray.isObject()) { + catalogArray = objectMapper.createArrayNode().add(catalogArray); + } + JsonNode targetCatalogEntry = null; + for (var entry : catalogArray) { + var dctTypeObject = entry.get("dct:type"); + if (dctTypeObject != null) { + if (("https://w3id.org/catenax/taxonomy#UniqueIdPushConnectToParentNotification").equals(dctTypeObject.get("@id").asText())) { + if ("2.0".equals(entry.get("https://w3id.org/catenax/ontology/common#version").asText())) { + if (targetCatalogEntry == null) { + targetCatalogEntry = entry; + } else { + log.warn("Ambiguous catalog entries found! \n" + catalogArray.toPrettyString()); + } + } + } + } + } + if (targetCatalogEntry == null) { + log.error("Could not find api asset for PartTypeInformation at partner " + partner.getBpnl() + " 's catalog"); + return null; + } + String assetApiId = targetCatalogEntry.get("@id").asText(); + JsonNode negotiationResponse = initiateNegotiation(partner, targetCatalogEntry); + String negotiationId = negotiationResponse.get("@id").asText(); + // Await confirmation of contract and contractId + String contractId = null; + for (int i = 0; i < 100; i++) { + Thread.sleep(100); + var responseObject = getNegotiationState(negotiationId); + if ("FINALIZED".equals(responseObject.get("edc:state").asText())) { + contractId = responseObject.get("edc:contractAgreementId").asText(); + break; + } + } + if (contractId == null) { + var negotiationState = getNegotiationState(negotiationId); + log.warn("no contract id, last negotiation state: \n" + negotiationState.toPrettyString()); + log.error("Failed to obtain " + assetApiId + " from " + partner.getEdcUrl()); + return null; + } + + // Initiate transfer of edr + var transferResp = initiateProxyPullTransfer(partner, contractId, assetApiId); + String transferId = transferResp.get("@id").asText(); + for (int i = 0; i < 100; i++) { + Thread.sleep(100); + transferResp = getTransferState(transferId); + if ("STARTED".equals(transferResp.get("edc:state").asText())) { + break; + } + } + + // Await arrival of edr + for (int i = 0; i < 100; i++) { + Thread.sleep(100); + EDR_Dto edr_Dto = edrService.findByTransferId(transferId); + if (edr_Dto != null) { + log.info("Successfully negotiated for " + assetApiId + " with " + partner.getEdcUrl()); + return new String[]{edr_Dto.authKey(), edr_Dto.authCode(), edr_Dto.endpoint(), contractId}; + } + } + log.warn("did not receive authCode"); + log.error("Failed to obtain " + assetApiId + " from " + partner.getEdcUrl()); + return null; + + } catch (Exception e) { + log.error("Failed to get contract for PartTypeInfo api from " + partner.getBpnl(), e); + return null; + } + } + /** * Tries to negotiate for the given api Method with the given partner * and also tries to initiate the transfer of the edr token to the given endpoint. diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java index 085f45f8..b1e7035a 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java @@ -212,6 +212,20 @@ public JsonNode buildDtrContractDefinitionForPartner(Partner partner) { return body; } + public JsonNode buildPartTypeInfoContractDefinitionForPartner(Partner partner) { + var body = getEdcContextObject(); + body.put("@id", partner.getBpnl() +"_contractdefinition_for_PartTypeInfoAsset"); + body.put("accessPolicyId", getBpnPolicyId(partner)); + body.put("contractPolicyId", getBpnPolicyId(partner)); + var assetsSelector = MAPPER.createObjectNode(); + body.set("assetsSelector", assetsSelector); + assetsSelector.put("@type", "CriterionDto"); + assetsSelector.put("operandLeft", EDC_NAMESPACE + "id"); + assetsSelector.put("operator", "="); + assetsSelector.put("operandRight", getPartTypeInfoAssetId(partner)); + return body; + } + /** * This method helps to ensure that the buildContractDefinitionWithBpnRestrictedPolicy uses the * same policy-id as the one that is created with the buildContractDefinitionWithBpnRestrictedPolicy @@ -338,10 +352,42 @@ public JsonNode buildDtrRegistrationBody() { return body; } + public JsonNode buildPartTypeInfoRegistrationBody(Partner partner) { + var body = getAssetRegistrationContext(); + body.put("@id", getPartTypeInfoAssetId(partner)); + var propertiesObject = MAPPER.createObjectNode(); + body.set("properties", propertiesObject); + var dctTypeObject = MAPPER.createObjectNode(); + propertiesObject.set("dct:type", dctTypeObject); + dctTypeObject.put("@id", "cx-taxo:UniqueIdPushConnectToParentNotification"); + propertiesObject.put("cx-common:version", "2.0"); + propertiesObject.put("asset:prop:type", "foo.bar.PartTypeProp"); + var dataAddress = MAPPER.createObjectNode(); + String url = variablesService.getParttypeInformationServerendpoint(); + if (!url.endsWith("/")) { + url += "/"; + } + url += partner.getBpnl(); + dataAddress.put("@type", "DataAddress"); + dataAddress.put("proxyPath", "true"); + dataAddress.put("proxyQueryParams", "false"); + dataAddress.put("proxyMethod", "false"); + dataAddress.put("type", "HttpData"); + dataAddress.put("baseUrl", url); + dataAddress.put("authKey", "x-api-key"); + dataAddress.put("authCode", variablesService.getApiKey()); + body.set("dataAddress", dataAddress); + return body; + } + private String getDtrAssetId() { return "DigitalTwinRegistryId@" + variablesService.getOwnBpnl(); } + private String getPartTypeInfoAssetId(Partner partner) { + return "PartTypeInformationApi_" + partner.getBpnl(); + } + private ObjectNode getAssetRegistrationContext() { var body = MAPPER.createObjectNode(); var context = MAPPER.createObjectNode(); diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java index 16153249..f68f3d19 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java @@ -79,7 +79,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeHttpRequests( // any request in spring context (authorizeHttpRequests) -> authorizeHttpRequests - .requestMatchers("/stockView/**", "/partners/**", "/materials/**", "/materialpartnerrelations/**", "/item-stock/**", "/edrendpoint/**", "/edc/**").authenticated() + .requestMatchers("/stockView/**", "/partners/**", "/materials/**", "/materialpartnerrelations/**", "/item-stock/**", "/edrendpoint/**", "/edc/**", "/parttype/**").authenticated() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/health/**").permitAll() .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() ) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java index 24807e94..6d4d4705 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java @@ -116,6 +116,9 @@ public class VariablesService { */ private String dtrUrl; + @Value("${puris.parttypeinformation.serverendpoint}") + private String parttypeInformationServerendpoint; + @Value("${puris.generatematerialcatenaxid}") /** * A flag that signals whether the MaterialService diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/controller/PartTypeInformationController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/controller/PartTypeInformationController.java new file mode 100644 index 00000000..da0c8489 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/masterdata/controller/PartTypeInformationController.java @@ -0,0 +1,57 @@ +package org.eclipse.tractusx.puris.backend.masterdata.controller; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; +import org.eclipse.tractusx.puris.backend.masterdata.logic.adapter.PartTypeInformationSammMapper; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialPartnerRelationService; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialService; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.PartnerService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.regex.Pattern; + +@RestController +@RequestMapping("parttype") +@Slf4j +public class PartTypeInformationController { + static Pattern bpnlPattern = PatternStore.BPNL_PATTERN; + static Pattern materialNumberPattern = PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_PATTERN; + + @Autowired + private PartnerService partnerService; + @Autowired + private MaterialService materialService; + @Autowired + private MaterialPartnerRelationService mprService; + @Autowired + private PartTypeInformationSammMapper sammMapper; + + @GetMapping("/{bpnl}/{materialnumber}") + public ResponseEntity getMapping(@PathVariable String bpnl, @PathVariable String materialnumber) { + if (!bpnlPattern.matcher(bpnl).matches() || !materialNumberPattern.matcher(materialnumber).matches()) { + return ResponseEntity.badRequest().build(); + } + Partner partner = partnerService.findByBpnl(bpnl); + if (partner == null) { + return ResponseEntity.status(401).build(); + } + log.info(bpnl + " requests part type information on " + materialnumber); + Material material = materialService.findByOwnMaterialNumber(materialnumber); + if (material == null || !material.isProductFlag()) { + return ResponseEntity.status(404).build(); + } + var mpr = mprService.find(material, partner); + if (mpr == null || !mpr.isPartnerBuysMaterial()) { + return ResponseEntity.status(404).build(); + } + var samm = sammMapper.productToSamm(material); + return ResponseEntity.ok(samm); + } +} 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 13e2d31f..8cc49461 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 @@ -21,11 +21,14 @@ */ package org.eclipse.tractusx.puris.backend.masterdata.logic.service; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; 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; import org.eclipse.tractusx.puris.backend.common.util.VariablesService; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.MaterialPartnerRelation; @@ -60,9 +63,15 @@ public class MaterialPartnerRelationServiceImpl implements MaterialPartnerRelati @Autowired private DtrAdapterService dtrAdapterService; + @Autowired + private EdcAdapterService edcAdapterService; + @Autowired private ExecutorService executorService; + @Autowired + private ObjectMapper objectMapper; + /** * Stores the given relation to the database. * @@ -76,12 +85,67 @@ public MaterialPartnerRelation create(MaterialPartnerRelation materialPartnerRel if (searchResult == null) { dtmService.update(materialPartnerRelation); executorService.submit(new DtrRegistrationTask(materialPartnerRelation, "CREATE", 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, 3)); + } return mprRepository.save(materialPartnerRelation); } log.error("Could not create MaterialPartnerRelation, " + materialPartnerRelation.getKey() + " already exists"); return null; } + @AllArgsConstructor + private class PartTypeInformationRetrievalTask implements Callable { + final MaterialPartnerRelation materialPartnerRelation; + int retries; + + @Override + public Boolean call() throws Exception { + Thread.sleep(100); + if (retries < 0) { + log.warn("PartTypeInformation fetch from " + materialPartnerRelation.getPartner().getBpnl() + + " for " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + " failed"); + return false; + } + String[] data = edcAdapterService.getContractForPartTypeInfoApi(materialPartnerRelation.getPartner()); + if (data != null) { + String authKey = data[0]; + String authCode = data[1]; + String endpoint = data[2]; + var response = edcAdapterService.getProxyPullRequest(endpoint, authKey, authCode, + new String[]{materialPartnerRelation.getPartnerMaterialNumber()}); + if (response != null && response.isSuccessful()) { + var body = objectMapper.readTree(response.body().string()); + var cxId = body.get("catenaXId").asText(); + if (cxId != null && PatternStore.URN_OR_UUID_PATTERN.matcher(cxId).matches()) { + materialPartnerRelation.setPartnerCXNumber(cxId); + var updatedMpr = mprRepository.save(materialPartnerRelation); + if (updatedMpr != null) { + log.info("Successfully inserted Partner CX Id for Partner " + + materialPartnerRelation.getPartner().getBpnl() + " and Material " + + materialPartnerRelation.getMaterial().getOwnMaterialNumber()); + } + } + } else { + log.warn("PartTypeInformation fetch from " + materialPartnerRelation.getPartner().getBpnl() + + " for " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + " failed. Retries left: " + retries); + retries--; + return call(); + } + return true; + } else { + log.warn("PartTypeInformation fetch from " + materialPartnerRelation.getPartner().getBpnl() + + " for " + materialPartnerRelation.getMaterial().getOwnMaterialNumber() + " failed. Retries left: " + retries); + retries--; + return call(); + } + + } + } + @AllArgsConstructor private class DtrRegistrationTask implements Callable { @@ -100,7 +164,7 @@ public Boolean call() throws Exception { if (retries < 0) { return false; } - if (materialPartnerRelation.getPartnerCXNumber() == null){ + if (materialPartnerRelation.getPartnerCXNumber() == null) { log.error("Missing partnerCX Number in " + materialPartnerRelation + "\nAborting DTR call"); return false; } @@ -111,7 +175,7 @@ public Boolean call() throws Exception { if (materialPartnerRelation.getMaterial().isProductFlag()) { var allCustomers = mprRepository.findAllByMaterial_OwnMaterialNumberAndPartnerBuysMaterialIsTrue( - materialPartnerRelation.getMaterial().getOwnMaterialNumber()). + materialPartnerRelation.getMaterial().getOwnMaterialNumber()). stream().filter(mpr -> mpr.getPartnerCXNumber() != null).toList(); boolean result = dtrAdapterService.updateProduct(materialPartnerRelation.getMaterial(), allCustomers); if (result) { @@ -164,7 +228,7 @@ public Boolean call() throws Exception { } } if (success) { - return true; + return true; } else { retries--; return call(); @@ -184,6 +248,12 @@ public MaterialPartnerRelation update(MaterialPartnerRelation materialPartnerRel var foundEntity = mprRepository.findById(materialPartnerRelation.getKey()); if (foundEntity.isPresent()) { dtmService.update(materialPartnerRelation); + 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)); + } if (!foundEntity.get().isPartnerSuppliesMaterial() && materialPartnerRelation.isPartnerSuppliesMaterial()) { executorService.submit(new DtrRegistrationTask(materialPartnerRelation, "CREATE", 3)); } else { diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 9243ea17..0915055f 100755 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -13,6 +13,7 @@ puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:FrameworkAgreement.traceability} puris.api.key=${PURIS_API_KEY:test} puris.dtr.url=${PURIS_DTR_URL:http://localhost:4243} +puris.parttypeinformation.serverendpoint=${PURIS_PARTTYPEINFORMATION_SERVERENDPOINT:http://customer-backend:8081/catena/parttype} # 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 diff --git a/backend/src/test/resources/application.properties b/backend/src/test/resources/application.properties index 66860332..cc5d74d1 100755 --- a/backend/src/test/resources/application.properties +++ b/backend/src/test/resources/application.properties @@ -13,6 +13,7 @@ puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:FrameworkAgreement.traceability} puris.api.key=${PURIS_API_KEY:test} puris.dtr.url=${PURIS_DTR_URL:http://localhost:4243} +puris.parttypeinformation.serverendpoint=${PURIS_PARTTYPEINFORMATION_SERVERENDPOINT:http://customer-backend:8081/catena/parttype} puris.generatematerialcatenaxid=${PURIS_GENERATEMATERIALCATENAXID:true} # DB Configuration diff --git a/local/tractus-x-edc/config/customer/puris-backend.properties b/local/tractus-x-edc/config/customer/puris-backend.properties index 75d33430..d86b1d91 100644 --- a/local/tractus-x-edc/config/customer/puris-backend.properties +++ b/local/tractus-x-edc/config/customer/puris-backend.properties @@ -12,6 +12,7 @@ puris.frameworkagreement.use=true puris.frameworkagreement.credential=FrameworkAgreement.traceability puris.api.key=${CUSTOMER_BACKEND_API_KEY} puris.dtr.url=http://dtr-customer:4243 +puris.parttypeinformation.serverendpoint=http://customer-backend:8081/catena/parttype puris.generatematerialcatenaxid=true edc.controlplane.key=${EDC_API_PW} diff --git a/local/tractus-x-edc/config/supplier/puris-backend.properties b/local/tractus-x-edc/config/supplier/puris-backend.properties index 9dffbda7..139cdb21 100644 --- a/local/tractus-x-edc/config/supplier/puris-backend.properties +++ b/local/tractus-x-edc/config/supplier/puris-backend.properties @@ -12,6 +12,7 @@ puris.frameworkagreement.use=true puris.frameworkagreement.credential=FrameworkAgreement.traceability puris.api.key=${SUPPLIER_BACKEND_API_KEY} puris.dtr.url=http://dtr-supplier:4243 +puris.parttypeinformation.serverendpoint=http://supplier-backend:8082/catena/parttype puris.generatematerialcatenaxid=true edc.controlplane.key=${EDC_API_PW}