Skip to content

Commit

Permalink
Merge pull request eclipse-tractusx#382 from FraunhoferISST/fix/dtrco…
Browse files Browse the repository at this point in the history
…ntract_reusage

Fix/dtrcontract reusage
  • Loading branch information
tom-rm-meyer-ISST authored May 24, 2024
2 parents 138c358 + b88aece commit 297e5c9
Show file tree
Hide file tree
Showing 16 changed files with 196 additions and 138 deletions.
2 changes: 1 addition & 1 deletion backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</parent>
<groupId>org.eclipse.tractusx.puris</groupId>
<artifactId>puris-backend</artifactId>
<version>2.0.0</version>
<version>2.0.1</version>
<name>puris-backend</name>
<description>PURIS Backend</description>
<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,18 @@ public Integer updateProduct(Material material, List<MaterialPartnerRelation> 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.
* <p>
* 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<MaterialPartnerRelation> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
* <p>
* Method assumes that the query at dtr only finds one shell (else take first entry)
*
Expand All @@ -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);
Expand All @@ -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());
Expand Down Expand Up @@ -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());
Expand All @@ -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());
}
Expand All @@ -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);
}
Expand All @@ -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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,12 @@ public class DeliveryInformationSammMapper {
@Autowired
private MaterialService materialService;

public DeliveryInformation ownDeliveryToSamm(List<OwnDelivery> 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<OwnDelivery> 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -39,6 +35,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
@Slf4j
/**
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,7 @@ public class ShortTermMaterialDemandSammMapper {
@Autowired
private MaterialService materialService;

public ShortTermMaterialDemand ownDemandToSamm(List<OwnDemand> 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<OwnDemand> 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;
Expand Down
Loading

0 comments on commit 297e5c9

Please sign in to comment.