diff --git a/charts/digital-product-pass/values-beta.yaml b/charts/digital-product-pass/values-beta.yaml index d8ffaa0f7..c6af5e7e9 100644 --- a/charts/digital-product-pass/values-beta.yaml +++ b/charts/digital-product-pass/values-beta.yaml @@ -144,10 +144,10 @@ backend: temporaryStorage: true discovery: - endpoint: "https://semantics.beta.demo.catena-x.net/discoveryfinder/api/administration/connectors/discovery/search" + endpoint: "https://semantics.beta.demo.catena-x.net/discoveryfinder/api/v1.0/administration/connectors/discovery/search" bpn: key: "manufacturerPartId" - searchPath: "/api/administration/connectors/bpnDiscovery/search" + searchPath: "/api/v1.0/administration/connectors/bpnDiscovery/search" edc: key: "bpn" diff --git a/charts/digital-product-pass/values-dev.yaml b/charts/digital-product-pass/values-dev.yaml index ecd2d910d..6da0d67b4 100644 --- a/charts/digital-product-pass/values-dev.yaml +++ b/charts/digital-product-pass/values-dev.yaml @@ -128,7 +128,7 @@ backend: dtr: central: false centralUrl: 'https://semantics.dev.demo.catena-x.net/registry' - assetId: 'digital-twin-registry' + assetId: 'registry-asset' dspEndpointKey: 'dspEndpoint' endpointInterface: 'SUBMODEL-3.0' internalDtr: "https://materialpass.dev.demo.catena-x.net/BPNL000000000000" # -- If there is an internal DTR available it can be referenced here and will be injected in the list of DTRs @@ -144,10 +144,10 @@ backend: temporaryStorage: true discovery: - endpoint: "https://semantics.dev.demo.catena-x.net/discoveryfinder/api/administration/connectors/discovery/search" + endpoint: "https://semantics.dev.demo.catena-x.net/discoveryfinder/api/v1.0/administration/connectors/discovery/search" bpn: key: "manufacturerPartId" - searchPath: "/api/administration/connectors/bpnDiscovery/search" + searchPath: "/api/v1.0/administration/connectors/bpnDiscovery/search" edc: key: "bpn" diff --git a/charts/digital-product-pass/values-int.yaml b/charts/digital-product-pass/values-int.yaml index a06a4b030..791bcf9f0 100644 --- a/charts/digital-product-pass/values-int.yaml +++ b/charts/digital-product-pass/values-int.yaml @@ -126,7 +126,7 @@ backend: dtr: central: false centralUrl: 'https://semantics.int.demo.catena-x.net/registry' - assetId: 'digital-twin-registry' + assetId: 'registry-asset' dspEndpointKey: 'dspEndpoint' endpointInterface: 'SUBMODEL-3.0' internalDtr: "https://materialpass.int.demo.catena-x.net/BPNL000000000000" # -- If there is an internal DTR available it can be referenced here and will be injected in the list of DTRs @@ -142,10 +142,10 @@ backend: temporaryStorage: true discovery: - endpoint: "https://semantics.int.demo.catena-x.net/discoveryfinder/api/administration/connectors/discovery/search" + endpoint: "https://semantics.int.demo.catena-x.net/discoveryfinder/api/v1.0/administration/connectors/discovery/search" bpn: key: "manufacturerPartId" - searchPath: "/api/administration/connectors/bpnDiscovery/search" + searchPath: "/api/v1.0/administration/connectors/bpnDiscovery/search" edc: key: "bpn" diff --git a/charts/digital-product-pass/values.yaml b/charts/digital-product-pass/values.yaml index 377de0444..4272b743c 100644 --- a/charts/digital-product-pass/values.yaml +++ b/charts/digital-product-pass/values.yaml @@ -149,7 +149,7 @@ backend: # -- central digital twin registry url centralUrl: 'https://' # -- asset id to search for the registry in the edc - assetId: 'digital-twin-registry' + assetId: 'registry-asset' # -- submodel endpoint interface to search endpointInterface: 'SUBMODEL-3.0' # -- dsp endpoint key inside submodel body @@ -171,11 +171,11 @@ backend: # -- discovery configuration discovery: # -- discovery finder configuration - endpoint: "https:///discoveryfinder/api/administration/connectors/discovery/search" + endpoint: "https:///discoveryfinder/api/v1.0/administration/connectors/discovery/search" # -- bpn discovery configuration bpn: key: "manufacturerPartId" - searchPath: "/api/administration/connectors/bpnDiscovery/search" + searchPath: "/api/v1.0/administration/connectors/bpnDiscovery/search" # -- edc discovery configuration edc: key: "bpn" diff --git a/consumer-backend/productpass/pom.xml b/consumer-backend/productpass/pom.xml index 87e550318..05270a8eb 100644 --- a/consumer-backend/productpass/pom.xml +++ b/consumer-backend/productpass/pom.xml @@ -33,7 +33,7 @@ org.eclipse.tractusx productpass - 1.1.0 + 1.2.0 jar Catena-X Digital Product Passport Backend Product Passport Consumer Backend System for Product Passport Consumer Frontend Application diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/DtrConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/DtrConfig.java index 28eaea104..4b0557509 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/DtrConfig.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/DtrConfig.java @@ -49,10 +49,24 @@ public class DtrConfig { String endpointInterface; String dspEndpointKey; + String semanticIdTypeKey; /** CONSTRUCTOR(S) **/ public DtrConfig() { } + public DtrConfig(Boolean central, String centralUrl, String internalDtr, Timeouts timeouts, Boolean temporaryStorage, DecentralApis decentralApis, String assetId, String endpointInterface, String dspEndpointKey, String semanticIdTypeKey) { + this.central = central; + this.centralUrl = centralUrl; + this.internalDtr = internalDtr; + this.timeouts = timeouts; + this.temporaryStorage = temporaryStorage; + this.decentralApis = decentralApis; + this.assetId = assetId; + this.endpointInterface = endpointInterface; + this.dspEndpointKey = dspEndpointKey; + this.semanticIdTypeKey = semanticIdTypeKey; + } + /** GETTERS AND SETTERS **/ public DecentralApis getDecentralApis() { return decentralApis; @@ -113,6 +127,14 @@ public void setAssetId(String assetId) { this.assetId = assetId; } + public String getSemanticIdTypeKey() { + return semanticIdTypeKey; + } + + public void setSemanticIdTypeKey(String semanticIdTypeKey) { + this.semanticIdTypeKey = semanticIdTypeKey; + } + /** INNER CLASSES **/ /** diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/PassportConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/PassportConfig.java index 6e844c1ee..66ee91440 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/PassportConfig.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/PassportConfig.java @@ -35,94 +35,21 @@ @ConfigurationProperties(prefix="configuration.passport") public class PassportConfig { - /** ATTRIBUTES **/ - private BatteryPass batteryPass; - private DigitalProductPass digitalProductPass; + private List aspects; - /** GETTERS AND SETTERS **/ - public BatteryPass getBatteryPass() { - return batteryPass; - } - public void setBatteryPass(BatteryPass batteryPass) { - this.batteryPass = batteryPass; - } - public DigitalProductPass getDigitalProductPass() { - return digitalProductPass; - } - public void setDigitalProductPass(DigitalProductPass digitalProductPass) { - this.digitalProductPass = digitalProductPass; + public PassportConfig() { } - /** INNER CLASSES **/ - - /** - * This class consists exclusively to define the attributes and methods needed for the BatterPass configuration. - **/ - public static class BatteryPass extends DigitalProductPass { + public PassportConfig(List aspects) { + this.aspects = aspects; } - /** - * This class consists exclusively to define the attributes and methods needed for the DigitalProductPass configuration. - **/ - public static class DigitalProductPass { - - /** ATTRIBUTES **/ - private List versions; - private String semanticId; - private String aspectId; - private String fullSemanticId; - - /** CONSTRUCTOR(S) **/ - @SuppressWarnings("Unused") - public DigitalProductPass(List versions, String semanticId, String aspectId) { - this.versions = versions; - this.semanticId = semanticId; - this.aspectId = aspectId; - } - - public DigitalProductPass() { - } - - /** GETTERS AND SETTERS **/ - public List getVersions() { - return this.versions; - } - public void setVersions(List versions) { - this.versions = versions; - } - public String getSemanticId() { - return semanticId; - } - public void setSemanticId(String semanticId) { - this.semanticId = semanticId; - } - @SuppressWarnings("Unused") - public String getAspectId() { - return aspectId; - } - @SuppressWarnings("Unused") - public void setAspectId(String aspectId) { - this.aspectId = aspectId; - } - - /** METHODS **/ - - /** - * Builds the semanticId to search the submodel inside the Digital twin. - * It concatenates the semanticId, the passport version and the aspectId. - *

- * @param version - * the {@code String} intended passport's version . - * - * @return this {@code String} with the built semanticId. - * - */ - public String getFullSemanticId(String version) { - if (this.fullSemanticId == null) { - this.fullSemanticId = semanticId + ":" + versions.stream().filter(v -> v.equalsIgnoreCase(version)).findFirst().get() + "#" + aspectId; - } - return fullSemanticId; - } + public List getAspects() { + return aspects; + } + public void setAspects(List aspects) { + this.aspects = aspects; } + } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/AppController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/AppController.java index 9a031afc8..efb88f1a2 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/AppController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/AppController.java @@ -23,6 +23,7 @@ package org.eclipse.tractusx.productpass.http.controllers; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -34,8 +35,6 @@ import org.eclipse.tractusx.productpass.config.DtrConfig; import org.eclipse.tractusx.productpass.config.ProcessConfig; import org.eclipse.tractusx.productpass.exceptions.ControllerException; -import org.eclipse.tractusx.productpass.exceptions.DataModelException; -import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.managers.ProcessManager; import org.eclipse.tractusx.productpass.models.catenax.Dtr; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; @@ -48,7 +47,6 @@ import org.eclipse.tractusx.productpass.models.manager.History; import org.eclipse.tractusx.productpass.models.manager.SearchStatus; import org.eclipse.tractusx.productpass.models.manager.Status; -import org.eclipse.tractusx.productpass.models.passports.Passport; import org.eclipse.tractusx.productpass.services.AasService; import org.eclipse.tractusx.productpass.services.DataPlaneService; import org.springframework.beans.factory.annotation.Autowired; @@ -57,6 +55,7 @@ import utils.*; import java.util.Map; +import java.util.Objects; /** * This class consists exclusively to define the HTTP methods of the Application's controller. @@ -179,9 +178,12 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr String connectorId = null; String assetId = null; String connectorAddress = null; + String semanticId = null; + try { digitalTwin = digitalTwinRegistry.getDigitalTwin(); subModel = digitalTwinRegistry.getSubModel(); + semanticId = Objects.requireNonNull(subModel.getSemanticId().getKeys().stream().filter(k -> k.getType().equalsIgnoreCase(this.dtrConfig.getSemanticIdTypeKey())).findFirst().orElse(null)).getValue(); connectorId = subModel.getIdShort(); EndPoint3 endpoint = subModel.getEndpoints().stream().filter(obj -> obj.getInterfaceName().equals(dtrConfig.getEndpointInterface())).findFirst().orElse(null); if (endpoint == null) { @@ -207,6 +209,7 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr } processManager.setEndpoint(processId, connectorAddress); processManager.setBpn(processId, dtr.getBpn()); + processManager.setSemanticId(processId, semanticId); processManager.saveDigitalTwin3(processId, digitalTwin, dtRequestTime); LogUtil.printDebug("[PROCESS " + processId + "] Digital Twin [" + digitalTwin.getIdentification() + "] and Submodel [" + subModel.getIdentification() + "] with EDC endpoint [" + connectorAddress + "] retrieved from DTR"); processManager.setStatus(processId, "digital-twin-found", new History( @@ -285,7 +288,7 @@ public Response endpoint(@RequestBody Object body, @PathVariable String processI return httpUtil.buildResponse(httpUtil.getNotFound("Process not found!"), httpResponse); } - Passport passport = dataPlaneService.getPassport(endpointData); + JsonNode passport = dataPlaneService.getPassport(endpointData); if (passport == null) { return httpUtil.buildResponse(httpUtil.getNotFound("Passport not found in data plane!"), httpResponse); } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ApiController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ApiController.java index ea59c2aac..25cb2e9b8 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ApiController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ApiController.java @@ -23,6 +23,7 @@ package org.eclipse.tractusx.productpass.http.controllers.api; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -41,9 +42,7 @@ import org.eclipse.tractusx.productpass.models.manager.Process; import org.eclipse.tractusx.productpass.models.manager.Status; import org.eclipse.tractusx.productpass.models.negotiation.Dataset; -import org.eclipse.tractusx.productpass.models.passports.Passport; import org.eclipse.tractusx.productpass.models.passports.PassportResponse; -import org.eclipse.tractusx.productpass.models.passports.PassportV3; import org.eclipse.tractusx.productpass.services.AasService; import org.eclipse.tractusx.productpass.services.AuthenticationService; import org.eclipse.tractusx.productpass.services.DataTransferService; @@ -100,16 +99,14 @@ Response index() throws Exception { * @return this {@code Response} HTTP response with status. * */ - @RequestMapping(value = "/passport", method = {RequestMethod.POST}) - @Operation(summary = "Returns versioned product passport by id", responses = { + @RequestMapping(value = "/data", method = {RequestMethod.POST}) + @Operation(summary = "Returns the data negotiated and transferred", responses = { @ApiResponse(description = "Default Response Structure", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))), @ApiResponse(description = "Content of Data Field in Response", responseCode = "200", content = @Content(mediaType = "application/json", schema = @Schema(implementation = PassportResponse.class))), - @ApiResponse(description = "Content of Passport Field in Data Field", useReturnTypeSchema = true, content = @Content(mediaType = "application/json", - schema = @Schema(implementation = PassportV3.class))) }) - public Response getPassport(@Valid @RequestBody TokenRequest tokenRequestBody) { + public Response getData(@Valid @RequestBody TokenRequest tokenRequestBody) { Response response = httpUtil.getInternalError(); // Check for authentication @@ -172,24 +169,17 @@ public Response getPassport(@Valid @RequestBody TokenRequest tokenRequestBody) { return httpUtil.buildResponse(response, httpResponse); } - if (!status.historyExists("passport-received")) { - response = httpUtil.getNotFound("The passport is not available!"); + if (!status.historyExists("data-received")) { + response = httpUtil.getNotFound("The data is not available!"); return httpUtil.buildResponse(response, httpResponse); } - if (status.historyExists("passport-retrieved")) { - response = httpUtil.getNotFound("The passport was already retrieved and is no longer available!"); + if (status.historyExists("data-retrieved")) { + response = httpUtil.getNotFound("The data was already retrieved and is no longer available!"); return httpUtil.buildResponse(response, httpResponse); } - - Passport passport; - if (process.getIsDigitalProductPass()) { - passport = processManager.loadDigitalProductPassport(processId); - } else { - passport = processManager.loadPassport(processId); - } - - + String semanticId = status.getSemanticId(); + JsonNode passport = processManager.loadPassport(processId); if (passport == null) { response = httpUtil.getNotFound("Failed to load passport!"); return httpUtil.buildResponse(response, httpResponse); @@ -204,7 +194,8 @@ public Response getPassport(@Valid @RequestBody TokenRequest tokenRequestBody) { "negotiation", negotiation, "transfer", transfer ), - "passport", passport + "aspect", passport, + "semanticId", semanticId ); return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ContractController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ContractController.java index f0de061da..5133284db 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ContractController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/ContractController.java @@ -62,6 +62,7 @@ import utils.JsonUtil; import utils.LogUtil; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -133,22 +134,25 @@ public Response create(@Valid @RequestBody DiscoverySearch searchBody) { return httpUtil.buildResponse(response, httpResponse); } - BpnDiscovery bpnDiscovery = null; + List bpnDiscoveries = null; try { - bpnDiscovery = catenaXService.getBpnDiscovery(searchBody.getId(), searchBody.getType()); + bpnDiscoveries = catenaXService.getBpnDiscovery(searchBody.getId(), searchBody.getType()); } catch (Exception e) { response.message = "Failed to get the bpn number from the discovery service"; response.status = 404; response.statusText = "Not Found"; return httpUtil.buildResponse(response, httpResponse); } - if (bpnDiscovery == null) { + if (bpnDiscoveries == null) { response.message = "Failed to get the bpn number from the discovery service, discovery response is null"; response.status = 404; response.statusText = "Not Found"; return httpUtil.buildResponse(response, httpResponse); } - List bpnList = bpnDiscovery.getBpnNumbers(); + List bpnList = new ArrayList<>(); + for(BpnDiscovery bpnDiscovery : bpnDiscoveries){ + bpnList.addAll(bpnDiscovery.getBpnNumbers()); + } String processId = processManager.initProcess(); ConcurrentHashMap> dataModel = null; List edcEndpointBinded = null; @@ -161,7 +165,7 @@ public Response create(@Valid @RequestBody DiscoverySearch searchBody) { } // This checks if the cache is deactivated or if the bns are not in thedataModel, if one of them is not in the data model then we need to check for them if(!dtrConfig.getTemporaryStorage() || ((dataModel==null) || !jsonUtil.checkJsonKeys(dataModel, bpnList, ".", false))){ - List edcEndpoints = catenaXService.getEdcDiscovery(bpnDiscovery.getBpnNumbers()); + List edcEndpoints = catenaXService.getEdcDiscovery(bpnList); try { edcEndpointBinded = (List) jsonUtil.bindReferenceType(edcEndpoints, new TypeReference>() {}); } catch (Exception e) { @@ -239,30 +243,21 @@ public Response search(@Valid @RequestBody Search searchBody) { return httpUtil.buildResponse(response, httpResponse); } try { - List mandatoryParams = List.of("id", "version"); + List mandatoryParams = List.of("id"); if (!jsonUtil.checkJsonKeys(searchBody, mandatoryParams, ".", false)) { response = httpUtil.getBadRequest("One or all the mandatory parameters " + mandatoryParams + " are missing"); return httpUtil.buildResponse(response, httpResponse); } List versions; - boolean isDigitalProductPass; - if (searchBody.getIdShort().equalsIgnoreCase("digitalProductPass")) { + /*if (searchBody.getIdShort().equalsIgnoreCase("digitalProductPass")) { versions = passportConfig.getDigitalProductPass().getVersions(); searchBody.setSemanticId(passportConfig.getDigitalProductPass().getFullSemanticId(versions.get(0))); LogUtil.printWarning("SEMANTID ID: " + passportConfig.getDigitalProductPass().getFullSemanticId(versions.get(0))); - isDigitalProductPass = true; } else { versions = passportConfig.getBatteryPass().getVersions(); searchBody.setSemanticId(passportConfig.getBatteryPass().getFullSemanticId(versions.get(0))); - isDigitalProductPass = false; - } - - // Initialize variables - // Check if version is available - if (!versions.contains(searchBody.getVersion())) { - return httpUtil.buildResponse(httpUtil.getForbiddenResponse("This passport version is not available at the moment!"), httpResponse); - } + }*/ Process process = null; AssetSearch assetSearch = null; @@ -283,7 +278,6 @@ public Response search(@Valid @RequestBody Search searchBody) { return httpUtil.buildResponse(response, httpResponse); } process = processManager.createProcess(processId, httpRequest); - process.setIsDigitalProductPass(isDigitalProductPass); Status status = processManager.getStatus(processId); if (status == null) { response = httpUtil.getBadRequest("The status is not available!"); @@ -469,7 +463,7 @@ public Response cancel(@Valid @RequestBody TokenRequest tokenRequestBody) { return httpUtil.buildResponse(response, httpResponse); } - if (status.getStatus().equals("COMPLETED") || status.getStatus().equals("RETRIEVED") || status.historyExists("transfer-request") || status.historyExists("transfer-completed") || status.historyExists("passport-received") || status.historyExists("passport-retrieved")) { + if (status.getStatus().equals("COMPLETED") || status.getStatus().equals("RETRIEVED") || status.historyExists("transfer-request") || status.historyExists("transfer-completed") || status.historyExists("data-received") || status.historyExists("data-retrieved")) { response = httpUtil.getForbiddenResponse("This negotiation can not be canceled! It was already transferred!"); return httpUtil.buildResponse(response, httpResponse); } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/ProcessManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/ProcessManager.java index 7661feddf..4cd51c9f7 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/ProcessManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/ProcessManager.java @@ -25,10 +25,10 @@ package org.eclipse.tractusx.productpass.managers; +import com.fasterxml.jackson.databind.JsonNode; import jakarta.servlet.http.HttpServletRequest; import org.eclipse.tractusx.productpass.config.ProcessConfig; import org.eclipse.tractusx.productpass.exceptions.ManagerException; -import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.models.catenax.Dtr; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; @@ -41,16 +41,12 @@ import org.eclipse.tractusx.productpass.models.manager.SearchStatus; import org.eclipse.tractusx.productpass.models.manager.Status; import org.eclipse.tractusx.productpass.models.negotiation.*; -import org.eclipse.tractusx.productpass.models.passports.DigitalProductPassport; -import org.eclipse.tractusx.productpass.models.passports.Passport; -import org.eclipse.tractusx.productpass.models.passports.PassportV3; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import utils.*; import java.nio.file.Path; -import java.util.List; import java.util.Map; /** @@ -559,6 +555,7 @@ public Process createProcess(HttpServletRequest httpRequest, String processId, S * @throws ManagerException * if unable to create the status file. */ + public String newStatusFile(String processId, String connectorAddress, Long created){ try { String path = this.getProcessFilePath(processId, this.metaFileName); @@ -659,6 +656,23 @@ public String setBpn(String processId, String bpn) { } } + public String setSemanticId(String processId, String semanticId) { + try { + String path = this.getProcessFilePath(processId, this.metaFileName); + Status statusFile = null; + if (!fileUtil.pathExists(path)) { + throw new ManagerException(this.getClass().getName(), "Process file does not exists for id ["+processId+"]!"); + } + + statusFile = (Status) jsonUtil.fromJsonFileToObject(path, Status.class); + statusFile.setSemanticId(semanticId); + statusFile.setModified(DateTimeUtil.getTimestamp()); + return jsonUtil.toJsonFile(path, statusFile, processConfig.getIndent()); // Store the plain JSON + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "It was not possible to set the semanticId!"); + } + } + /** * Sets the history of the process's status containing the given processId. *

@@ -950,7 +964,7 @@ public String saveProcessPayload(String processId, Object payload, String fileNa this.setStatus(processId, eventKey, history); String path = this.getProcessFilePath(processId, fileName); String returnPath = ""; - if(eventKey.equals("passport-received") && encrypt) { + if(eventKey.equals("data-received") && encrypt) { returnPath = fileUtil.toFile(path, payload.toString(), false); }else { returnPath = jsonUtil.toJsonFile(path, payload, processConfig.getIndent()); @@ -1189,7 +1203,7 @@ public String getContractId(DataPlaneEndpoint endpointData){ * @throws ManagerException * if unable to load the passport. */ - public PassportV3 loadPassport(String processId){ + public JsonNode loadPassport(String processId){ try { String path = this.getProcessFilePath(processId, this.passportFileName); History history = new History( @@ -1199,7 +1213,7 @@ public PassportV3 loadPassport(String processId){ if(!fileUtil.pathExists(path)){ throw new ManagerException(this.getClass().getName(), "Passport file ["+path+"] not found!"); } - PassportV3 passport = null; + JsonNode passport = null; Boolean encrypt = env.getProperty("passport.dataTransfer.encrypt", Boolean.class, true); if(encrypt){ Status status = this.getStatus(processId); @@ -1207,9 +1221,9 @@ public PassportV3 loadPassport(String processId){ String decryptedPassportJson = CrypUtil.decryptAes(fileUtil.readFile(path), this.generateStatusToken(status, negotiationHistory.getId())); // Delete passport file - passport = (PassportV3) jsonUtil.loadJson(decryptedPassportJson, PassportV3.class); + passport = (JsonNode) jsonUtil.loadJson(decryptedPassportJson, JsonNode.class); }else{ - passport = (PassportV3) jsonUtil.fromJsonFileToObject(path, PassportV3.class); + passport = (JsonNode) jsonUtil.fromJsonFileToObject(path, JsonNode.class); } if(passport == null){ @@ -1225,67 +1239,13 @@ public PassportV3 loadPassport(String processId){ LogUtil.printStatus("[PROCESS " + processId +"] Failed to delete passport file!"); } - this.setStatus(processId,"passport-retrieved", history); + this.setStatus(processId,"data-retrieved", history); return passport; } catch (Exception e) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to load the passport!"); } } - /** - * Loads the transferred digital product passport of the Process with the given processId after the negotiations being succeeded. - *

- * @param processId - * the {@code String} id of the application's process. - * - * @return a {@code DigitalProductPassport} object with the loaded passport data. - * - * @throws ManagerException - * if unable to load the digital product passport. - */ - public DigitalProductPassport loadDigitalProductPassport(String processId){ - try { - String path = this.getProcessFilePath(processId, this.passportFileName); - History history = new History( - processId, - "RETRIEVED" - ); - if(!fileUtil.pathExists(path)){ - throw new ManagerException(this.getClass().getName(), "Digital Product Passport file ["+path+"] not found!"); - } - DigitalProductPassport passport = null; - Boolean encrypt = env.getProperty("passport.dataTransfer.encrypt", Boolean.class, true); - if(encrypt){ - Status status = this.getStatus(processId); - History negotiationHistory = status.getHistory("negotiation-accepted"); - String decryptedPassportJson = CrypUtil.decryptAes(fileUtil.readFile(path), this.generateStatusToken(status, negotiationHistory.getId())); - // Delete passport file - - passport = (DigitalProductPassport) jsonUtil.loadJson(decryptedPassportJson, DigitalProductPassport.class); - }else{ - passport = (DigitalProductPassport) jsonUtil.fromJsonFileToObject(path, DigitalProductPassport.class); - } - - if(passport == null){ - throw new ManagerException(this.getClass().getName(), "Failed to load the passport"); - } - Boolean deleteResponse = fileUtil.deleteFile(path); - - if(deleteResponse==null){ - LogUtil.printStatus("[PROCESS " + processId +"] Digital Product file not found, failed to delete!"); - } else if (deleteResponse) { - LogUtil.printStatus("[PROCESS " + processId +"] Digital Product file deleted successfully!"); - } else{ - LogUtil.printStatus("[PROCESS " + processId +"] Failed to delete digital product passport file!"); - } - - this.setStatus(processId,"passport-retrieved", history); - return passport; - } catch (Exception e) { - throw new ManagerException(this.getClass().getName(), e, "It was not possible to load the digital product passport!"); - } - } - /** * Saves the given Passport in the Process with the given processId encrypted with a token generated by * data extracted from the {@code DataPlaneEndpoint} object. @@ -1302,7 +1262,7 @@ public DigitalProductPassport loadDigitalProductPassport(String processId){ * @throws ManagerException * if unable to save the passport. */ - public String savePassport(String processId, DataPlaneEndpoint endpointData, Passport passport) { + public String savePassport(String processId, DataPlaneEndpoint endpointData, JsonNode passport) { try { // Retrieve the configuration Boolean prettyPrint = env.getProperty("passport.dataTransfer.indent", Boolean.class, true); @@ -1325,7 +1285,7 @@ public String savePassport(String processId, DataPlaneEndpoint endpointData, Pas this.passportFileName, endpointData.getId(), "RECEIVED", - "passport-received"); + "data-received"); } catch (Exception e) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to save the digital product passport!"); } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/SubModel3.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/SubModel3.java index 7eb919a20..8f42f5286 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/SubModel3.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/SubModel3.java @@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.JsonNode; import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -43,12 +44,15 @@ public class SubModel3 { ArrayList description; @JsonProperty("idShort") String idShort; + @JsonProperty("supplementalSemanticId") Object supplementalSemanticId; + @JsonProperty("id") String identification; @JsonProperty("semanticId") SemanticId semanticId; + @JsonProperty("endpoints") ArrayList endpoints; @@ -78,15 +82,19 @@ public SubModel3(ArrayList description, String idShort, Object supplem public ArrayList getDescription() { return description; } + public void setDescription(ArrayList description) { this.description = description; } + public String getIdShort() { return idShort; } + public void setIdShort(String idShort) { this.idShort = idShort; } + public String getIdentification() { return identification; } @@ -94,15 +102,19 @@ public String getIdentification() { public void setIdentification(String identification) { this.identification = identification; } + public SemanticId getSemanticId() { return semanticId; } + public void setSemanticId(SemanticId semanticId) { this.semanticId = semanticId; } + public ArrayList getEndpoints() { return endpoints; } + public void setEndpoints(ArrayList endpoints) { this.endpoints = endpoints; } @@ -125,11 +137,11 @@ public static class SemanticId { @JsonProperty("type") String type; @JsonProperty("keys") - Map keys; + ArrayList keys; /** CONSTRUCTOR(S) **/ @SuppressWarnings("Unused") - public SemanticId(String type, Map keys) { + public SemanticId(String type, ArrayList keys) { this.type = type; this.keys = keys; } @@ -141,15 +153,46 @@ public SemanticId() { public String getType() { return type; } + public void setType(String type) { this.type = type; } - public Map getKeys() { + + public ArrayList getKeys() { return keys; } @SuppressWarnings("Unused") - public void setKeys(Map keys) { + public void setKeys(ArrayList keys) { this.keys = keys; } + + /** INNER CLASSES **/ + /** + * This class consists exclusively to define attributes related to the SemanticId's keys property. + **/ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + static public class Key { + + /** ATTRIBUTES **/ + @JsonProperty("type") + String type; + @JsonProperty("value") + String value; + + /** CONSTRUCTOR(S) **/ + public Key() {} + + public Key(String type, String value) { + this.type = type; + this.value = value; + } + + /** GETTERS AND SETTERS **/ + public String getType() { return type; } + public void setType(String type) { this.type = type; } + public String getValue() { return value; } + public void setValue(String value) { this.value = value; } + } } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Process.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Process.java index a32158401..f964fbf6d 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Process.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Process.java @@ -47,8 +47,6 @@ public class Process { public Long updated; @JsonProperty("thread") public Thread thread; - @JsonProperty("isDigitalProductPass") - private boolean isDigitalProductPass; /** CONSTRUCTOR(S) **/ public Process(String id, String state, Thread thread) { @@ -118,10 +116,5 @@ public Long getCreated() { public void setCreated(Long created) { this.created = created; } - public boolean getIsDigitalProductPass() { - return isDigitalProductPass; - } - public void setIsDigitalProductPass(boolean isDigitalProductPass) { - this.isDigitalProductPass = isDigitalProductPass; - } + } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Status.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Status.java index 459ed8763..9a33d44bc 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Status.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Status.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.boot.context.properties.bind.DefaultValue; import utils.DateTimeUtil; import java.util.HashMap; @@ -42,20 +43,31 @@ public class Status { /** ATTRIBUTES **/ @JsonProperty("id") public String id; + @JsonProperty("status") public String status; + @JsonProperty("created") public Long created; + @JsonProperty("modified") public Long modified; + + @JsonProperty("endpoint") public String endpoint; + @JsonProperty("bpn") public String bpn; + @JsonProperty("history") public Map history; /** CONSTRUCTOR(S) **/ + @JsonProperty("semanticId") + public String semanticId; + + @SuppressWarnings("Unused") public Status(String id, String status, Long created, Long modified, String endpoint, Map history) { this.id = id; @@ -101,6 +113,7 @@ public Status(String id, String status, String endpoint, Long modified) { this.endpoint = endpoint; this.history = new HashMap(); } + public Status(String id, String status, String endpoint, Long created, Long modified) { this.id = id; this.status = status; @@ -109,9 +122,11 @@ public Status(String id, String status, String endpoint, Long created, Long modi this.endpoint = endpoint; this.history = new HashMap(); } - @SuppressWarnings("Unused") - public Status() { + + public Status(Map history) { + this.history = history; } + @SuppressWarnings("Unused") public Status(String id, String status, Long created, Long modified) { this.id = id; @@ -159,40 +174,53 @@ public Status(String id, String status, Long created, Long modified, String endp this.history = Map.of(historyId, history); } + public Status() { + } + /** GETTERS AND SETTERS **/ public String getId() { return id; } + public void setId(String id) { this.id = id; } + public String getStatus() { return status; } + public void setStatus(String status) { this.status = status; } + public Long getCreated() { return created; } + public void setCreated(Long created) { this.created = created; } + public Long getModified() { return modified; } + public void setModified(Long modified) { this.modified = modified; } + public Map getHistory() { return history; } public Boolean historyExists(String name) { return this.history.containsKey(name); } + public void setHistory(Map history) { this.history = history; } + public void setHistory(String name, History history) { this.history.put(name, history); } @@ -211,18 +239,30 @@ public Boolean removeHistory(String name) { public History getHistory(String name) { return this.history.getOrDefault(name, null); } + public String getEndpoint() { return endpoint; } + public void setEndpoint(String endpoint) { this.endpoint = endpoint; } + public String getBpn() { return this.bpn; } + public void setBpn(String bpn) { this.bpn = bpn; } + + public String getSemanticId() { + return semanticId; + } + + public void setSemanticId(String semanticId) { + this.semanticId = semanticId; + } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/DataDestination.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/DataDestination.java deleted file mode 100644 index f46beaf7c..000000000 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/DataDestination.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.eclipse.tractusx.productpass.models.negotiation; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * This class consists exclusively to define attributes related to the Transfer's and Transfer request's data destination property. - **/ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class DataDestination { - - /** ATTRIBUTES **/ - @JsonProperty("edc:type") - String type; - - /** GETTERS AND SETTERS **/ - public String getType() { - return type; - } - public void setType(String type) { - this.type = type; - } -} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/Transfer.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/Transfer.java index fa5491284..ba2899a5b 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/Transfer.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/Transfer.java @@ -188,6 +188,18 @@ public void setConnectorId(String connectorId) { this.connectorId = connectorId; } } + @JsonInclude(JsonInclude.Include.NON_NULL) + static class DataDestination { + @JsonProperty("edc:type") + String type; + + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/TransferRequest.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/TransferRequest.java index 5eec26999..4b09917dc 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/TransferRequest.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/negotiation/TransferRequest.java @@ -152,4 +152,18 @@ public void setReceiverHttpEndpoint(String receiverHttpEndpoint) { this.receiverHttpEndpoint = receiverHttpEndpoint; } } + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class DataDestination { + @JsonProperty("type") + String type; + + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/DigitalProductPassport.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/DigitalProductPassport.java deleted file mode 100644 index 297704ec8..000000000 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/DigitalProductPassport.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.eclipse.tractusx.productpass.models.passports; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.JsonNode; - -/** - * This class consists exclusively to define attributes related to the designed model of the Digital Product Passport. - **/ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class DigitalProductPassport extends Passport { - @JsonProperty("serialization") - JsonNode serialization; - @JsonProperty("typology") - JsonNode typology; - @JsonProperty("metadata") - String metadata; - @JsonProperty("characteristics") - JsonNode characteristics; - @JsonProperty("commercial") - JsonNode commercial; - @JsonProperty("identification") - JsonNode identification; - @JsonProperty("sources") - JsonNode sources; - @JsonProperty("handling") - JsonNode handling; - @JsonProperty("additionalData") - String additionalData; - @JsonProperty("sustainability") - JsonNode sustainability; - @JsonProperty("operation") - JsonNode operation; -} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/Passport.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/Passport.java deleted file mode 100644 index 778396700..000000000 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/Passport.java +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************************* - * - * Catena-X - Product Passport Consumer Backend - * - * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the - * License for the specific language govern in permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -package org.eclipse.tractusx.productpass.models.passports; - -import com.fasterxml.jackson.annotation.JsonInclude; - -/** - * This class consists exclusively to define attributes and methods that are common to the passports used in the Application. - * Also used to perform polymorphism in the Application with all the passports that extends it. - **/ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Passport { - // Here will be included then next release Generic Passport Structure -} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/PassportResponse.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/PassportResponse.java index 84d5e15e9..5808c08fc 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/PassportResponse.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/PassportResponse.java @@ -36,10 +36,10 @@ public class PassportResponse { @JsonProperty("metadata") Map metadata; @JsonProperty("passport") - Passport passport; + JsonNode passport; @SuppressWarnings("Unused") - public PassportResponse(Map metadata, Passport passport) { + public PassportResponse(Map metadata, JsonNode passport) { this.metadata = metadata; this.passport = passport; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/PassportV3.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/PassportV3.java deleted file mode 100644 index 0af8ea6e7..000000000 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/passports/PassportV3.java +++ /dev/null @@ -1,72 +0,0 @@ -/********************************************************************************* - * - * Catena-X - Product Passport Consumer Backend - * - * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the - * License for the specific language govern in permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -package org.eclipse.tractusx.productpass.models.passports; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.JsonNode; - -/** - * This class consists exclusively to define attributes related to the designed model of the Passport v3.0.1. - * - * * =======[DESCRIPTION]========================================================= - * * Passport Semantic BAMM Version @v3.0.1 - * * Aspect model URN: urn:bamm:io.catenax.battery.battery_pass:3.0.1#BatteryPass - * * https://portal.int.demo.catena-x.net/semantichub/urn%3Abamm%3Aio.catenax.battery.battery_pass%3A3.0.1%23BatteryPass - * * Flexible Structure (Abstraction from main attributes using JsonNodes) - * * ============================================================================= - **/ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class PassportV3 extends Passport{ - - @JsonProperty("electrochemicalProperties") - JsonNode electrochemicalProperties; - @JsonProperty("document") - JsonNode document; - @JsonProperty("datePlacedOnMarket") - String datePlacedOnMarket; - @JsonProperty("cellChemistry") - JsonNode cellChemistry; - @JsonProperty("physicalDimensions") - JsonNode physicalDimensions; - @JsonProperty("temperatureRangeIdleState") - JsonNode temperatureRangeIdleState; - @JsonProperty("batteryCycleLife") - JsonNode batteryCycleLife; - @JsonProperty("manufacturer") - JsonNode manufacturer; - @JsonProperty("warrantyPeriod") - String warrantyPeriod; - @JsonProperty("composition") - JsonNode composition; - @JsonProperty("manufacturing") - JsonNode manufacturing; - @JsonProperty("batteryIdentification") - JsonNode batteryIdentification; - @JsonProperty("stateOfBattery") - JsonNode stateOfBattery; - @JsonProperty("cO2FootprintTotal") - JsonNode cO2FootprintTotal; - -} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/AasService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/AasService.java index 26a557412..4c6af1c0e 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/AasService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/AasService.java @@ -23,7 +23,9 @@ package org.eclipse.tractusx.productpass.services; +import org.apache.juli.logging.Log; import org.eclipse.tractusx.productpass.config.DtrConfig; +import org.eclipse.tractusx.productpass.config.PassportConfig; import org.eclipse.tractusx.productpass.exceptions.ControllerException; import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.exceptions.ServiceInitializationException; @@ -63,6 +65,8 @@ public class AasService extends BaseService { public String registryUrl; public Boolean central; + public String semanticIdTypeKey; + private final HttpUtil httpUtil; private final JsonUtil jsonUtil; private final DtrConfig dtrConfig; @@ -72,9 +76,12 @@ public class AasService extends BaseService { private ProcessManager processManager; private DataTransferService dataService; + private PassportConfig passportConfig; + + /** CONSTRUCTOR(S) **/ @Autowired - public AasService(Environment env, HttpUtil httpUtil, JsonUtil jsonUtil, AuthenticationService authService, DtrConfig dtrConfig, DtrSearchManager dtrSearchManager, ProcessManager processManager, DataTransferService dataService) throws ServiceInitializationException { + public AasService(Environment env, HttpUtil httpUtil, JsonUtil jsonUtil, AuthenticationService authService, DtrConfig dtrConfig, DtrSearchManager dtrSearchManager, ProcessManager processManager, DataTransferService dataService, PassportConfig passportConfig) throws ServiceInitializationException { this.httpUtil = httpUtil; this.jsonUtil = jsonUtil; this.authService = authService; @@ -84,6 +91,7 @@ public AasService(Environment env, HttpUtil httpUtil, JsonUtil jsonUtil, Authent this.dataService = dataService; this.init(env); this.checkEmptyVariables(); + this.passportConfig = passportConfig; } /** METHODS **/ @@ -102,6 +110,7 @@ public void init(Environment env) { "subModel", "/submodel-descriptors" ); } + this.semanticIdTypeKey = dtrConfig.getSemanticIdTypeKey(); this.apis = Map.of( "central", Map.of( "search", "/lookup/shells", @@ -195,7 +204,6 @@ public DigitalTwin3 searchDigitalTwin3(String assetType, String assetId, Integer "It was not possible to get digital twin in the selected position for the selected asset type and the the selected assetId"); } - String digitalTwinId = digitalTwinIds.get(position); DigitalTwin3 digitalTwin = this.getDigitalTwin3(digitalTwinId, registryUrl, edr); if (digitalTwin == null) { @@ -319,7 +327,31 @@ public SubModel3 searchSubModel3ById(DigitalTwin3 digitalTwin, String idShort) { public SubModel3 searchSubModel3BySemanticId(DigitalTwin3 digitalTwin, String semanticId) { try { SubModel3 subModel = this.getSubModel3BySemanticId(digitalTwin, semanticId); - LogUtil.printWarning("SUBMODEL3:\n" + jsonUtil.toJson(subModel, true)); + if (subModel == null) { + throw new ServiceException(this.getClass().getName() + "." + "searchSubModel3BySemanticId", + "It was not possible to get submodel in the selected position for the selected asset type and the the selected assetId"); + } + return subModel; + } catch (Exception e) { + throw new ServiceException(this.getClass().getName() + "." + "searchSubModel3ById", + e, + "It was not possible to search submodel!"); + } + } + /** + * Searches a {@code Submodel3} from a Digital Twin by the configured semanticIds + *

+ * @param digitalTwin + * the {@code DigitalTwin3} object with its submodels. + * + * @return a {@code Submodel3} object with the submodel found, if exists. + * + * @throws ServiceException + * if unable to find a the {@code Submodel3} for the given semantic id. + */ + public SubModel3 searchSubModel3BySemanticId(DigitalTwin3 digitalTwin) { + try { + SubModel3 subModel = this.getSubModel3BySemanticId(digitalTwin); if (subModel == null) { throw new ServiceException(this.getClass().getName() + "." + "searchSubModel3BySemanticId", "It was not possible to get submodel in the selected position for the selected asset type and the the selected assetId"); @@ -557,12 +589,50 @@ public SubModel3 getSubModel3ById(DigitalTwin3 digitalTwin, String idShort) { } } + /** + * Gets the {@code Submodel3} from a Digital Twin by the configured semantic aspects + *

+ * @param digitalTwin + * the {@code DigitalTwin3} object with its submodels. + * + * @return a {@code Submodel3} object with the submodel found, if exists. + * + * @throws ServiceException + * if unable to find a the {@code Submodel3} for the given semantic id. + */ + + public SubModel3 getSubModel3BySemanticId(DigitalTwin3 digitalTwin) { + try { + ArrayList subModels = digitalTwin.getSubmodelDescriptors(); + if (subModels.size() < 1) { + throw new ServiceException(this.getClass().getName() + "." + "getSubModel3BySemanticId", + "No subModel found in digitalTwin!"); + } + SubModel3 subModel = null; + // Search for first subModel with matching semanticId, if it fails gives null + for (String semanticId: passportConfig.getAspects()) { + subModel = subModels.stream().filter(s -> s.getSemanticId().getKeys().stream().anyMatch( + k -> (k.getType().equalsIgnoreCase(this.semanticIdTypeKey) && k.getValue().equalsIgnoreCase(semanticId)) + )).findFirst().orElse(null); + if (subModel != null) { + return subModel; // Return subModel if found + } + } + // If the subModel semanticId does not exist + throw new ServiceException(this.getClass().getName() + "." + "getSubModel3BySemanticId", + "SubModel for SemanticId not found!"); + } catch (Exception e) { + throw new ServiceException(this.getClass().getName() + "." + "getSubModel3BySemanticId", + e, + "It was not possible to get subModel!"); + } + } /** * Gets the {@code Submodel3} from a Digital Twin by a given semantic identification. *

* @param digitalTwin * the {@code DigitalTwin3} object with its submodels. - * @param semanticId + * @param aspectSemanticId * the {@code String} semantic id of the intended submodel. * * @return a {@code Submodel3} object with the submodel found, if exists. @@ -570,25 +640,27 @@ public SubModel3 getSubModel3ById(DigitalTwin3 digitalTwin, String idShort) { * @throws ServiceException * if unable to find a the {@code Submodel3} for the given semantic id. */ - public SubModel3 getSubModel3BySemanticId(DigitalTwin3 digitalTwin, String semanticId) { + public SubModel3 getSubModel3BySemanticId(DigitalTwin3 digitalTwin, String aspectSemanticId) { try { ArrayList subModels = digitalTwin.getSubmodelDescriptors(); if (subModels.size() < 1) { - throw new ServiceException(this.getClass().getName() + "." + "getSubModel3ById", + throw new ServiceException(this.getClass().getName() + "." + "getSubModel3BySemanticId", "No subModel found in digitalTwin!"); } - // Search for first subModel with matching idShort, if it fails gives null - SubModel3 subModel = subModels.stream().filter(s -> s.getSemanticId().getKeys().get("Submodel").equalsIgnoreCase(semanticId)).findFirst().orElse(null); - - if (subModel == null) { - // If the subModel idShort does not exist - throw new ServiceException(this.getClass().getName() + "." + "getSubModel3ById", - "SubModel for SemanticId not found!"); + SubModel3 subModel = null; + // Search for first subModel with matching semanticId, if it fails gives null + subModel = subModels.stream().filter( + s -> s.getSemanticId().getKeys().stream().anyMatch( + k -> (k.getType().equalsIgnoreCase(this.semanticIdTypeKey) && k.getValue().equalsIgnoreCase(aspectSemanticId)) + )).findFirst().orElse(null); + if (subModel != null) { + return subModel; // Return subModel if found } - // Return subModel if found - return subModel; + // If the subModel semanticId does not exist + throw new ServiceException(this.getClass().getName() + "." + "getSubModel3BySemanticId", + "SubModel for SemanticId not found!"); } catch (Exception e) { - throw new ServiceException(this.getClass().getName() + "." + "getSubModel3ById", + throw new ServiceException(this.getClass().getName() + "." + "getSubModel3BySemanticId", e, "It was not possible to get subModel!"); } @@ -753,11 +825,8 @@ public AssetSearch decentralDtrSearch(String processId, Search searchBody){ try { Status status = this.processManager.getStatus(processId); SearchStatus searchStatus = this.processManager.setSearch(processId, searchBody); - LogUtil.printWarning("Decentral SearchStatus:\n" + jsonUtil.toJson(searchStatus, true)); for (String endpointId : searchStatus.getDtrs().keySet()) { Dtr dtr = searchStatus.getDtr(endpointId); - LogUtil.printWarning("EndpointId: " + endpointId); - LogUtil.printWarning("Decentral DTR:\n" + jsonUtil.toJson(dtr, true)); DataTransferService.DigitalTwinRegistryTransfer dtrTransfer = dataService.new DigitalTwinRegistryTransfer( processId, endpointId, @@ -765,7 +834,6 @@ public AssetSearch decentralDtrSearch(String processId, Search searchBody){ searchBody, dtr ); - LogUtil.printWarning("Decentral DTRTransfer:\n" + jsonUtil.toJson(dtrTransfer, true)); Thread thread = ThreadUtil.runThread(dtrTransfer, dtr.getEndpoint()); thread.join(Duration.ofSeconds(this.dtrConfig.getTimeouts().getTransfer())); } @@ -780,7 +848,6 @@ public AssetSearch decentralDtrSearch(String processId, Search searchBody){ return null; } status = this.processManager.getStatus(processId); - LogUtil.printWarning("STATUS:\n" + jsonUtil.toJson(status, true)); if(status.historyExists("digital-twin-found")){ return new AssetSearch(status.getHistory("digital-twin-found").getId(), status.getEndpoint()); }; @@ -893,20 +960,25 @@ public void waitForDigitalTwin(){ Status status = this.getStatus(); while(!status.historyExists("digital-twin-found")){ status = this.getStatus(); - if(status.getStatus().equals("FAILED")){ + if (status.getStatus().equals("FAILED")) { break; } } } public Status getStatus(){ - return this.processManager.getStatus(this.processId); + try { + return this.processManager.getStatus(this.processId); + }catch (Exception e){ + LogUtil.printWarning("["+this.getClass().getName()+".getStatus()] Status file for process ["+ this.processId + "] is not available!"); + return new Status(Map.of()); + } } } - public class DecentralDigitalTwinRegistryQueryById implements Runnable { /** ATTRIBUTES **/ + private final String dppIdShort = "digitalProductPass"; private DataPlaneEndpoint edr; private SubModel3 subModel; private DigitalTwin3 digitalTwin; @@ -925,7 +997,23 @@ public DecentralDigitalTwinRegistryQueryById(Search search, DataPlaneEndpoint ed this.edr = edr; this.semanticId = search.getSemanticId(); } - + /** + * This method is exclusively to search for a digital twin and the submodel. + * + *

It's a Thread level method from Runnable interface and does the {@code DigitalTwin3} and {@code Submodel3} search, setting the results + * to this class object. + *

The submodel search it's done by the idShort or semanticId parameters depending on if the semantic Id is available or not, respectively. + * + */ + @Override + public void run() { + this.setDigitalTwin(searchDigitalTwin3(this.getIdType(), this.getAssetId(), this.getDtIndex(), this.getEdr().getEndpoint(), this.getEdr())); + if(this.semanticId == null || this.semanticId.isEmpty()){ + this.setSubModel(searchSubModel3BySemanticId(this.getDigitalTwin())); + }else { + this.setSubModel(searchSubModel3BySemanticId(this.getDigitalTwin(), this.semanticId)); + } + } /** GETTERS AND SETTERS **/ public DataPlaneEndpoint getEdr() { return edr; @@ -961,24 +1049,6 @@ public String getIdShort() { /** METHODS **/ - /** - * This method is exclusively to search for a digital twin and the submodel. - * - *

It's a Thread level method from Runnable interface and does the {@code DigitalTwin3} and {@code Submodel3} search, setting the results - * to this class object. - *

The submodel search it's done by the idShort or semanticId parameters depending on if it's a BatteryPass or DigitalProductPass search, respectively. - * - */ - @Override - public void run() { - this.setDigitalTwin(searchDigitalTwin3(this.getIdType(), this.getAssetId(), this.getDtIndex(), this.getEdr().getEndpoint(), this.getEdr())); - if (this.getIdShort().equalsIgnoreCase("digitalProductPass")) { - this.setSubModel(searchSubModel3BySemanticId(this.getDigitalTwin(), this.getSemanticId())); - } else { - this.setSubModel(searchSubModel3ById(this.getDigitalTwin(), this.getIdShort())); - } - - } } public class DigitalTwinRegistryQueryById implements Runnable { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/CatenaXService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/CatenaXService.java index 64649aeb3..25ef5ac5b 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/CatenaXService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/CatenaXService.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode; +import org.apache.juli.logging.Log; import org.eclipse.tractusx.productpass.config.DiscoveryConfig; import org.eclipse.tractusx.productpass.config.DtrConfig; import org.eclipse.tractusx.productpass.exceptions.ServiceException; @@ -34,6 +35,7 @@ import org.eclipse.tractusx.productpass.managers.DtrSearchManager; import org.eclipse.tractusx.productpass.models.catenax.BpnDiscovery; import org.eclipse.tractusx.productpass.models.catenax.Discovery; +import org.eclipse.tractusx.productpass.models.catenax.Dtr; import org.eclipse.tractusx.productpass.models.catenax.EdcDiscoveryEndpoint; import org.eclipse.tractusx.productpass.models.service.BaseService; import org.springframework.beans.factory.annotation.Autowired; @@ -46,7 +48,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; - +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; /** * This class consists exclusively of methods to operate on executing Catena-X related operations. * @@ -57,19 +60,22 @@ @Service public class CatenaXService extends BaseService { - /** ATTRIBUTES **/ private final HttpUtil httpUtil; + private final JsonUtil jsonUtil; private final FileUtil fileUtil; private final VaultService vaultService; private final DtrSearchManager dtrSearchManager; private final DataTransferService dataTransferService; + private final AuthenticationService authService; + private final DiscoveryConfig discoveryConfig; + private DtrConfig dtrConfig; private String discoveryEndpoint; - private List defaultDiscoveryKeys; + private List defaultDiscoveryKeys; /** CONSTRUCTOR(S) **/ @Autowired public CatenaXService(Environment env, FileUtil fileUtil, HttpUtil httpUtil, JsonUtil jsonUtil, VaultService vaultService, DtrSearchManager dtrSearchManager, AuthenticationService authService, DiscoveryConfig discoveryConfig, DataTransferService dataTransferService, DtrConfig dtrConfig) throws ServiceInitializationException { @@ -85,18 +91,39 @@ public CatenaXService(Environment env, FileUtil fileUtil, HttpUtil httpUtil, Jso this.init(env); this.checkEmptyVariables(); } - /** METHODS **/ /** * Initiates the main needed variables for Catena-X Service by loading from the application's configuration file. **/ + public void init(Environment env){ this.discoveryEndpoint = this.discoveryConfig.getEndpoint(); this.defaultDiscoveryKeys = List.of( this.discoveryConfig.getBpn().getKey(), this.discoveryConfig.getEdc().getKey() ); } + /** + * Creates a List of missing variables needed to proceed with the authentication. + *

+ * + * @return an {@code Arraylist} with the environment variables missing in the configuration for the Catena-x service. + * + */ + @Override + public List getEmptyVariables() { + List missingVariables = new ArrayList<>(); + if (this.discoveryEndpoint.isEmpty()) { + missingVariables.add("discovery.endpoint"); + } + if (this.discoveryConfig.getBpn().getKey().isEmpty()) { + missingVariables.add("discovery.edcKey"); + } + if (this.discoveryConfig.getBpn().getKey().isEmpty()) { + missingVariables.add("discovery.bpnKey"); + } + return missingVariables; + } /** * Checks if the empty variables are well configured. @@ -109,7 +136,6 @@ public void init(Environment env){ public void checkEmptyVariables() throws ServiceInitializationException { super.checkEmptyVariables(); } - /** * Checks if the empty variables are well configured. *

@@ -123,29 +149,6 @@ public void checkEmptyVariables() throws ServiceInitializationException { public void checkEmptyVariables(List initializationOptionalVariables) throws ServiceInitializationException { super.checkEmptyVariables(initializationOptionalVariables); } - - /** - * Creates a List of missing variables needed to proceed with the authentication. - *

- * - * @return an {@code Arraylist} with the environment variables missing in the configuration for the Catena-x service. - * - */ - @Override - public List getEmptyVariables() { - List missingVariables = new ArrayList<>(); - if (this.discoveryEndpoint.isEmpty()) { - missingVariables.add("discovery.endpoint"); - } - if (this.discoveryConfig.getBpn().getKey().isEmpty()) { - missingVariables.add("discovery.edcKey"); - } - if (this.discoveryConfig.getBpn().getKey().isEmpty()) { - missingVariables.add("discovery.bpnKey"); - } - return missingVariables; - } - /** * Gets the default discovery endpoints. *

@@ -156,7 +159,6 @@ public List getEmptyVariables() { public Discovery getDiscoveryEndpoints() { return this.getDiscoveryEndpoints(this.defaultDiscoveryKeys); // Get default discovery endpoints } - /** * Initiates the default endpoints discovery. *

@@ -178,7 +180,6 @@ public Discovery start(){ } return null; } - /** * Adds a new entry to the discovery endpoints list for a given key. *

@@ -205,6 +206,28 @@ public Discovery addEndpoint(String key){ "It was not possible to get the discovery endpoints"); } } + /** + * Gets the discovery endpoints from the {@code Discovery} object for a given key. + *

+ * @param discovery + * the {@code Discovery} object containing the list of discovery endpoints. + * @param key + * the {@code String} key parameter to search the discovery endpoint. + * + * @return a {@code List} object with the endpoint data found. + * + * @throws ServiceException + * if unable to get the endpoint for the given key. + */ + public List getDiscoveryEndpoints(Discovery discovery, String key) { + List endpoints = discovery.getEndpoints(); + List filteredEndpoints = endpoints.stream().filter(endpoint -> endpoint.getType().equals(key)).toList(); + if(filteredEndpoints.isEmpty()){ + throw new ServiceException(this.getClass().getName() + "." + "updateDiscovery", + "The endpoint ["+key+"] is not available in the discovery endpoint ["+this.discoveryEndpoint +"]"); + } + return filteredEndpoints; + } /** * Gets the discovery endpoint from the {@code Discovery} object for a given key. @@ -228,7 +251,6 @@ public Discovery.Endpoint getDiscoveryEndpoint(Discovery discovery, String key) } return responseEndpoint; } - /** * Updates the discovery endpoint from the {@code Discovery} object with a given key. *

@@ -242,7 +264,6 @@ public Discovery.Endpoint getDiscoveryEndpoint(Discovery discovery, String key) * @throws ServiceException * if unable to get the endpoint for the given key. */ - @SuppressWarnings("Unused") public Boolean updateDiscovery(Discovery discovery, String key){ try{ if(discovery.getEndpoints().isEmpty()){ @@ -257,7 +278,6 @@ public Boolean updateDiscovery(Discovery discovery, String key){ "Failed to update the discovery endpoints"); } } - /** * Updates the given {@code Discovery} object with default discovery endpoints. *

@@ -275,16 +295,42 @@ public Boolean updateDefaultDiscovery(Discovery discovery){ return false; } // Get discovery endpoints by key - Discovery.Endpoint bpnEndpoint = this.getDiscoveryEndpoint(discovery, this.discoveryConfig.getBpn().getKey()); - Discovery.Endpoint edcEndpoint = this.getDiscoveryEndpoint(discovery, this.discoveryConfig.getEdc().getKey()); - return this.updateDefaultDiscoveryFile(bpnEndpoint, edcEndpoint); // Create default discovery file + List bpnEndpoints = this.getDiscoveryEndpoints(discovery, this.discoveryConfig.getBpn().getKey()); + List edcEndpoints = this.getDiscoveryEndpoints(discovery, this.discoveryConfig.getEdc().getKey()); + return this.updateDefaultDiscoveryFile(bpnEndpoints, edcEndpoints); // Create default discovery file }catch(Exception e){ throw new ServiceException(this.getClass().getName() + "." + "updateDiscovery", e, "Failed to update the discovery endpoints"); } } - + /** + * Creates or Updates the endpoints with the given key in the vault, if exists. + *

+ * @param endpoints + * the {@code List} object to update. + * @param key + * the {@code String} key parameter to update. + * + * @return true if the endpoint is successfully created/update, false otherwise. + * + * @throws ServiceException + * if unable to update the discovery endpoint. + */ + public Boolean updateEndpointFile(List endpoints, String key){ + try { + boolean returnState; + for(Discovery.Endpoint endpoint: endpoints) { + returnState = this.updateEndpointFile(endpoint, key); + if(!returnState){ + return false; + } + } + return true; + }catch (Exception e){ + throw new ServiceException(this.getClass().getName(), e, "It was not possible to create/update discovery endpoints for key [" + key + "]"); + } + } /** * Creates or Updates the endpoint with the given key in the vault, if exists. *

@@ -305,17 +351,53 @@ public Boolean updateEndpointFile(Discovery.Endpoint endpoint, String key){ LogUtil.printError("The endpoint for key ["+key+"] address is not defined!"); return false; } - - if(!this.vaultService.setLocalSecret("discovery."+key, address)){ - LogUtil.printError("Failed to create/update discovery key ["+key+"] endpoint!"); - return false; - }; + List endpoints = new ArrayList(); + if(this.vaultService.secretExists("discovery."+key)){ + endpoints = (List) this.vaultService.getLocalSecret("discovery."+key); + } + if(!endpoints.contains(address)){ + endpoints.add(address); + if(!this.vaultService.setLocalSecret("discovery."+key, endpoints)){ + LogUtil.printError("Failed to create/update discovery key ["+key+"] endpoint!"); + return false; + }; + } return true; }catch (Exception e){ throw new ServiceException(this.getClass().getName(), e, "It was not possible to create/update discovery endpoints for key [" + key + "]"); } } + /** + * Creates or Updates BPN and EDC endpoints in the Vault. + *

+ * @param bpnEndpoints + * the {@code List} object related to BPN. + * @param edcEndpoints + * the {@code List} object related to EDC. + * + * @return true if both endpoints are successfully created/update, false otherwise. + * + * @throws ServiceException + * if unable to create/update the BPN and EDC endpoints. + */ + public Boolean updateDefaultDiscoveryFile(List bpnEndpoints, List edcEndpoints){ + try { + Boolean bpnResponse = this.updateEndpointFile(bpnEndpoints, this.discoveryConfig.getBpn().getKey()); + Boolean edcResponse = this.updateEndpointFile(edcEndpoints, "edc"); + if(!bpnResponse){ + LogUtil.printError("Something went wrong when getting the bpn endpoint"); + return false; + } + if(!edcResponse){ + LogUtil.printError("Something went wrong when getting the edc endpoint"); + return false; + } + return true; + }catch (Exception e){ + throw new ServiceException(this.getClass().getName(), e, "It was not possible to create/update main discovery endpoints"); + } + } /** * Creates or Updates BPN and EDC endpoints in the Vault. *

@@ -346,7 +428,6 @@ public Boolean updateDefaultDiscoveryFile(Discovery.Endpoint bpnEndpoint, Discov throw new ServiceException(this.getClass().getName(), e, "It was not possible to create/update main discovery endpoints"); } } - /** * Gets the Discovery endpoint for the given key, if exists. *

@@ -367,7 +448,6 @@ public Discovery getDiscoveryEndpoint(String key) { "It was not possible to retrieve the discovery finder!"); } } - /** * Gets the Discovery endpoint for a given endpoints list. *

@@ -399,7 +479,6 @@ public Discovery getDiscoveryEndpoints(List endpoints) { "It was not possible to retrieve the discovery finder!"); } } - /** * Gets the EDC Discovery endpoints for a given BPNs list. *

@@ -414,31 +493,46 @@ public Discovery getDiscoveryEndpoints(List endpoints) { public List getEdcDiscovery(List bpns) { try { this.checkEmptyVariables(); - String edcEndpoint = null; + List edcEndpoints = null; // Check if the variable edc endpoint is correct try { - edcEndpoint = (String) this.vaultService.getLocalSecret("discovery.edc"); + edcEndpoints = (List) this.vaultService.getLocalSecret("discovery.edc"); } catch (Exception e) { throw new ServiceException(this.getClass().getName() + ".getEdcDiscovery", e, "It was not possible to retrieve the edc discovery endpoint from the vault"); } - if (edcEndpoint == null) { + if (edcEndpoints == null) { throw new ServiceException(this.getClass().getName() + ".getEdcDiscovery", "The edc discovery endpoint is empty!"); } + List edcDiscoveryResponses = new ArrayList<>(); + for(String edcEndpoint : edcEndpoints) { + + // Add the technical token + HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); + headers.add("Content-Type", "application/json"); + try{ + ResponseEntity response = httpUtil.doPost(edcEndpoint, JsonNode.class, headers, httpUtil.getParams(), bpns, false, false); + JsonNode result = (JsonNode) response.getBody(); + List edcDiscoveryResponse = (List) jsonUtil.bindJsonNode(result, List.class); + if(edcDiscoveryResponse.isEmpty()) { + LogUtil.printWarning("List of EDCs not found in EDC Discovery Url: ["+edcEndpoint+"]"); + continue; + } + edcDiscoveryResponses.addAll(edcDiscoveryResponse); + }catch (Exception e){ + LogUtil.printException(e, "It was not possible to get the edc endpoints from the EDC Discovery Service endpoint: ["+edcEndpoint+"]"); + } - // Add the technical token - HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); - headers.add("Content-Type", "application/json"); - - ResponseEntity response = httpUtil.doPost(edcEndpoint, JsonNode.class, headers, httpUtil.getParams(), bpns, false, false); - JsonNode result = (JsonNode) response.getBody(); - return (List) jsonUtil.bindJsonNode(result, List.class); + } + if(edcDiscoveryResponses.isEmpty()){ + return null; + } + return edcDiscoveryResponses; } catch (Exception e) { throw new ServiceException(this.getClass().getName() + "." + "getEdcDiscovery", e, "It was not possible to get the edc endpoints from the EDC Discovery Service"); } } - /** * Gets the BPN discovery endpoint for a given id and id's type. *

@@ -452,10 +546,9 @@ public List getEdcDiscovery(List bpns) { * @throws ServiceException * if unable to get the BPN discovery endpoint. */ - public BpnDiscovery getBpnDiscovery(String id, String type){ + public List getBpnDiscovery(String id, String type){ try { this.checkEmptyVariables(); - String bpnEndpoint = null; // Check if the discovery type id exists in the endpoint from the edc discovery if(!this.vaultService.secretExists("discovery."+type)){ Discovery discovery = this.addEndpoint(type); @@ -463,41 +556,55 @@ public BpnDiscovery getBpnDiscovery(String id, String type){ throw new ServiceException(this.getClass().getName() + ".getBpnDiscovery", "The discovery finder service failed"); } } - + List bpnEndpoints = new ArrayList<>(); try { - bpnEndpoint = (String) this.vaultService.getLocalSecret("discovery."+type); + bpnEndpoints = (List) this.vaultService.getLocalSecret("discovery."+type); }catch (Exception e) { throw new ServiceException(this.getClass().getName() + ".getBpnDiscovery", e, "It was not possible to retrieve the bpn discovery endpoint from the vault"); } - if(bpnEndpoint == null){ + if(bpnEndpoints == null){ throw new ServiceException(this.getClass().getName() + ".getBpnDiscovery", "The bpn discovery endpoint is empty!"); } - - String searchEndpoint = bpnEndpoint + this.discoveryConfig.getBpn().getSearchPath(); - - - // Set request body - Object body = Map.of( - "searchFilter",List.of( - Map.of( - "type", type, "keys", List.of(id) - ) - ) - ); - - HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); - headers.add("Content-Type", "application/json"); - - ResponseEntity response = httpUtil.doPost(searchEndpoint, JsonNode.class, headers, httpUtil.getParams(), body, false, false); - JsonNode result = (JsonNode) response.getBody(); - return (BpnDiscovery) jsonUtil.bindJsonNode(result, BpnDiscovery.class); + List bpnDiscoveryResponse = new ArrayList<>(); + for(String bpnEndpoint : bpnEndpoints) { + + String searchEndpoint = bpnEndpoint + this.discoveryConfig.getBpn().getSearchPath(); + + + // Set request body + Object body = Map.of( + "searchFilter", List.of( + Map.of( + "type", type, "keys", List.of(id) + ) + ) + ); + + HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); + headers.add("Content-Type", "application/json"); + try{ + ResponseEntity response = httpUtil.doPost(searchEndpoint, JsonNode.class, headers, httpUtil.getParams(), body, false, false); + JsonNode result = (JsonNode) response.getBody(); + BpnDiscovery bpnDiscovery = (BpnDiscovery) jsonUtil.bindJsonNode(result, BpnDiscovery.class); + if(bpnDiscovery == null){ + LogUtil.printWarning("Response from search endpoint: [" + searchEndpoint + "]"); + continue; + } + bpnDiscoveryResponse.add(bpnDiscovery); + }catch (Exception e){ + LogUtil.printException(e, "BPN Number not found for ["+searchEndpoint+"] and keyType ["+type+"]!"); + } + } + if(bpnDiscoveryResponse.isEmpty()){ + return null; + } + return bpnDiscoveryResponse; } catch (Exception e) { throw new ServiceException(this.getClass().getName() + "." + "getBpnDiscovery", e, "It was not possible to retrieve the bpn at the BPN discovery service"); } } - /** * Searches for all DTRs for a given edcEndpoints and updates the DTR data model of the given process accordingly. *

diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataPlaneService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataPlaneService.java index 395f77895..025de684c 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataPlaneService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataPlaneService.java @@ -23,18 +23,16 @@ package org.eclipse.tractusx.productpass.services; +import com.fasterxml.jackson.databind.JsonNode; import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.exceptions.ServiceInitializationException; import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; -import org.eclipse.tractusx.productpass.models.passports.Passport; -import org.eclipse.tractusx.productpass.models.passports.PassportV3; import org.eclipse.tractusx.productpass.models.service.BaseService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; -import utils.HttpUtil; -import utils.JsonUtil; +import utils.*; import java.util.ArrayList; import java.util.List; @@ -98,9 +96,9 @@ public Object getTransferData(DataPlaneEndpoint endpointData) { * @throws ServiceException * if unable to parse the data to the passport. */ - public Passport getPassport(DataPlaneEndpoint endpointData) { + public JsonNode getPassport(DataPlaneEndpoint endpointData) { try { - return (PassportV3) jsonUtil.bindObject(this.getTransferData(endpointData), PassportV3.class); + return jsonUtil.toJsonNode(this.getTransferData(endpointData)); }catch (Exception e){ throw new ServiceException(this.getClass().getName()+"."+"getPassport", e, diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataTransferService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataTransferService.java index 76fb76662..d8b06bb70 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataTransferService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/DataTransferService.java @@ -35,9 +35,8 @@ import org.eclipse.tractusx.productpass.models.http.responses.IdResponse; import org.eclipse.tractusx.productpass.models.manager.History; import org.eclipse.tractusx.productpass.models.manager.Status; -import org.eclipse.tractusx.productpass.models.negotiation.Set; import org.eclipse.tractusx.productpass.models.negotiation.*; -import org.eclipse.tractusx.productpass.models.passports.PassportV3; +import org.eclipse.tractusx.productpass.models.negotiation.Set; import org.eclipse.tractusx.productpass.models.service.BaseService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; @@ -724,7 +723,7 @@ public Transfer seeTransfer(String id, String processId, ProcessDataModel dataMo * if unable to get the passport. */ @SuppressWarnings("Unused") - public PassportV3 getPassportV3(String transferProcessId, String endpoint) { + public JsonNode getPassport(String transferProcessId, String endpoint) { try { this.checkEmptyVariables(); Map params = httpUtil.getParams(); @@ -736,14 +735,14 @@ public PassportV3 getPassportV3(String transferProcessId, String endpoint) { try { response = httpUtil.doGet(endpoint, String.class, headers, params, false, false); } catch (Exception e) { - throw new ServiceException(this.getClass().getName() + ".getPassportV3", "It was not possible to get passport with id " + transferProcessId); + throw new ServiceException(this.getClass().getName() + ".getPassport", "It was not possible to get passport with id " + transferProcessId); } String responseBody = (String) response.getBody(); - return (PassportV3) jsonUtil.bindJsonNode(jsonUtil.toJsonNode(responseBody), PassportV3.class); + return (JsonNode) jsonUtil.toJsonNode(responseBody); } catch (Exception e) { - throw new ServiceException(this.getClass().getName() + "." + "getPassportV3", + throw new ServiceException(this.getClass().getName() + "." + "getPassport", e, - "It was not possible to retrieve the getPassport V1 for transferProcessId [" + transferProcessId + "]!"); + "It was not possible to retrieve the getPassport for transferProcessId [" + transferProcessId + "]!"); } } @@ -943,7 +942,7 @@ public TransferRequest buildTransferRequest(Dataset dataset, Status status, Nego transferType.setIsFinite(true); - DataDestination dataDestination = new DataDestination(); + TransferRequest.DataDestination dataDestination = new TransferRequest.DataDestination(); dataDestination.setType("HttpProxy"); TransferRequest.PrivateProperties privateProperties = new TransferRequest.PrivateProperties(); @@ -1164,13 +1163,10 @@ public DigitalTwinRegistryTransfer(String processId, String endpointId, Status s public void run() { try { this.dtrRequest = this.buildTransferRequest(this.processId,this.dtr, this.endpointId); - LogUtil.printWarning("DTR REQUEST:\n" + jsonUtil.toJson(this.dtrRequest, true)); processManager.saveTransferRequest(this.processId, dtrRequest, new IdResponse(processId, null), true); this.transferResponse = this.requestTransfer(dtrRequest); - processManager.saveTransferRequest(this.processId, dtrRequest, this.transferResponse, true); this.transfer = this.getTransferData(this.transferResponse); - LogUtil.printWarning("TRANSFER:\n" + jsonUtil.toJson(this.transfer, true)); if (this.transfer == null) { return; } @@ -1208,7 +1204,7 @@ public TransferRequest buildTransferRequest(String processId, Dtr dtr, String en transferType.setContentType("application/octet-stream"); transferType.setIsFinite(true); - DataDestination dataDestination = new DataDestination(); + TransferRequest.DataDestination dataDestination = new TransferRequest.DataDestination(); dataDestination.setType("HttpProxy"); TransferRequest.PrivateProperties privateProperties = new TransferRequest.PrivateProperties(); diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/VaultService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/VaultService.java index e4748ab90..985685f00 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/VaultService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/VaultService.java @@ -164,11 +164,11 @@ public Boolean secretExists(String localSecretPath){ */ public Object getLocalSecret(String localSecretPath) { try { - String secret = null; + Object secret = null; String filePath = this.createLocalVaultFile(true); Map content = yamlUtil.readFile(filePath); try { - secret = (String) jsonUtil.getValue(content,localSecretPath, ".",null); + secret = jsonUtil.getValue(content,localSecretPath, ".",null); }catch (Exception e){ LogUtil.printException(e, "["+this.getClass().getName()+"."+"getLocalSecret] " + "There was an error while searching the secret ["+localSecretPath+"] in file!"); } diff --git a/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java b/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java index e11b95bf4..d7ded75c3 100644 --- a/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java @@ -26,6 +26,8 @@ import org.springframework.core.env.Environment; import utils.exceptions.UtilException; +import java.nio.file.Paths; +import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -89,6 +91,14 @@ public static String buildDataEndpoint(String endpoint) { * @return the {@code String} BPN number found in the given String or null if it doesn't exist. * */ + public static String getAspectNameFromSemanticId(String semanticId){ + try { + return semanticId.split(String.format("\\%s","#"))[1]; + }catch(Exception e){ + throw new UtilException(CatenaXUtil.class, e, "[ERROR] It was not possible to ge the semantic aspect!"); + } + } + public static String getBPN(String str) { Pattern pattern = Pattern.compile(bpnNumberPattern); Matcher matcher = pattern.matcher(str); diff --git a/consumer-backend/productpass/src/main/java/utils/JsonUtil.java b/consumer-backend/productpass/src/main/java/utils/JsonUtil.java index 275992f32..5db7db719 100644 --- a/consumer-backend/productpass/src/main/java/utils/JsonUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/JsonUtil.java @@ -563,6 +563,25 @@ public JsonNode toJsonNode(String json){ } } + /** + * Parses the JSON string object to a JsonNode object. + *

+ * @param json + * the json object as a Object + * + * @return a {@code JsonObject} object parsed with the json data. + * + * @throws UtilException + * if unable to parse the json string. + */ + public JsonNode toJsonNode(Object json){ + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.convertValue(json,JsonNode.class); + } catch (Exception e) { + throw new UtilException(JsonUtil.class, "It was not possible to parse json -> [" + e.getMessage() + "]"); + } + } /** * Parses the JSON Map object to a JsonNode object. *

diff --git a/consumer-backend/productpass/src/main/java/utils/PassportUtil.java b/consumer-backend/productpass/src/main/java/utils/PassportUtil.java index 7f5d343f0..d4806fc93 100644 --- a/consumer-backend/productpass/src/main/java/utils/PassportUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/PassportUtil.java @@ -25,9 +25,9 @@ package utils; +import com.fasterxml.jackson.databind.JsonNode; import org.eclipse.tractusx.productpass.managers.ProcessManager; import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; -import org.eclipse.tractusx.productpass.models.passports.Passport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @@ -75,7 +75,7 @@ public PassportUtil(JsonUtil jsonUtil, FileUtil fileUtil,ProcessManager processM * if unable to save the Passport to a JSON file. */ @SuppressWarnings("Unused") - public String savePassport(Passport passport, DataPlaneEndpoint endpointData, Boolean prettyPrint, Boolean encrypted){ + public String savePassport(JsonNode passport, DataPlaneEndpoint endpointData, Boolean prettyPrint, Boolean encrypted){ try { fileUtil.createDir(this.transferDir); String path = Path.of(this.transferDir, endpointData.getId() + ".json").toAbsolutePath().toString(); @@ -104,7 +104,7 @@ public String savePassport(Passport passport, DataPlaneEndpoint endpointData, Bo * @throws UtilException * if unable to save the Passport to a JSON file. */ - public String savePassport(Passport passport, DataPlaneEndpoint endpointData, Boolean prettyPrint, Boolean encrypted, String filePath){ + public String savePassport(JsonNode passport, DataPlaneEndpoint endpointData, Boolean prettyPrint, Boolean encrypted, String filePath){ try { if(!encrypted) { return jsonUtil.toJsonFile(filePath, passport, prettyPrint); // Store the plain JSON diff --git a/consumer-backend/productpass/src/main/java/utils/ReflectionUtil.java b/consumer-backend/productpass/src/main/java/utils/ReflectionUtil.java index b6a59537e..95767a1e1 100644 --- a/consumer-backend/productpass/src/main/java/utils/ReflectionUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/ReflectionUtil.java @@ -50,8 +50,17 @@ private ReflectionUtil() { public static String getCurrentClassName(Class classObj){ return classObj.getSimpleName(); } - @SuppressWarnings("Unused") public static Boolean classIsTest(Class classObj){ return ReflectionUtil.getCurrentClassName(classObj).contains("test"); } + public static Class instanceClass(String packagePath, String className){ + try { + String classPath = packagePath + "." + className; + return Class.forName(classPath); + }catch (ClassNotFoundException e){ + throw new UtilException(ReflectionUtil.class, e, "It was not possible to instance class, class ["+packagePath+"."+className+"] not found!"); + }catch (Exception e){ + throw new UtilException(ReflectionUtil.class, e, "It was not possible to instance class!"); + } + } } diff --git a/consumer-backend/productpass/src/main/resources/application.yml b/consumer-backend/productpass/src/main/resources/application.yml index d163a17ac..48dc0205e 100644 --- a/consumer-backend/productpass/src/main/resources/application.yml +++ b/consumer-backend/productpass/src/main/resources/application.yml @@ -63,26 +63,27 @@ configuration: dtr: central: false centralUrl: 'https://semantics.int.demo.catena-x.net/registry' - assetId: 'digital-twin-registry' + assetId: 'registry-asset' endpointInterface: 'SUBMODEL-3.0' dspEndpointKey: 'dspEndpoint' internalDtr: "https://materialpass.int.demo.catena-x.net/BPNL000000000000" # -- If there is an internal DTR available it can be referenced here and will be injected in the list of DTRs + semanticIdTypeKey: 'Submodel' decentralApis: search: "/lookup/shells" digitalTwin: "/shell-descriptors" subModel: "/submodel-descriptors" timeouts: - search: 100 - negotiation: 100 - transfer: 100 - digitalTwin: 120 + search: 10 + negotiation: 40 + transfer: 10 + digitalTwin: 20 temporaryStorage: true discovery: - endpoint: "https://semantics.int.demo.catena-x.net/discoveryfinder/api/administration/connectors/discovery/search" + endpoint: "https://semantics.int.demo.catena-x.net/discoveryfinder/api/v1.0/administration/connectors/discovery/search" bpn: key: "manufacturerPartId" - searchPath: "/api/administration/connectors/bpnDiscovery/search" + searchPath: "/api/v1.0/administration/connectors/bpnDiscovery/search" edc: key: "bpn" @@ -98,16 +99,9 @@ configuration: encrypt: true indent: true dir: "data/transfer" - digitalProductPass: - versions: - - '1.0.0' - semanticId: "urn:bamm:io.catenax.generic.digital_product_passport" - aspectId: "DigitalProductPassport" - batteryPass: - versions: - - '3.0.1' - semanticId: "urn:bamm:io.catenax.battery.battery_pass" - aspectId: "BatteryPass" + aspects: + - "urn:bamm:io.catenax.generic.digital_product_passport:1.0.0#DigitalProductPassport" + - "urn:bamm:io.catenax.battery.battery_pass:3.0.1#BatteryPass" vault: type: 'local' @@ -130,4 +124,4 @@ server: include-exception: false port: 8888 tomcat: - max-connections: 10000 \ No newline at end of file + max-connections: 10000 diff --git a/src/components/general/LoadingComponent.vue b/src/components/general/LoadingComponent.vue index bc847c981..4ca3ef6dd 100644 --- a/src/components/general/LoadingComponent.vue +++ b/src/components/general/LoadingComponent.vue @@ -37,7 +37,7 @@ (statusData.data.history['transfer-request'] ? this.stepsNames.contractTransfer.progressValue : 0) + - (statusData.data.history['passport-received'] + (statusData.data.history['data-received'] ? this.stepsNames.passportRetrieval.progressValue : 0) " @@ -116,7 +116,7 @@ />