From abc0bab9cc9ac04d971aadc5aa3c499372d06582 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Thu, 28 Sep 2023 14:20:59 +0200 Subject: [PATCH 01/25] feat: configured initial structure for IRS integration with the backend --- .../productpass/config/IrsConfig.java | 50 +++++ .../http/controllers/api/IrsController.java | 82 ++++++++ .../productpass/models/irs/JobRequest.java | 186 ++++++++++++++++++ .../productpass/services/IrsService.java | 104 ++++++++++ .../src/main/resources/application.yml | 3 + 5 files changed, 425 insertions(+) create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java new file mode 100644 index 000000000..5cf21188c --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java @@ -0,0 +1,50 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix="configuration.irs") +public class IrsConfig { + String endpoint; + + public IrsConfig(String endpoint) { + this.endpoint = endpoint; + } + + public IrsConfig() { + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java new file mode 100644 index 000000000..af5678488 --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -0,0 +1,82 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.http.controllers.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.tractusx.productpass.config.IrsConfig; +import org.eclipse.tractusx.productpass.models.http.Response; +import org.eclipse.tractusx.productpass.services.AuthenticationService; +import org.eclipse.tractusx.productpass.services.IrsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import utils.HttpUtil; +import utils.JsonUtil; + +@RestController +@RequestMapping("/api/irs") +@Tag(name = "IRS Controller") +@SecurityRequirement(name = "BearerAuthentication") +public class IrsController { + + private @Autowired HttpServletRequest httpRequest; + private @Autowired HttpServletResponse httpResponse; + + private @Autowired AuthenticationService authService; + + private @Autowired HttpUtil httpUtil; + private @Autowired JsonUtil jsonUtil; + + private @Autowired IrsConfig irsConfig; + private @Autowired IrsService irsService; + + @RequestMapping(value = "/search", method = RequestMethod.GET) + @Operation(summary = "Search for tree of ids in IRS") + public Response search() { + Response response = httpUtil.getInternalError(); + // Check for authentication + if (!authService.isAuthenticated(httpRequest)) { + response = httpUtil.getNotAuthorizedResponse(); + return httpUtil.buildResponse(response, httpResponse); + } + try { + response = httpUtil.getResponse("IRS is not available at the moment!"); + response.data = irsService.searchComponents(null); + return httpUtil.buildResponse(response, httpResponse); + } catch (Exception e) { + response.message = e.getMessage(); + return httpUtil.buildResponse(response, httpResponse); + } + } + + +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java new file mode 100644 index 000000000..2f29ebab0 --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java @@ -0,0 +1,186 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.irs; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; + +/** + * This class states how a Job request for the IRS Component need to be created. + * + *

It defines the structure to follow when requesting a Job Creation. + * This is a model class and is used by the IRS service. + * + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JobRequest { + + @JsonProperty("aspects") + ArrayList aspects; + + @JsonProperty("bomLifecycle") + String bomLifecycle; + @JsonProperty("lookupBPNs") + Boolean lookupBPNs; + + @JsonProperty("collectAspects") + Boolean collectAspects; + + @JsonProperty("direction") + String direction; + + @JsonProperty("depth") + Integer depth; + + @JsonProperty("integrityCheck") + Boolean integrityCheck; + + @JsonProperty("key") + Key key; + + public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookupBPNs, Boolean collectAspects, String direction, Integer depth, Boolean integrityCheck, Key key) { + this.aspects = aspects; + this.bomLifecycle = bomLifecycle; + this.lookupBPNs = lookupBPNs; + this.collectAspects = collectAspects; + this.direction = direction; + this.depth = depth; + this.integrityCheck = integrityCheck; + this.key = key; + } + + public JobRequest() { + } + + public ArrayList getAspects() { + return aspects; + } + + public void setAspects(ArrayList aspects) { + this.aspects = aspects; + } + + public String getBomLifecycle() { + return bomLifecycle; + } + + public void setBomLifecycle(String bomLifecycle) { + this.bomLifecycle = bomLifecycle; + } + + public Boolean getLookupBPNs() { + return lookupBPNs; + } + + public void setLookupBPNs(Boolean lookupBPNs) { + this.lookupBPNs = lookupBPNs; + } + + public Boolean getCollectAspects() { + return collectAspects; + } + + public void setCollectAspects(Boolean collectAspects) { + this.collectAspects = collectAspects; + } + + public String getDirection() { + return direction; + } + + public void setDirection(String direction) { + this.direction = direction; + } + + public Integer getDepth() { + return depth; + } + + public void setDepth(Integer depth) { + this.depth = depth; + } + + public Boolean getIntegrityCheck() { + return integrityCheck; + } + + public void setIntegrityCheck(Boolean integrityCheck) { + this.integrityCheck = integrityCheck; + } + + public Key getKey() { + return key; + } + + public void setKey(Key key) { + this.key = key; + } + + public void setKey(String globalAssetId, String bpn) { + this.key = new Key(globalAssetId, bpn); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + static class Key { + @JsonProperty("globalAssetId") + String globalAssetId; + @JsonProperty("bpn") + String bpn; + + public Key(String globalAssetId, String bpn) { + this.globalAssetId = globalAssetId; + this.bpn = bpn; + } + + public Key() { + } + + public String getGlobalAssetId() { + return globalAssetId; + } + + public void setGlobalAssetId(String globalAssetId) { + this.globalAssetId = globalAssetId; + } + + public String getBpn() { + return bpn; + } + + public void setBpn(String bpn) { + this.bpn = bpn; + } + } + + + + +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java new file mode 100644 index 000000000..46ebaee0d --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -0,0 +1,104 @@ +/********************************************************************************* + * + * 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.services; + +import com.fasterxml.jackson.databind.JsonNode; +import org.eclipse.tractusx.productpass.config.IrsConfig; +import org.eclipse.tractusx.productpass.exceptions.ServiceException; +import org.eclipse.tractusx.productpass.exceptions.ServiceInitializationException; +import org.eclipse.tractusx.productpass.models.catenax.Discovery; +import org.eclipse.tractusx.productpass.models.irs.JobRequest; +import org.eclipse.tractusx.productpass.models.service.BaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import utils.HttpUtil; +import utils.JsonUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * This class is a service responsible for handling the communication with a external IRS component. + * + *

It contains all the methods and properties to communicate with the IRS Service. + * Its is called by the IRS Controller and can be used by managers to update information. + * + */ +@Service +public class IrsService extends BaseService { + + HttpUtil httpUtil; + + JsonUtil jsonUtil; + + String irsEndpoint; + AuthenticationService authService; + IrsConfig irsConfig; + @Autowired + public IrsService(Environment env, IrsConfig irsConfig, HttpUtil httpUtil, JsonUtil jsonUtil,AuthenticationService authService) throws ServiceInitializationException { + this.httpUtil = httpUtil; + this.jsonUtil = jsonUtil; + this.authService = authService; + this.irsConfig = irsConfig; + this.init(env); + } + + public Object startJob(){ + try { + this.checkEmptyVariables(); + // Add body + Object body = Map.of( + "searchParam", search + ); + + HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); + headers.add("Content-Type", "application/json"); + + ResponseEntity response = httpUtil.doPost(this.irsEndpoint, JsonNode.class, headers, httpUtil.getParams(), body, false, false); + JsonNode result = (JsonNode) response.getBody(); + return jsonUtil.bindJsonNode(result, Object.class); + }catch (Exception e){ + throw new ServiceException(this.getClass().getName()+"."+"searchComponents", + e, + "It was not possible to search for the drill down of components!"); + } + } + + @Override + public List getEmptyVariables() { + List missingVariables = new ArrayList<>(); + if (this.irsEndpoint.isEmpty()) { + missingVariables.add("irs.endpoint"); + } + return missingVariables; + } + + public void init(Environment env){ + this.irsEndpoint = this.irsConfig.getEndpoint(); + } +} diff --git a/consumer-backend/productpass/src/main/resources/application.yml b/consumer-backend/productpass/src/main/resources/application.yml index 98fa990ab..e9f99defc 100644 --- a/consumer-backend/productpass/src/main/resources/application.yml +++ b/consumer-backend/productpass/src/main/resources/application.yml @@ -60,6 +60,9 @@ configuration: bpn: true edc: true + irs: + endpoint: "https://materialpass-irs.int.demo.catena-x.net" + dtr: central: false centralUrl: 'https://semantics.int.demo.catena-x.net/registry' From e47c704a4a3b118a2b7fd39249f821fabb053075 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Mon, 2 Oct 2023 16:00:27 +0200 Subject: [PATCH 02/25] feat: created irs initial integration --- .../productpass/config/IrsConfig.java | 38 ++- .../http/controllers/api/IrsController.java | 20 +- .../tractusx/productpass/models/irs/Job.java | 174 ++++++++++++++ .../productpass/models/irs/JobRequest.java | 13 ++ .../productpass/models/irs/JobResponse.java | 111 +++++++++ .../productpass/models/irs/Relationship.java | 220 ++++++++++++++++++ .../productpass/services/IrsService.java | 66 +++++- .../src/main/resources/application.yml | 2 + 8 files changed, 618 insertions(+), 26 deletions(-) create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Relationship.java diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java index 5cf21188c..77fc77008 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java @@ -33,13 +33,17 @@ public class IrsConfig { String endpoint; - public IrsConfig(String endpoint) { - this.endpoint = endpoint; - } + Paths paths; + public IrsConfig() { } + public IrsConfig(String endpoint, Paths paths) { + this.endpoint = endpoint; + this.paths = paths; + } + public String getEndpoint() { return endpoint; } @@ -47,4 +51,32 @@ public String getEndpoint() { public void setEndpoint(String endpoint) { this.endpoint = endpoint; } + + public Paths getPaths() { + return paths; + } + + public void setPaths(Paths paths) { + this.paths = paths; + } + + public static class Paths{ + String job; + + public Paths(String job) { + this.job = job; + } + + public Paths() { + } + + public String getJob() { + return job; + } + + public void setJob(String job) { + this.job = job; + } + } + } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index af5678488..0543c0bbc 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -35,12 +35,10 @@ import org.eclipse.tractusx.productpass.services.AuthenticationService; import org.eclipse.tractusx.productpass.services.IrsService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import utils.HttpUtil; import utils.JsonUtil; +import utils.LogUtil; @RestController @RequestMapping("/api/irs") @@ -59,18 +57,13 @@ public class IrsController { private @Autowired IrsConfig irsConfig; private @Autowired IrsService irsService; - @RequestMapping(value = "/search", method = RequestMethod.GET) - @Operation(summary = "Search for tree of ids in IRS") - public Response search() { + @RequestMapping(value = "/endpoint", method = RequestMethod.POST) + @Operation(summary = "Listening endpoint for IRS ready requests") + public Response endpoint(@RequestBody Object body) { Response response = httpUtil.getInternalError(); - // Check for authentication - if (!authService.isAuthenticated(httpRequest)) { - response = httpUtil.getNotAuthorizedResponse(); - return httpUtil.buildResponse(response, httpResponse); - } + LogUtil.printMessage(jsonUtil.toJson(body, true)); try { response = httpUtil.getResponse("IRS is not available at the moment!"); - response.data = irsService.searchComponents(null); return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { response.message = e.getMessage(); @@ -79,4 +72,5 @@ public Response search() { } + } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java new file mode 100644 index 000000000..166c6281d --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java @@ -0,0 +1,174 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.irs; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Job { + @JsonProperty("id") + String id; + + @JsonProperty("globalAssetId") + String globalAssetId; + + @JsonProperty("state") + String state; + + @JsonProperty("exception") + Object exception; + + @JsonProperty("createdOn") + String createdOn; + + @JsonProperty("startedOn") + String startedOn; + + @JsonProperty("lastModifiedOn") + String lastModifiedOn; + + @JsonProperty("completedOn") + String completedOn; + + @JsonProperty("owner") + String owner; + + @JsonProperty("summary") + Object summary; + + @JsonProperty("parameter") + JobRequest parameter; + + public Job() { + } + + public Job(String id, String globalAssetId, String state, Object exception, String createdOn, String startedOn, String lastModifiedOn, String completedOn, String owner, Object summary, JobRequest parameter) { + this.id = id; + this.globalAssetId = globalAssetId; + this.state = state; + this.exception = exception; + this.createdOn = createdOn; + this.startedOn = startedOn; + this.lastModifiedOn = lastModifiedOn; + this.completedOn = completedOn; + this.owner = owner; + this.summary = summary; + this.parameter = parameter; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getGlobalAssetId() { + return globalAssetId; + } + + public void setGlobalAssetId(String globalAssetId) { + this.globalAssetId = globalAssetId; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Object getException() { + return exception; + } + + public void setException(Object exception) { + this.exception = exception; + } + + public String getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(String createdOn) { + this.createdOn = createdOn; + } + + public String getStartedOn() { + return startedOn; + } + + public void setStartedOn(String startedOn) { + this.startedOn = startedOn; + } + + public String getLastModifiedOn() { + return lastModifiedOn; + } + + public void setLastModifiedOn(String lastModifiedOn) { + this.lastModifiedOn = lastModifiedOn; + } + + public String getCompletedOn() { + return completedOn; + } + + public void setCompletedOn(String completedOn) { + this.completedOn = completedOn; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public Object getSummary() { + return summary; + } + + public void setSummary(Object summary) { + this.summary = summary; + } + + public JobRequest getParameter() { + return parameter; + } + + public void setParameter(JobRequest parameter) { + this.parameter = parameter; + } +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java index 2f29ebab0..ebe6a0754 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java @@ -56,6 +56,9 @@ public class JobRequest { @JsonProperty("direction") String direction; + @JsonProperty("callbackUrl") + String callbackUrl; + @JsonProperty("depth") Integer depth; @@ -79,6 +82,16 @@ public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookup public JobRequest() { } + public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookupBPNs, Boolean collectAspects, String direction, Integer depth, Boolean integrityCheck) { + this.aspects = aspects; + this.bomLifecycle = bomLifecycle; + this.lookupBPNs = lookupBPNs; + this.collectAspects = collectAspects; + this.direction = direction; + this.depth = depth; + this.integrityCheck = integrityCheck; + } + public ArrayList getAspects() { return aspects; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java new file mode 100644 index 000000000..7014d87f1 --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java @@ -0,0 +1,111 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.irs; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; + +import java.util.ArrayList; +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JobResponse { + + @JsonProperty("job") + Job job; + @JsonProperty("relationships") + ArrayList relationships; + @JsonProperty("shells") + ArrayList shells; + @JsonProperty("tombstones") + Object tombstones; + @JsonProperty("submodels") + ArrayList submodels; + @JsonProperty("bpns") + ArrayList bpns; + + public JobResponse(Job job, ArrayList relationships, ArrayList shells, Object tombstones, ArrayList submodels, ArrayList bpns) { + this.job = job; + this.relationships = relationships; + this.shells = shells; + this.tombstones = tombstones; + this.submodels = submodels; + this.bpns = bpns; + } + + public JobResponse() { + } + + public Job getJob() { + return job; + } + + public void setJob(Job job) { + this.job = job; + } + + public ArrayList getRelationships() { + return relationships; + } + + public void setRelationships(ArrayList relationships) { + this.relationships = relationships; + } + + public ArrayList getShells() { + return shells; + } + + public void setShells(ArrayList shells) { + this.shells = shells; + } + + public Object getTombstones() { + return tombstones; + } + + public void setTombstones(Object tombstones) { + this.tombstones = tombstones; + } + + public ArrayList getSubmodels() { + return submodels; + } + + public void setSubmodels(ArrayList submodels) { + this.submodels = submodels; + } + + public ArrayList getBpns() { + return bpns; + } + + public void setBpns(ArrayList bpns) { + this.bpns = bpns; + } +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Relationship.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Relationship.java new file mode 100644 index 000000000..855e7160b --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Relationship.java @@ -0,0 +1,220 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.irs; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Relationship { + @JsonProperty("catenaXId") + String catenaXId; + @JsonProperty("linkedItem") + Item linkedItem; + @JsonProperty("aspectType") + String aspectType; + @JsonProperty("bpn") + String bpn; + + public Relationship() { + } + + public Relationship(String catenaXId, Item linkedItem, String aspectType, String bpn) { + this.catenaXId = catenaXId; + this.linkedItem = linkedItem; + this.aspectType = aspectType; + this.bpn = bpn; + } + + public String getCatenaXId() { + return catenaXId; + } + + public void setCatenaXId(String catenaXId) { + this.catenaXId = catenaXId; + } + + public Item getLinkedItem() { + return linkedItem; + } + + public void setLinkedItem(Item linkedItem) { + this.linkedItem = linkedItem; + } + + public String getAspectType() { + return aspectType; + } + + public void setAspectType(String aspectType) { + this.aspectType = aspectType; + } + + public String getBpn() { + return bpn; + } + + public void setBpn(String bpn) { + this.bpn = bpn; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class Item { + + @JsonProperty("quantity") + Quantity quantity; + @JsonProperty("licecycleContext") + String licecycleContext; + @JsonProperty("assembledOn") + String assembledOn; + @JsonProperty("lastModifiedOn") + String lastModifiedOn; + @JsonProperty("childCatenaXId") + String childCatenaXId; + + public Item(Quantity quantity, String licecycleContext, String assembledOn, String lastModifiedOn, String childCatenaXId) { + this.quantity = quantity; + this.licecycleContext = licecycleContext; + this.assembledOn = assembledOn; + this.lastModifiedOn = lastModifiedOn; + this.childCatenaXId = childCatenaXId; + } + + public Item() { + } + + public Quantity getQuantity() { + return quantity; + } + + public void setQuantity(Quantity quantity) { + this.quantity = quantity; + } + + public String getLicecycleContext() { + return licecycleContext; + } + + public void setLicecycleContext(String licecycleContext) { + this.licecycleContext = licecycleContext; + } + + public String getAssembledOn() { + return assembledOn; + } + + public void setAssembledOn(String assembledOn) { + this.assembledOn = assembledOn; + } + + public String getLastModifiedOn() { + return lastModifiedOn; + } + + public void setLastModifiedOn(String lastModifiedOn) { + this.lastModifiedOn = lastModifiedOn; + } + + public String getChildCatenaXId() { + return childCatenaXId; + } + + public void setChildCatenaXId(String childCatenaXId) { + this.childCatenaXId = childCatenaXId; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class Quantity{ + @JsonProperty("quantityNumber") + Double quantityNumber; + @JsonProperty("measurementUnit") + MeasurementUnit measurementUnit; + + public Quantity(Double quantityNumber, MeasurementUnit measurementUnit) { + this.quantityNumber = quantityNumber; + this.measurementUnit = measurementUnit; + } + + public Quantity() { + } + + public Double getQuantityNumber() { + return quantityNumber; + } + + public void setQuantityNumber(Double quantityNumber) { + this.quantityNumber = quantityNumber; + } + + public MeasurementUnit getMeasurementUnit() { + return measurementUnit; + } + + public void setMeasurementUnit(MeasurementUnit measurementUnit) { + this.measurementUnit = measurementUnit; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class MeasurementUnit{ + @JsonProperty("datatypeURI") + String datatypeURI; + @JsonProperty("lexicalValue") + String lexicalValue; + + public MeasurementUnit(String datatypeURI, String lexicalValue) { + this.datatypeURI = datatypeURI; + this.lexicalValue = lexicalValue; + } + + public MeasurementUnit() { + } + + public String getDatatypeURI() { + return datatypeURI; + } + + public void setDatatypeURI(String datatypeURI) { + this.datatypeURI = datatypeURI; + } + + public String getLexicalValue() { + return lexicalValue; + } + + public void setLexicalValue(String lexicalValue) { + this.lexicalValue = lexicalValue; + } + } + + } + } + +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 46ebaee0d..0f1637610 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -24,10 +24,14 @@ package org.eclipse.tractusx.productpass.services; import com.fasterxml.jackson.databind.JsonNode; +import org.checkerframework.checker.units.qual.K; import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.exceptions.ServiceInitializationException; import org.eclipse.tractusx.productpass.models.catenax.Discovery; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; +import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; +import org.eclipse.tractusx.productpass.models.irs.Job; import org.eclipse.tractusx.productpass.models.irs.JobRequest; import org.eclipse.tractusx.productpass.models.service.BaseService; import org.springframework.beans.factory.annotation.Autowired; @@ -57,48 +61,90 @@ public class IrsService extends BaseService { JsonUtil jsonUtil; String irsEndpoint; + String irsJobPath; + AuthenticationService authService; IrsConfig irsConfig; + VaultService vaultService; @Autowired - public IrsService(Environment env, IrsConfig irsConfig, HttpUtil httpUtil, JsonUtil jsonUtil,AuthenticationService authService) throws ServiceInitializationException { + public IrsService(Environment env, IrsConfig irsConfig, HttpUtil httpUtil,VaultService vaultService, JsonUtil jsonUtil,AuthenticationService authService) throws ServiceInitializationException { this.httpUtil = httpUtil; this.jsonUtil = jsonUtil; this.authService = authService; this.irsConfig = irsConfig; + this.vaultService = vaultService; this.init(env); } - public Object startJob(){ + public Object startJob(String globalAssetId) throws ServiceException{ + try { + // In case the BPN is not known use the backend BPN. + return this.startJob(globalAssetId, (String) this.vaultService.getLocalSecret("edc.bpn")); + }catch (Exception e){ + throw new ServiceException(this.getClass().getName()+"."+"startJob", + e, + "It was not possible to start a IRS job! Because of invalid BPN configuration!"); + } + } + + public Map startJob(String globalAssetId, String bpn){ try { this.checkEmptyVariables(); - // Add body - Object body = Map.of( - "searchParam", search + String url = this.irsEndpoint + "/" + this.irsJobPath; + // Build the Job request for the IRS + JobRequest body = new JobRequest( + new ArrayList<>(), + "asBuilt", + false, + false, + "downward", + 1, + false ); - + body.setKey(globalAssetId, bpn); HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); headers.add("Content-Type", "application/json"); - ResponseEntity response = httpUtil.doPost(this.irsEndpoint, JsonNode.class, headers, httpUtil.getParams(), body, false, false); + ResponseEntity response = httpUtil.doPost(url, JsonNode.class, headers, httpUtil.getParams(), body, false, false); JsonNode result = (JsonNode) response.getBody(); - return jsonUtil.bindJsonNode(result, Object.class); + return (Map) jsonUtil.bindJsonNode(result, Map.class); }catch (Exception e){ - throw new ServiceException(this.getClass().getName()+"."+"searchComponents", + throw new ServiceException(this.getClass().getName()+"."+"startJob", e, - "It was not possible to search for the drill down of components!"); + "It was not possible to start a IRS job!"); } } + public Job getJob(String jobId) { + try { + String url = this.irsEndpoint + "/" + this.irsJobPath + "/" + jobId; + Map params = httpUtil.getParams(); + HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); + ResponseEntity response = httpUtil.doGet(url, String.class, headers, params, true, false); + String responseBody = (String) response.getBody(); + return (Job) jsonUtil.bindJsonNode(jsonUtil.toJsonNode(responseBody), Job.class); + } catch (Exception e) { + throw new ServiceException(this.getClass().getName() + "." + "getJob", + e, + "It was not possible to get the IRS job!"); + } + + } + @Override public List getEmptyVariables() { List missingVariables = new ArrayList<>(); if (this.irsEndpoint.isEmpty()) { missingVariables.add("irs.endpoint"); } + if (this.irsJobPath.isEmpty()) { + missingVariables.add("irs.paths.job"); + } return missingVariables; } public void init(Environment env){ this.irsEndpoint = this.irsConfig.getEndpoint(); + this.irsJobPath = this.irsConfig.getPaths().getJob(); } } diff --git a/consumer-backend/productpass/src/main/resources/application.yml b/consumer-backend/productpass/src/main/resources/application.yml index e9f99defc..372d1eea2 100644 --- a/consumer-backend/productpass/src/main/resources/application.yml +++ b/consumer-backend/productpass/src/main/resources/application.yml @@ -62,6 +62,8 @@ configuration: irs: endpoint: "https://materialpass-irs.int.demo.catena-x.net" + paths: + job: "/irs/jobs" dtr: central: false From cff7982aafd2d761f300e5135f5c67010b6fc917 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Mon, 2 Oct 2023 16:24:54 +0200 Subject: [PATCH 03/25] feat: created irs initial integration mend --- .../productpass/http/controllers/api/IrsController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index 0543c0bbc..e8719047c 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -57,7 +57,7 @@ public class IrsController { private @Autowired IrsConfig irsConfig; private @Autowired IrsService irsService; - @RequestMapping(value = "/endpoint", method = RequestMethod.POST) + @RequestMapping(value = "/endpoint", method = RequestMethod.GET) @Operation(summary = "Listening endpoint for IRS ready requests") public Response endpoint(@RequestBody Object body) { Response response = httpUtil.getInternalError(); From d014afd4fbad1fee79efdc415e80087bd15d939a Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Wed, 4 Oct 2023 17:29:15 +0200 Subject: [PATCH 04/25] feat: created irs tree manager and datamodel initial structure --- .../productpass/config/IrsConfig.java | 50 +- .../http/controllers/AppController.java | 8 +- .../http/controllers/api/IrsController.java | 48 +- .../productpass/managers/TreeDataModel.java | 50 ++ .../productpass/managers/TreeManager.java | 83 ++ .../productpass/models/irs/JobRequest.java | 20 + .../productpass/models/manager/Node.java | 155 ++++ .../productpass/services/IrsService.java | 32 +- .../src/main/resources/application.yml | 5 +- deployment/helm/edc-consumer/ssa.json | 761 ++++++++++++++++++ 10 files changed, 1196 insertions(+), 16 deletions(-) create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java create mode 100644 deployment/helm/edc-consumer/ssa.json diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java index 77fc77008..46a1b809e 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java @@ -25,6 +25,7 @@ package org.eclipse.tractusx.productpass.config; +import com.sun.source.tree.Tree; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @@ -33,17 +34,21 @@ public class IrsConfig { String endpoint; + TreeConfig tree; + Paths paths; public IrsConfig() { } - public IrsConfig(String endpoint, Paths paths) { + public IrsConfig(String endpoint, TreeConfig tree, Paths paths) { this.endpoint = endpoint; + this.tree = tree; this.paths = paths; } + public String getEndpoint() { return endpoint; } @@ -60,6 +65,49 @@ public void setPaths(Paths paths) { this.paths = paths; } + public TreeConfig getTree() { + return tree; + } + + public void setTree(TreeConfig tree) { + this.tree = tree; + } + + + public static class TreeConfig{ + String fileName; + + Boolean indent; + + public TreeConfig(String fileName) { + this.fileName = fileName; + } + + public TreeConfig(String fileName, Boolean indent) { + this.fileName = fileName; + this.indent = indent; + } + + public TreeConfig() { + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Boolean getIndent() { + return indent; + } + + public void setIndent(Boolean indent) { + this.indent = indent; + } + } + public static class Paths{ String job; 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 228d1370a..fe8847cb1 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 @@ -47,6 +47,7 @@ import org.eclipse.tractusx.productpass.models.passports.Passport; import org.eclipse.tractusx.productpass.services.AasService; import org.eclipse.tractusx.productpass.services.DataPlaneService; +import org.eclipse.tractusx.productpass.services.IrsService; import org.sonarsource.scanner.api.internal.shaded.minimaljson.Json; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; @@ -78,6 +79,9 @@ public class AppController { PassportUtil passportUtil; @Autowired AasService aasService; + + @Autowired + IrsService irsService; @Autowired DataPlaneService dataPlaneService; @@ -182,9 +186,11 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr if (connectorAddress.isEmpty() || assetId.isEmpty()) { LogUtil.printError("Failed to parse endpoint [" + connectorAddress + "] or the assetId is not found!"); } + String bpn = dtr.getBpn(); processManager.setEndpoint(processId, connectorAddress); - processManager.setBpn(processId, dtr.getBpn()); + processManager.setBpn(processId,bpn); processManager.saveDigitalTwin3(processId, digitalTwin, dtRequestTime); + irsService.getChildren(processId, digitalTwin, bpn); 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( assetId, diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index e8719047c..5c308ee23 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -31,6 +31,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.tractusx.productpass.config.IrsConfig; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.http.Response; import org.eclipse.tractusx.productpass.services.AuthenticationService; import org.eclipse.tractusx.productpass.services.IrsService; @@ -40,6 +41,8 @@ import utils.JsonUtil; import utils.LogUtil; +import java.util.Map; + @RestController @RequestMapping("/api/irs") @Tag(name = "IRS Controller") @@ -55,13 +58,14 @@ public class IrsController { private @Autowired JsonUtil jsonUtil; private @Autowired IrsConfig irsConfig; + private @Autowired IrsService irsService; - @RequestMapping(value = "/endpoint", method = RequestMethod.GET) - @Operation(summary = "Listening endpoint for IRS ready requests") - public Response endpoint(@RequestBody Object body) { + @RequestMapping(value = "/{processId}/ready", method = RequestMethod.GET) + @Operation(summary = "Endpoint called by the IRS to set status completed") + public Response endpoint( @PathVariable String processId) { Response response = httpUtil.getInternalError(); - LogUtil.printMessage(jsonUtil.toJson(body, true)); + LogUtil.printMessage(jsonUtil.toJson(httpRequest, true)); try { response = httpUtil.getResponse("IRS is not available at the moment!"); return httpUtil.buildResponse(response, httpResponse); @@ -71,6 +75,42 @@ public Response endpoint(@RequestBody Object body) { } } + @RequestMapping(value = "/{processId}/tree", method = RequestMethod.GET) + @Operation(summary = "Api called by the frontend to obtain the tree of components") + public Response tree( @PathVariable String processId) { + Response response = httpUtil.getInternalError(); + if (!authService.isAuthenticated(httpRequest)) { + response = httpUtil.getNotAuthorizedResponse(); + return httpUtil.buildResponse(response, httpResponse); + } + try { + response = httpUtil.getResponse("IRS is not available at the moment!"); + return httpUtil.buildResponse(response, httpResponse); + } catch (Exception e) { + response.message = e.getMessage(); + return httpUtil.buildResponse(response, httpResponse); + } + } + + @RequestMapping(value = "/{processId}/tree/create", method = RequestMethod.POST) + @Operation(summary = "Api called by the frontend to obtain the tree of components") + public Response create(@PathVariable String processId, @RequestBody String body) { + Response response = httpUtil.getInternalError(); + if (!authService.isAuthenticated(httpRequest)) { + response = httpUtil.getNotAuthorizedResponse(); + return httpUtil.buildResponse(response, httpResponse); + } + String jobId = this.irsService.getChildren(processId,(DigitalTwin3) jsonUtil.loadJson(body, DigitalTwin3.class), "BPNL00000000CBA5"); + try { + response = httpUtil.getResponse("IRS Job created!"); + response.data = Map.of("jobId",jobId); + return httpUtil.buildResponse(response, httpResponse); + } catch (Exception e) { + response.message = e.getMessage(); + return httpUtil.buildResponse(response, httpResponse); + } + } + } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java new file mode 100644 index 000000000..002594d5f --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java @@ -0,0 +1,50 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.managers; + +import org.eclipse.tractusx.productpass.models.manager.Node; +import org.springframework.stereotype.Component; + +import java.util.Map; +@Component +public class TreeDataModel { + + + public Map dataModel; + + + public TreeDataModel(Map dataModel) { + this.dataModel = dataModel; + } + + public Map getDataModel() { + return dataModel; + } + + public void setDataModel(Map dataModel) { + this.dataModel = dataModel; + } +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java new file mode 100644 index 000000000..e2a9f54b3 --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -0,0 +1,83 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.managers; + +import org.eclipse.tractusx.productpass.config.IrsConfig; +import org.eclipse.tractusx.productpass.exceptions.ManagerException; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; +import org.eclipse.tractusx.productpass.models.manager.Node; +import org.eclipse.tractusx.productpass.models.manager.Status; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import utils.DateTimeUtil; +import utils.FileUtil; +import utils.JsonUtil; + +import java.util.Map; +@Component +public class TreeManager { + private FileUtil fileUtil; + private JsonUtil jsonUtil; + + private ProcessManager processManager; + + private IrsConfig irsConfig; + + @Autowired + public TreeManager(FileUtil fileUtil, JsonUtil jsonUtil, ProcessManager processManager, IrsConfig irsConfig) { + this.fileUtil = fileUtil; + this.jsonUtil = jsonUtil; + this.processManager = processManager; + this.irsConfig = irsConfig; + } + + public String newTreeFile(String processId, DigitalTwin3 digitalTwin){ + try { + String path = processManager.getProcessFilePath(processId, this.irsConfig.getTree().getFileName()); + TreeDataModel treeDataModel = new TreeDataModel( + Map.of( + digitalTwin.getIdentification(), + new Node( + digitalTwin + ) + ) + ); + return jsonUtil.toJsonFile( + path, + treeDataModel.dataModel, + this.irsConfig.getTree().getIndent() + ); // Store the plain JSON + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "It was not possible to create the tree data model file"); + } + } + + + + + + +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java index ebe6a0754..13309fdd9 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java @@ -92,6 +92,18 @@ public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookup this.integrityCheck = integrityCheck; } + public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookupBPNs, Boolean collectAspects, String direction, Integer depth, Boolean integrityCheck, Key key, String callbackUrl) { + this.aspects = aspects; + this.bomLifecycle = bomLifecycle; + this.lookupBPNs = lookupBPNs; + this.collectAspects = collectAspects; + this.direction = direction; + this.callbackUrl = callbackUrl; + this.depth = depth; + this.integrityCheck = integrityCheck; + this.key = key; + } + public ArrayList getAspects() { return aspects; } @@ -160,6 +172,14 @@ public void setKey(String globalAssetId, String bpn) { this.key = new Key(globalAssetId, bpn); } + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) static class Key { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java new file mode 100644 index 000000000..712276ff4 --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java @@ -0,0 +1,155 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.manager; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.eclipse.tractusx.productpass.managers.TreeDataModel; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; + +import java.util.Map; +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Node { + + @JsonProperty("id") + String id; + @JsonProperty("globalAssetId") + String globalAssetId; + @JsonProperty("idShort") + String idShort; + @JsonProperty("path") + String path; + @JsonProperty("digitalTwin") + DigitalTwin3 digitalTwin; + @JsonProperty("children") + Map children; + + + public Node(Node parent, DigitalTwin3 digitalTwin, Map children){ + this.setup(digitalTwin); + this.setPath(parent, digitalTwin.getIdentification()); + this.children = children; + } + + public Node(String parentPath, DigitalTwin3 digitalTwin, Map children){ + this.setup(digitalTwin); + this.setPath(parentPath, digitalTwin.getIdentification()); + this.children = children; + } + + public Node(DigitalTwin3 digitalTwin, Map children){ + this.setup(digitalTwin); + this.setPath("", digitalTwin.getIdentification()); + this.children = children; + } + public Node(Node parent, DigitalTwin3 digitalTwin){ + this.setup(digitalTwin); + this.setPath(parent, digitalTwin.getIdentification()); + this.children = Map.of(); + } + + public Node(String parentPath, DigitalTwin3 digitalTwin){ + this.setup(digitalTwin); + this.setPath(parentPath, digitalTwin.getIdentification()); + this.children = Map.of(); + } + + public Node(DigitalTwin3 digitalTwin){ + this.setup(digitalTwin); + this.setPath("", digitalTwin.getIdentification()); + this.children = Map.of(); + } + + public void setup(DigitalTwin3 digitalTwin){ + this.id = digitalTwin.getIdentification(); + this.globalAssetId = digitalTwin.getGlobalAssetId(); + this.idShort = digitalTwin.getIdShort(); + this.digitalTwin = digitalTwin; + } + public Node(String id, String globalAssetId, String idShort, String path, DigitalTwin3 digitalTwin, Map children) { + this.id = id; + this.globalAssetId = globalAssetId; + this.idShort = idShort; + this.path = path; + this.digitalTwin = digitalTwin; + this.children = children; + } + + public Node() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getGlobalAssetId() { + return globalAssetId; + } + + public void setGlobalAssetId(String globalAssetId) { + this.globalAssetId = globalAssetId; + } + + public String getIdShort() { + return idShort; + } + + public void setIdShort(String idShort) { + this.idShort = idShort; + } + + public String getPath() { + return path; + } + public void setPath(Node parentNode, String id) { + this.path = parentNode.getPath()+"/"+id; + } + public void setPath(String parentPath, String id) { + this.path = parentPath+"/"+id; + } + + public DigitalTwin3 getDigitalTwin() { + return digitalTwin; + } + + public void setDigitalTwin(DigitalTwin3 digitalTwin) { + this.digitalTwin = digitalTwin; + } + + public Map getChildren() { + return children; + } + + public void setChildren(Map children) { + this.children = children; + } +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 0f1637610..1cb098a45 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -28,8 +28,10 @@ import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.exceptions.ServiceInitializationException; +import org.eclipse.tractusx.productpass.managers.TreeManager; import org.eclipse.tractusx.productpass.models.catenax.Discovery; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; import org.eclipse.tractusx.productpass.models.irs.Job; import org.eclipse.tractusx.productpass.models.irs.JobRequest; @@ -51,7 +53,6 @@ * *

It contains all the methods and properties to communicate with the IRS Service. * Its is called by the IRS Controller and can be used by managers to update information. - * */ @Service public class IrsService extends BaseService { @@ -65,29 +66,32 @@ public class IrsService extends BaseService { AuthenticationService authService; IrsConfig irsConfig; + TreeManager treeManager; VaultService vaultService; + @Autowired - public IrsService(Environment env, IrsConfig irsConfig, HttpUtil httpUtil,VaultService vaultService, JsonUtil jsonUtil,AuthenticationService authService) throws ServiceInitializationException { + public IrsService(Environment env, IrsConfig irsConfig, TreeManager treeManager, HttpUtil httpUtil, VaultService vaultService, JsonUtil jsonUtil, AuthenticationService authService) throws ServiceInitializationException { this.httpUtil = httpUtil; this.jsonUtil = jsonUtil; this.authService = authService; this.irsConfig = irsConfig; + this.treeManager = treeManager; this.vaultService = vaultService; this.init(env); } - public Object startJob(String globalAssetId) throws ServiceException{ + public Object startJob(String globalAssetId) throws ServiceException { try { // In case the BPN is not known use the backend BPN. return this.startJob(globalAssetId, (String) this.vaultService.getLocalSecret("edc.bpn")); - }catch (Exception e){ - throw new ServiceException(this.getClass().getName()+"."+"startJob", + } catch (Exception e) { + throw new ServiceException(this.getClass().getName() + "." + "startJob", e, "It was not possible to start a IRS job! Because of invalid BPN configuration!"); } } - public Map startJob(String globalAssetId, String bpn){ + public Map startJob(String globalAssetId, String bpn) { try { this.checkEmptyVariables(); String url = this.irsEndpoint + "/" + this.irsJobPath; @@ -108,13 +112,23 @@ public Map startJob(String globalAssetId, String bpn){ ResponseEntity response = httpUtil.doPost(url, JsonNode.class, headers, httpUtil.getParams(), body, false, false); JsonNode result = (JsonNode) response.getBody(); return (Map) jsonUtil.bindJsonNode(result, Map.class); - }catch (Exception e){ - throw new ServiceException(this.getClass().getName()+"."+"startJob", + } catch (Exception e) { + throw new ServiceException(this.getClass().getName() + "." + "startJob", e, "It was not possible to start a IRS job!"); } } + public String getChildren(String processId, DigitalTwin3 digitalTwin, String bpn) { + try { + Map irsResponse = this.startJob(digitalTwin.getGlobalAssetId(), bpn); + this.treeManager.newTreeFile(processId, digitalTwin); + return irsResponse.get("id"); + } catch (Exception e) { + throw new ServiceException(this.getClass().getName() + "." + "getChildren", e, "It was not possible to get the children for the digital twin [" + digitalTwin.getIdentification() + "]"); + } + } + public Job getJob(String jobId) { try { String url = this.irsEndpoint + "/" + this.irsJobPath + "/" + jobId; @@ -143,7 +157,7 @@ public List getEmptyVariables() { return missingVariables; } - public void init(Environment env){ + public void init(Environment env) { this.irsEndpoint = this.irsConfig.getEndpoint(); this.irsJobPath = this.irsConfig.getPaths().getJob(); } diff --git a/consumer-backend/productpass/src/main/resources/application.yml b/consumer-backend/productpass/src/main/resources/application.yml index 372d1eea2..58e88fbc1 100644 --- a/consumer-backend/productpass/src/main/resources/application.yml +++ b/consumer-backend/productpass/src/main/resources/application.yml @@ -56,7 +56,7 @@ configuration: security: check: - enabled: true + enabled: false bpn: true edc: true @@ -64,6 +64,9 @@ configuration: endpoint: "https://materialpass-irs.int.demo.catena-x.net" paths: job: "/irs/jobs" + tree: + fileName: "treeDataModel" + indent: true dtr: central: false diff --git a/deployment/helm/edc-consumer/ssa.json b/deployment/helm/edc-consumer/ssa.json new file mode 100644 index 000000000..e5dd4bad5 --- /dev/null +++ b/deployment/helm/edc-consumer/ssa.json @@ -0,0 +1,761 @@ +{ + "job": { + "id": "fbb710e6-699c-4313-8c13-cceafb93a9c2", + "globalAssetId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "state": "RUNNING", + "exception": null, + "createdOn": "2023-10-02T07:09:22.438292594Z", + "startedOn": "2023-10-02T07:09:22.438635117Z", + "lastModifiedOn": "2023-10-02T07:14:07.391429828Z", + "completedOn": null, + "owner": "sa241", + "summary": { + "asyncFetchedItems": { + "running": 30, + "completed": 5, + "failed": 4 + }, + "bpnLookups": { + "completed": 0, + "failed": 0 + } + }, + "parameter": { + "bomLifecycle": "asBuilt", + "aspects": [ + "SerialPart" + ], + "depth": 1, + "bpn": "BPNL00000000CBA5", + "direction": "downward", + "collectAspects": false, + "lookupBPNs": false, + "callbackUrl": null + } + }, + "relationships": [ + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:a550bcb2-6ed2-49e6-b718-2012b82cfc9b" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:4ac27014-519f-4dce-ba81-4316966dcd78" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:42e551d0-5f6a-4c6b-abdc-bf18093f3a21" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:6db600e1-5e27-4502-b4e9-1597cd02f701" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:6e49506c-6f7e-4700-8a1a-3ba173fffe12" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:ccb8f629-fb93-49b9-82d8-2623054cfe81" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:eeed1b1c-dcdc-457e-a586-2308fb729824" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:63b95496-86ed-4762-b248-491d5c1242e1" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AVTH" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:c686418b-a89a-4a00-b646-c66ba6903479" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:e4229df7-35ea-49d6-bf58-e661f4461cd3" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AYRE" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:21bd3a19-dbe8-4b4d-b7fd-46a41bd4ecc0" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:56d5f82b-a94e-4a41-9041-47c503e382fe" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:d676d79b-0969-485b-a83d-c8ddb1d2a362" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AVTH" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:f4fe84cf-3958-4283-b369-a6a2beb8e27f" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:032bbf5a-0d3d-42af-a1da-61bb8a0b1256" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AYRE" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:8398b9c6-58fd-47f1-9822-347c02f6f4a4" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:d6497d89-2646-424a-afde-fd802678a786" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:defb27a1-f206-4217-ba61-3ed18e9f6938" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AVTH" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:fdc11263-e4ad-4fd6-9d34-744e2139f835" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:fa5aa5a6-e466-486d-bb82-d3cbe9d470c7" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:b82ae3c0-3338-49e5-89d7-b0622092c6ae" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:d8ec6acc-1ad7-47b4-bc7e-612122d9d552" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AYRE" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:423bbf30-8b0a-4b62-add8-b667dd7f41c4" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AYRE" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:83c76460-4cc7-4edd-99bb-e265779426f3" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000003AVTH" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:abba905f-24f6-4835-82b8-1b805a88d52c" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:8bf3349d-ace7-49cb-96d8-57c5e3fc02aa" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:c985b586-396a-4b36-8b81-0ede61ac7a2f" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:201e493b-8d25-4276-ab2b-6b5350c4a67d" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:5d2e8e8c-913f-48f7-b967-62bbf434ad79" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:c97f5701-b527-427f-8231-3c5f68665f16" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:7ccf273b-bef6-490b-aee0-87972970bb96" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:1b91f9c0-63d5-4b8a-87af-ec32bfe40b1a" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:3b4fbc56-f33e-460b-932f-8a3d0bb07e5e" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + }, + { + "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "linkedItem": { + "quantity": { + "quantityNumber": 2.5, + "measurementUnit": { + "datatypeURI": null, + "lexicalValue": "unit:litre" + } + }, + "lifecycleContext": "asBuilt", + "assembledOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z", + "childCatenaXId": "urn:uuid:c480badd-44bb-4a67-97ca-943fe598e7b0" + }, + "aspectType": "SingleLevelBomAsBuilt", + "bpn": "BPNL00000000CBA5" + } + ], + "shells": [ + { + "administration": null, + "description": [], + "globalAssetId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", + "idShort": "VehicleCombustion", + "id": "urn:uuid:ed064c32-a9b0-487e-ab34-ee6000e5db78", + "specificAssetIds": [ + { + "name": "manufacturerId", + "subjectId": null, + "value": "BPNL00000000CBA5", + "semanticId": null + }, + { + "name": "van", + "subjectId": null, + "value": "OMCOFCRMXMBASAFZY", + "semanticId": null + }, + { + "name": "manufacturerPartId", + "subjectId": null, + "value": "CV-87", + "semanticId": null + }, + { + "name": "partInstanceId", + "subjectId": null, + "value": "OMCOFCRMXMBASAFZY", + "semanticId": null + } + ], + "submodelDescriptors": [ + { + "administration": null, + "description": [], + "idShort": "SerialPart", + "id": "urn:uuid:4702ba73-e5d5-4743-bfaa-7309013cccab", + "semanticId": { + "keys": [ + { + "value": "urn:bamm:io.catenax.serial_part:1.0.1#SerialPart", + "type": "GlobalReference" + } + ], + "type": "ExternalReference" + }, + "endpoints": [ + { + "protocolInformation": { + "href": "https://materialpass.int.demo.catena-x.net/BPNL000000000000/api/public/data/urn:uuid:4702ba73-e5d5-4743-bfaa-7309013cccab", + "endpointProtocol": "HTTP", + "endpointProtocolVersion": [ + "1.1" + ], + "subprotocol": "DSP", + "subprotocolBody": "id=urn:uuid:7eeef127-3687-4c36-be77-55af3db8cff2;dspEndpoint=https://materialpass.int.demo.catena-x.net/BPNL000000000000", + "subprotocolBodyEncoding": "plain" + }, + "interface": "SUBMODEL-3.0" + } + ] + } + ] + } + ], + "tombstones": [ + { + "catenaXId": "urn:uuid:63b95496-86ed-4762-b248-491d5c1242e1", + "endpointURL": null, + "processingError": { + "processStep": "DigitalTwinRequest", + "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", + "lastAttempt": "2023-10-02T07:14:05.976166927Z", + "retryCounter": 3 + } + }, + { + "catenaXId": "urn:uuid:d676d79b-0969-485b-a83d-c8ddb1d2a362", + "endpointURL": null, + "processingError": { + "processStep": "DigitalTwinRequest", + "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", + "lastAttempt": "2023-10-02T07:14:06.207893051Z", + "retryCounter": 3 + } + }, + { + "catenaXId": "urn:uuid:defb27a1-f206-4217-ba61-3ed18e9f6938", + "endpointURL": null, + "processingError": { + "processStep": "DigitalTwinRequest", + "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", + "lastAttempt": "2023-10-02T07:14:06.585485484Z", + "retryCounter": 3 + } + }, + { + "catenaXId": "urn:uuid:83c76460-4cc7-4edd-99bb-e265779426f3", + "endpointURL": null, + "processingError": { + "processStep": "DigitalTwinRequest", + "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", + "lastAttempt": "2023-10-02T07:14:06.974591483Z", + "retryCounter": 3 + } + } + ], + "submodels": [], + "bpns": [] +} \ No newline at end of file From 15dd54b65242225fcf2f6b15d0bdc9b33b7c1075 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Fri, 6 Oct 2023 13:27:18 +0200 Subject: [PATCH 05/25] feat: added callback logic to irs and job call --- .../http/controllers/api/IrsController.java | 7 +- .../productpass/managers/ProcessManager.java | 31 + .../productpass/models/irs/JobRequest.java | 11 +- .../productpass/models/manager/Status.java | 29 + .../productpass/services/IrsService.java | 34 +- .../src/main/java/utils/HttpUtil.java | 14 +- .../src/main/resources/application.yml | 1 + deployment/helm/edc-consumer/ssa.json | 761 ------------------ deployment/helm/registry/values.yaml | 2 +- 9 files changed, 116 insertions(+), 774 deletions(-) delete mode 100644 deployment/helm/edc-consumer/ssa.json diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index 5c308ee23..667b57da8 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -61,12 +61,14 @@ public class IrsController { private @Autowired IrsService irsService; - @RequestMapping(value = "/{processId}/ready", method = RequestMethod.GET) + @RequestMapping(value = "/{processId}", method = RequestMethod.GET) @Operation(summary = "Endpoint called by the IRS to set status completed") - public Response endpoint( @PathVariable String processId) { + public Response endpoint(@PathVariable String processId, @RequestParam String id, @RequestParam String state) { Response response = httpUtil.getInternalError(); LogUtil.printMessage(jsonUtil.toJson(httpRequest, true)); try { + LogUtil.printMessage("["+processId+"] Requesting Job ["+id+"] after state ["+state+"]"); + LogUtil.printMessage(jsonUtil.toJson(this.irsService.getJob(id), true)); response = httpUtil.getResponse("IRS is not available at the moment!"); return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { @@ -102,6 +104,7 @@ public Response create(@PathVariable String processId, @RequestBody String body) } String jobId = this.irsService.getChildren(processId,(DigitalTwin3) jsonUtil.loadJson(body, DigitalTwin3.class), "BPNL00000000CBA5"); try { + response = httpUtil.getResponse("IRS Job created!"); response.data = Map.of("jobId",jobId); 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 07e3c5e98..36dc7ca93 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 @@ -248,6 +248,7 @@ public String addSearchStatusDtr(String processId, Dtr dtr) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to create/update the search status file"); } } + public String initProcess() { try { String processId = CrypUtil.getUUID(); @@ -330,7 +331,37 @@ public String setBpn(String processId, String bpn) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to create/update the status file"); } } + public String getJobId(String processId, String globalAssetId) { + 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); + return statusFile.getJobId(globalAssetId); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "It was not possible to create/update the status file"); + } + } + public String setJobId(String processId, String globalAssetId, String jobId) { + 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.addJobId(globalAssetId, jobId); + statusFile.setHistory(jobId, new History(jobId, "DRILLDOWN-STARTED")); + 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 create/update the status file"); + } + } public String setStatus(String processId, String historyId, History history) { try { String path = this.getProcessFilePath(processId, this.metaFileName); diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java index 13309fdd9..c3a4450ae 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java @@ -91,7 +91,16 @@ public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookup this.depth = depth; this.integrityCheck = integrityCheck; } - + public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookupBPNs, Boolean collectAspects, String direction, Integer depth, Boolean integrityCheck, String callbackUrl) { + this.aspects = aspects; + this.bomLifecycle = bomLifecycle; + this.lookupBPNs = lookupBPNs; + this.collectAspects = collectAspects; + this.direction = direction; + this.callbackUrl = callbackUrl; + this.depth = depth; + this.integrityCheck = integrityCheck; + } public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookupBPNs, Boolean collectAspects, String direction, Integer depth, Boolean integrityCheck, Key key, String callbackUrl) { this.aspects = aspects; this.bomLifecycle = bomLifecycle; 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 95f8a9138..75edb387f 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 @@ -47,6 +47,8 @@ public class Status { @JsonProperty("modified") public Long modified; + @JsonProperty("jobs") + public Map jobs; @JsonProperty("endpoint") public String endpoint; @@ -155,6 +157,18 @@ public Status(String id, String status, Long created, Long modified, String endp this.bpn = bpn; this.history = Map.of(historyId, history); } + + public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, Map history) { + this.id = id; + this.status = status; + this.created = created; + this.modified = modified; + this.jobs = jobs; + this.endpoint = endpoint; + this.bpn = bpn; + this.history = history; + } + public String getId() { return id; } @@ -230,6 +244,21 @@ public String getBpn() { public void setBpn(String bpn) { this.bpn = bpn; } + + public Map getJobs() { + return jobs; + } + + public void setJobs(Map jobs) { + this.jobs = jobs; + } + + public void addJobId(String globalAssetId, String jobId){ + this.jobs.put(globalAssetId, jobId); + } + public String getJobId(String globalAssetId){ + return this.jobs.get(globalAssetId); + } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 1cb098a45..581c2e5e2 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -28,6 +28,7 @@ import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.exceptions.ServiceInitializationException; +import org.eclipse.tractusx.productpass.managers.ProcessManager; import org.eclipse.tractusx.productpass.managers.TreeManager; import org.eclipse.tractusx.productpass.models.catenax.Discovery; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; @@ -43,7 +44,9 @@ import org.springframework.stereotype.Service; import utils.HttpUtil; import utils.JsonUtil; +import utils.LogUtil; +import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -66,12 +69,14 @@ public class IrsService extends BaseService { AuthenticationService authService; IrsConfig irsConfig; + ProcessManager processManager; TreeManager treeManager; VaultService vaultService; @Autowired - public IrsService(Environment env, IrsConfig irsConfig, TreeManager treeManager, HttpUtil httpUtil, VaultService vaultService, JsonUtil jsonUtil, AuthenticationService authService) throws ServiceInitializationException { + public IrsService(Environment env, ProcessManager processManager, IrsConfig irsConfig, TreeManager treeManager, HttpUtil httpUtil, VaultService vaultService, JsonUtil jsonUtil, AuthenticationService authService) throws ServiceInitializationException { this.httpUtil = httpUtil; + this.processManager = processManager; this.jsonUtil = jsonUtil; this.authService = authService; this.irsConfig = irsConfig; @@ -80,10 +85,13 @@ public IrsService(Environment env, IrsConfig irsConfig, TreeManager treeManager, this.init(env); } - public Object startJob(String globalAssetId) throws ServiceException { + public IrsService() { + } + + public Object startJob(String processId, String globalAssetId) throws ServiceException { try { // In case the BPN is not known use the backend BPN. - return this.startJob(globalAssetId, (String) this.vaultService.getLocalSecret("edc.bpn")); + return this.startJob(processId, globalAssetId, (String) this.vaultService.getLocalSecret("edc.bpn")); } catch (Exception e) { throw new ServiceException(this.getClass().getName() + "." + "startJob", e, @@ -91,11 +99,19 @@ public Object startJob(String globalAssetId) throws ServiceException { } } - public Map startJob(String globalAssetId, String bpn) { + public Map startJob(String processId, String globalAssetId, String bpn) { try { this.checkEmptyVariables(); String url = this.irsEndpoint + "/" + this.irsJobPath; // Build the Job request for the IRS + + String backendUrl = InetAddress.getLocalHost().getCanonicalHostName() + "/api/irs/" + processId; + Map params = Map.of( + "id", globalAssetId, + "state", "COMPLETED" + ); + String callbackUrl = httpUtil.buildUrl(backendUrl, params, false); + LogUtil.printMessage("Backend CallBack Url: "+callbackUrl); JobRequest body = new JobRequest( new ArrayList<>(), "asBuilt", @@ -103,7 +119,8 @@ public Map startJob(String globalAssetId, String bpn) { false, "downward", 1, - false + false, + callbackUrl ); body.setKey(globalAssetId, bpn); HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); @@ -121,9 +138,12 @@ public Map startJob(String globalAssetId, String bpn) { public String getChildren(String processId, DigitalTwin3 digitalTwin, String bpn) { try { - Map irsResponse = this.startJob(digitalTwin.getGlobalAssetId(), bpn); + String globalAssetId = digitalTwin.getGlobalAssetId(); + Map irsResponse = this.startJob(processId,globalAssetId, bpn); this.treeManager.newTreeFile(processId, digitalTwin); - return irsResponse.get("id"); + String jobId = irsResponse.get("id"); + this.processManager.setJobId(processId,globalAssetId,jobId); + return jobId; } catch (Exception e) { throw new ServiceException(this.getClass().getName() + "." + "getChildren", e, "It was not possible to get the children for the digital twin [" + digitalTwin.getIdentification() + "]"); } diff --git a/consumer-backend/productpass/src/main/java/utils/HttpUtil.java b/consumer-backend/productpass/src/main/java/utils/HttpUtil.java index 9e88f9f05..d2a447366 100644 --- a/consumer-backend/productpass/src/main/java/utils/HttpUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/HttpUtil.java @@ -128,6 +128,7 @@ public String getAuthorizationToken(HttpServletRequest httpRequest){ } return token; } + /* public String buildUrl(String url, Map params, Boolean encode){ StringBuilder finalUrl = new StringBuilder(url); for(Map.Entry entry : params.entrySet()){ @@ -142,8 +143,9 @@ public String buildUrl(String url, Map params, Boolean encode){ finalUrl.append("?").append(entry.getKey()).append("=").append(value); } return finalUrl.toString(); - } - public String mapToParams(Map params, Boolean encode){ + }*/ + + public String mapToParams(Map params, Boolean encode){ StringBuilder finalUrl = new StringBuilder(); for(Map.Entry entry : params.entrySet()){ @@ -350,6 +352,14 @@ public URI buildUri(String url, Map params, Boolean encoded){ return builder.build(encoded).toUri(); } + public String buildUrl(String url, Map params, Boolean encoded){ + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url); + for(Map.Entry entry : params.entrySet()){ + builder.queryParam(entry.getKey(), entry.getValue()); + } + return builder.build(encoded).toUriString(); + } + /************************************************** * Generic Request Methods ************************ **************************************************/ diff --git a/consumer-backend/productpass/src/main/resources/application.yml b/consumer-backend/productpass/src/main/resources/application.yml index 58e88fbc1..9537b0af2 100644 --- a/consumer-backend/productpass/src/main/resources/application.yml +++ b/consumer-backend/productpass/src/main/resources/application.yml @@ -67,6 +67,7 @@ configuration: tree: fileName: "treeDataModel" indent: true + callbackUrl: "https://materialpass.int.demo.catena-x.net/api/irs" dtr: central: false diff --git a/deployment/helm/edc-consumer/ssa.json b/deployment/helm/edc-consumer/ssa.json deleted file mode 100644 index e5dd4bad5..000000000 --- a/deployment/helm/edc-consumer/ssa.json +++ /dev/null @@ -1,761 +0,0 @@ -{ - "job": { - "id": "fbb710e6-699c-4313-8c13-cceafb93a9c2", - "globalAssetId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "state": "RUNNING", - "exception": null, - "createdOn": "2023-10-02T07:09:22.438292594Z", - "startedOn": "2023-10-02T07:09:22.438635117Z", - "lastModifiedOn": "2023-10-02T07:14:07.391429828Z", - "completedOn": null, - "owner": "sa241", - "summary": { - "asyncFetchedItems": { - "running": 30, - "completed": 5, - "failed": 4 - }, - "bpnLookups": { - "completed": 0, - "failed": 0 - } - }, - "parameter": { - "bomLifecycle": "asBuilt", - "aspects": [ - "SerialPart" - ], - "depth": 1, - "bpn": "BPNL00000000CBA5", - "direction": "downward", - "collectAspects": false, - "lookupBPNs": false, - "callbackUrl": null - } - }, - "relationships": [ - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:a550bcb2-6ed2-49e6-b718-2012b82cfc9b" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:4ac27014-519f-4dce-ba81-4316966dcd78" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:42e551d0-5f6a-4c6b-abdc-bf18093f3a21" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:6db600e1-5e27-4502-b4e9-1597cd02f701" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:6e49506c-6f7e-4700-8a1a-3ba173fffe12" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:ccb8f629-fb93-49b9-82d8-2623054cfe81" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:eeed1b1c-dcdc-457e-a586-2308fb729824" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:63b95496-86ed-4762-b248-491d5c1242e1" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AVTH" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:c686418b-a89a-4a00-b646-c66ba6903479" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:e4229df7-35ea-49d6-bf58-e661f4461cd3" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AYRE" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:21bd3a19-dbe8-4b4d-b7fd-46a41bd4ecc0" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:56d5f82b-a94e-4a41-9041-47c503e382fe" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:d676d79b-0969-485b-a83d-c8ddb1d2a362" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AVTH" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:f4fe84cf-3958-4283-b369-a6a2beb8e27f" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:032bbf5a-0d3d-42af-a1da-61bb8a0b1256" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AYRE" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:8398b9c6-58fd-47f1-9822-347c02f6f4a4" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:d6497d89-2646-424a-afde-fd802678a786" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:defb27a1-f206-4217-ba61-3ed18e9f6938" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AVTH" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:fdc11263-e4ad-4fd6-9d34-744e2139f835" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:fa5aa5a6-e466-486d-bb82-d3cbe9d470c7" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:b82ae3c0-3338-49e5-89d7-b0622092c6ae" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:d8ec6acc-1ad7-47b4-bc7e-612122d9d552" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AYRE" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:423bbf30-8b0a-4b62-add8-b667dd7f41c4" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AYRE" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:83c76460-4cc7-4edd-99bb-e265779426f3" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000003AVTH" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:abba905f-24f6-4835-82b8-1b805a88d52c" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:8bf3349d-ace7-49cb-96d8-57c5e3fc02aa" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:c985b586-396a-4b36-8b81-0ede61ac7a2f" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:201e493b-8d25-4276-ab2b-6b5350c4a67d" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:5d2e8e8c-913f-48f7-b967-62bbf434ad79" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:c97f5701-b527-427f-8231-3c5f68665f16" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:7ccf273b-bef6-490b-aee0-87972970bb96" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:1b91f9c0-63d5-4b8a-87af-ec32bfe40b1a" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:3b4fbc56-f33e-460b-932f-8a3d0bb07e5e" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - }, - { - "catenaXId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "linkedItem": { - "quantity": { - "quantityNumber": 2.5, - "measurementUnit": { - "datatypeURI": null, - "lexicalValue": "unit:litre" - } - }, - "lifecycleContext": "asBuilt", - "assembledOn": "2022-02-03T14:48:54.709Z", - "lastModifiedOn": "2022-02-03T14:48:54.709Z", - "childCatenaXId": "urn:uuid:c480badd-44bb-4a67-97ca-943fe598e7b0" - }, - "aspectType": "SingleLevelBomAsBuilt", - "bpn": "BPNL00000000CBA5" - } - ], - "shells": [ - { - "administration": null, - "description": [], - "globalAssetId": "urn:uuid:efcb5f8d-f31c-4b1f-b090-9c878054554d", - "idShort": "VehicleCombustion", - "id": "urn:uuid:ed064c32-a9b0-487e-ab34-ee6000e5db78", - "specificAssetIds": [ - { - "name": "manufacturerId", - "subjectId": null, - "value": "BPNL00000000CBA5", - "semanticId": null - }, - { - "name": "van", - "subjectId": null, - "value": "OMCOFCRMXMBASAFZY", - "semanticId": null - }, - { - "name": "manufacturerPartId", - "subjectId": null, - "value": "CV-87", - "semanticId": null - }, - { - "name": "partInstanceId", - "subjectId": null, - "value": "OMCOFCRMXMBASAFZY", - "semanticId": null - } - ], - "submodelDescriptors": [ - { - "administration": null, - "description": [], - "idShort": "SerialPart", - "id": "urn:uuid:4702ba73-e5d5-4743-bfaa-7309013cccab", - "semanticId": { - "keys": [ - { - "value": "urn:bamm:io.catenax.serial_part:1.0.1#SerialPart", - "type": "GlobalReference" - } - ], - "type": "ExternalReference" - }, - "endpoints": [ - { - "protocolInformation": { - "href": "https://materialpass.int.demo.catena-x.net/BPNL000000000000/api/public/data/urn:uuid:4702ba73-e5d5-4743-bfaa-7309013cccab", - "endpointProtocol": "HTTP", - "endpointProtocolVersion": [ - "1.1" - ], - "subprotocol": "DSP", - "subprotocolBody": "id=urn:uuid:7eeef127-3687-4c36-be77-55af3db8cff2;dspEndpoint=https://materialpass.int.demo.catena-x.net/BPNL000000000000", - "subprotocolBodyEncoding": "plain" - }, - "interface": "SUBMODEL-3.0" - } - ] - } - ] - } - ], - "tombstones": [ - { - "catenaXId": "urn:uuid:63b95496-86ed-4762-b248-491d5c1242e1", - "endpointURL": null, - "processingError": { - "processStep": "DigitalTwinRequest", - "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", - "lastAttempt": "2023-10-02T07:14:05.976166927Z", - "retryCounter": 3 - } - }, - { - "catenaXId": "urn:uuid:d676d79b-0969-485b-a83d-c8ddb1d2a362", - "endpointURL": null, - "processingError": { - "processStep": "DigitalTwinRequest", - "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", - "lastAttempt": "2023-10-02T07:14:06.207893051Z", - "retryCounter": 3 - } - }, - { - "catenaXId": "urn:uuid:defb27a1-f206-4217-ba61-3ed18e9f6938", - "endpointURL": null, - "processingError": { - "processStep": "DigitalTwinRequest", - "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", - "lastAttempt": "2023-10-02T07:14:06.585485484Z", - "retryCounter": 3 - } - }, - { - "catenaXId": "urn:uuid:83c76460-4cc7-4edd-99bb-e265779426f3", - "endpointURL": null, - "processingError": { - "processStep": "DigitalTwinRequest", - "errorDetail": "EndpointDataReference was not found. Requested connectorEndpoints: ", - "lastAttempt": "2023-10-02T07:14:06.974591483Z", - "retryCounter": 3 - } - } - ], - "submodels": [], - "bpns": [] -} \ No newline at end of file diff --git a/deployment/helm/registry/values.yaml b/deployment/helm/registry/values.yaml index a112b28a6..e85ff2e89 100644 --- a/deployment/helm/registry/values.yaml +++ b/deployment/helm/registry/values.yaml @@ -64,4 +64,4 @@ provider-dtr: auth: username: password: - database: default-database + database: default-database \ No newline at end of file From cf0c5c415208f80278d489932423bf08b2cb9c6c Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Fri, 6 Oct 2023 14:40:05 +0200 Subject: [PATCH 06/25] feat: set callback url in application.yaml --- .../tractusx/productpass/config/IrsConfig.java | 17 +++++++++++++++++ .../productpass/services/IrsService.java | 5 +++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java index 46a1b809e..f36092282 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java @@ -38,6 +38,8 @@ public class IrsConfig { Paths paths; + String callbackUrl; + public IrsConfig() { } @@ -48,6 +50,13 @@ public IrsConfig(String endpoint, TreeConfig tree, Paths paths) { this.paths = paths; } + public IrsConfig(String endpoint, TreeConfig tree, Paths paths, String callbackUrl) { + this.endpoint = endpoint; + this.tree = tree; + this.paths = paths; + this.callbackUrl = callbackUrl; + } + public String getEndpoint() { return endpoint; @@ -73,6 +82,14 @@ public void setTree(TreeConfig tree) { this.tree = tree; } + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + public static class TreeConfig{ String fileName; diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 581c2e5e2..c8fd42253 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -66,7 +66,7 @@ public class IrsService extends BaseService { String irsEndpoint; String irsJobPath; - + String callbackUrl; AuthenticationService authService; IrsConfig irsConfig; ProcessManager processManager; @@ -105,7 +105,7 @@ public Map startJob(String processId, String globalAssetId, Stri String url = this.irsEndpoint + "/" + this.irsJobPath; // Build the Job request for the IRS - String backendUrl = InetAddress.getLocalHost().getCanonicalHostName() + "/api/irs/" + processId; + String backendUrl = this.callbackUrl +"/" + processId; Map params = Map.of( "id", globalAssetId, "state", "COMPLETED" @@ -180,5 +180,6 @@ public List getEmptyVariables() { public void init(Environment env) { this.irsEndpoint = this.irsConfig.getEndpoint(); this.irsJobPath = this.irsConfig.getPaths().getJob(); + this.callbackUrl = this.irsConfig.getCallbackUrl(); } } From c274e431aa3aa966aa2da8db1030dccd1dde72b8 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Mon, 9 Oct 2023 13:27:28 +0200 Subject: [PATCH 07/25] feat: added init for JobId --- .../eclipse/tractusx/productpass/models/manager/Status.java | 3 +++ 1 file changed, 3 insertions(+) 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 75edb387f..3c1b9d1b5 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 @@ -254,6 +254,9 @@ public void setJobs(Map jobs) { } public void addJobId(String globalAssetId, String jobId){ + if(this.jobs == null){ + this.jobs = Map.of(); + } this.jobs.put(globalAssetId, jobId); } public String getJobId(String globalAssetId){ From 0874daf8707499595994c4162fe3bf0f5e6ecdf7 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Mon, 9 Oct 2023 19:22:25 +0200 Subject: [PATCH 08/25] feat: added logic to parse tree node and update tree --- .../http/controllers/AppController.java | 15 ++- .../http/controllers/api/IrsController.java | 51 ++++---- .../productpass/managers/ProcessManager.java | 33 ++++- .../productpass/managers/TreeDataModel.java | 50 ------- .../productpass/managers/TreeManager.java | 123 +++++++++++++++--- .../productpass/models/irs/JobHistory.java | 86 ++++++++++++ .../productpass/models/manager/Node.java | 36 ++++- .../productpass/models/manager/Status.java | 39 ++++-- .../productpass/services/IrsService.java | 36 +++-- .../src/main/java/utils/JsonUtil.java | 14 +- .../src/main/java/utils/StringUtil.java | 2 + 11 files changed, 369 insertions(+), 116 deletions(-) delete mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java 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 fe8847cb1..bd70c27c6 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 @@ -35,6 +35,7 @@ import org.eclipse.tractusx.productpass.config.ProcessConfig; import org.eclipse.tractusx.productpass.exceptions.ControllerException; import org.eclipse.tractusx.productpass.managers.ProcessManager; +import org.eclipse.tractusx.productpass.managers.TreeManager; import org.eclipse.tractusx.productpass.models.catenax.Dtr; import org.eclipse.tractusx.productpass.models.dtregistry.*; import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; @@ -42,6 +43,7 @@ import org.eclipse.tractusx.productpass.models.http.Response; import org.eclipse.tractusx.productpass.models.http.requests.Search; import org.eclipse.tractusx.productpass.models.manager.History; +import org.eclipse.tractusx.productpass.models.manager.Node; import org.eclipse.tractusx.productpass.models.manager.SearchStatus; import org.eclipse.tractusx.productpass.models.manager.Status; import org.eclipse.tractusx.productpass.models.passports.Passport; @@ -82,6 +84,9 @@ public class AppController { @Autowired IrsService irsService; + + @Autowired + TreeManager treeManager; @Autowired DataPlaneService dataPlaneService; @@ -190,7 +195,15 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr processManager.setEndpoint(processId, connectorAddress); processManager.setBpn(processId,bpn); processManager.saveDigitalTwin3(processId, digitalTwin, dtRequestTime); - irsService.getChildren(processId, digitalTwin, bpn); + + // Update tree + String globalAssetId = digitalTwin.getGlobalAssetId(); + String actualPath = status.getTreeState() + "/" + globalAssetId; + processManager.setTreeState(processId, actualPath); + this.treeManager.setNodeByPath(processId, actualPath, new Node(digitalTwin)); + + // Get children from the node + this.irsService.getChildren(processId, actualPath, globalAssetId, bpn); 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( assetId, diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index 667b57da8..db3349617 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -31,8 +31,15 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.tractusx.productpass.config.IrsConfig; +import org.eclipse.tractusx.productpass.managers.ProcessManager; +import org.eclipse.tractusx.productpass.managers.TreeManager; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.http.Response; +import org.eclipse.tractusx.productpass.models.irs.Job; +import org.eclipse.tractusx.productpass.models.irs.JobHistory; +import org.eclipse.tractusx.productpass.models.irs.JobResponse; +import org.eclipse.tractusx.productpass.models.manager.Node; +import org.eclipse.tractusx.productpass.models.manager.Status; import org.eclipse.tractusx.productpass.services.AuthenticationService; import org.eclipse.tractusx.productpass.services.IrsService; import org.springframework.beans.factory.annotation.Autowired; @@ -60,15 +67,34 @@ public class IrsController { private @Autowired IrsConfig irsConfig; private @Autowired IrsService irsService; + private @Autowired TreeManager treeManager; + private @Autowired ProcessManager processManager; - @RequestMapping(value = "/{processId}", method = RequestMethod.GET) + @RequestMapping(value = "/{processId}/{searchId}", method = RequestMethod.GET) @Operation(summary = "Endpoint called by the IRS to set status completed") - public Response endpoint(@PathVariable String processId, @RequestParam String id, @RequestParam String state) { + public Response endpoint(@PathVariable String processId,@PathVariable String searchId, @RequestParam String id, @RequestParam String state) { Response response = httpUtil.getInternalError(); LogUtil.printMessage(jsonUtil.toJson(httpRequest, true)); try { + if (!processManager.checkProcess(processId)) { + return httpUtil.buildResponse(httpUtil.getNotFound("Process not found!"), httpResponse); + } + + Status status = processManager.getStatus(processId); + if(status == null){ + return httpUtil.buildResponse(httpUtil.getNotFound("No status is created"), httpResponse); + } + + if(!status.getJobs().containsKey(searchId)){ + return httpUtil.buildResponse(httpUtil.getNotFound("The search id is invalid!"), httpResponse); + } + + JobHistory jobHistory = status.getJobId(searchId); + LogUtil.printMessage("["+processId+"] Requesting Job ["+id+"] after state ["+state+"]"); - LogUtil.printMessage(jsonUtil.toJson(this.irsService.getJob(id), true)); + JobResponse irsJob = this.irsService.getJob(id); + LogUtil.printMessage(jsonUtil.toJson(irsJob, true)); + this.treeManager.updateNode(processId, jobHistory.getPath(), irsJob); response = httpUtil.getResponse("IRS is not available at the moment!"); return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { @@ -94,25 +120,6 @@ public Response tree( @PathVariable String processId) { } } - @RequestMapping(value = "/{processId}/tree/create", method = RequestMethod.POST) - @Operation(summary = "Api called by the frontend to obtain the tree of components") - public Response create(@PathVariable String processId, @RequestBody String body) { - Response response = httpUtil.getInternalError(); - if (!authService.isAuthenticated(httpRequest)) { - response = httpUtil.getNotAuthorizedResponse(); - return httpUtil.buildResponse(response, httpResponse); - } - String jobId = this.irsService.getChildren(processId,(DigitalTwin3) jsonUtil.loadJson(body, DigitalTwin3.class), "BPNL00000000CBA5"); - try { - - response = httpUtil.getResponse("IRS Job created!"); - response.data = Map.of("jobId",jobId); - return httpUtil.buildResponse(response, httpResponse); - } catch (Exception e) { - response.message = e.getMessage(); - 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 36dc7ca93..47406e159 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 @@ -35,6 +35,7 @@ import org.eclipse.tractusx.productpass.models.edc.Jwt; import org.eclipse.tractusx.productpass.models.http.requests.Search; import org.eclipse.tractusx.productpass.models.http.responses.IdResponse; +import org.eclipse.tractusx.productpass.models.irs.JobHistory; import org.eclipse.tractusx.productpass.models.manager.History; import org.eclipse.tractusx.productpass.models.manager.Process; import org.eclipse.tractusx.productpass.models.manager.SearchStatus; @@ -288,9 +289,13 @@ public String newStatusFile(String processId, String connectorAddress, Long crea new Status( processId, "CREATED", - connectorAddress, created, - DateTimeUtil.getTimestamp() + DateTimeUtil.getTimestamp(), + Map.of(), + connectorAddress, + "", + "", + Map.of() ), processConfig.getIndent()); // Store the plain JSON } catch (Exception e) { @@ -331,7 +336,23 @@ public String setBpn(String processId, String bpn) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to create/update the status file"); } } - public String getJobId(String processId, String globalAssetId) { + public String setTreeState(String processId, String state) { + 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.setTreeState(state); + 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 create/update the status file"); + } + } + public JobHistory getJobHistoryById(String processId, String globalAssetId) { try { String path = this.getProcessFilePath(processId, this.metaFileName); Status statusFile = null; @@ -345,7 +366,7 @@ public String getJobId(String processId, String globalAssetId) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to create/update the status file"); } } - public String setJobId(String processId, String globalAssetId, String jobId) { + public String addJobHistory(String processId, String searchId, JobHistory jobHistory) { try { String path = this.getProcessFilePath(processId, this.metaFileName); Status statusFile = null; @@ -354,8 +375,8 @@ public String setJobId(String processId, String globalAssetId, String jobId) { } statusFile = (Status) jsonUtil.fromJsonFileToObject(path, Status.class); - statusFile.addJobId(globalAssetId, jobId); - statusFile.setHistory(jobId, new History(jobId, "DRILLDOWN-STARTED")); + statusFile.addJobHistory(searchId, jobHistory); + statusFile.setHistory(searchId, new History(searchId, searchId+"-DRILLDOWN-STARTED")); statusFile.setModified(DateTimeUtil.getTimestamp()); return jsonUtil.toJsonFile(path, statusFile, processConfig.getIndent()); // Store the plain JSON } catch (Exception e) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java deleted file mode 100644 index 002594d5f..000000000 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeDataModel.java +++ /dev/null @@ -1,50 +0,0 @@ -/********************************************************************************* - * - * Catena-X - Product Passport Consumer Backend - * - * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA - * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. - * - * - * 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.managers; - -import org.eclipse.tractusx.productpass.models.manager.Node; -import org.springframework.stereotype.Component; - -import java.util.Map; -@Component -public class TreeDataModel { - - - public Map dataModel; - - - public TreeDataModel(Map dataModel) { - this.dataModel = dataModel; - } - - public Map getDataModel() { - return dataModel; - } - - public void setDataModel(Map dataModel) { - this.dataModel = dataModel; - } -} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index e2a9f54b3..74f7c27d9 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -28,14 +28,17 @@ import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.exceptions.ManagerException; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; +import org.eclipse.tractusx.productpass.models.irs.Job; +import org.eclipse.tractusx.productpass.models.irs.JobResponse; +import org.eclipse.tractusx.productpass.models.irs.Relationship; import org.eclipse.tractusx.productpass.models.manager.Node; import org.eclipse.tractusx.productpass.models.manager.Status; +import org.eclipse.tractusx.productpass.models.negotiation.Negotiation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import utils.DateTimeUtil; -import utils.FileUtil; -import utils.JsonUtil; +import utils.*; +import java.util.List; import java.util.Map; @Component public class TreeManager { @@ -46,6 +49,7 @@ public class TreeManager { private IrsConfig irsConfig; + private final String PATH_SEP = "/"; @Autowired public TreeManager(FileUtil fileUtil, JsonUtil jsonUtil, ProcessManager processManager, IrsConfig irsConfig) { this.fileUtil = fileUtil; @@ -54,27 +58,116 @@ public TreeManager(FileUtil fileUtil, JsonUtil jsonUtil, ProcessManager processM this.irsConfig = irsConfig; } - public String newTreeFile(String processId, DigitalTwin3 digitalTwin){ + public String getTreeFilePath(String processId){ + return processManager.getProcessFilePath(processId, this.irsConfig.getTree().getFileName()); + } + public Boolean treeExists(String processId){ + String path = this.getTreeFilePath(processId); + return fileUtil.pathExists(path); + } + public String createTreeFile(String processId){ + try { + return this.saveTree(processId, Map.of()); // Save the tree + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".newTree()", e, "It was not possible to create the tree data model file"); + } + } + public static String generateSearchId(String processId, String globalAssetId) { + return CrypUtil.md5(DateTimeUtil.getDateTimeFormatted("yyyyMMddHHmmssSSS") + processId + globalAssetId); + } + public Map loadTree(String processId){ try { - String path = processManager.getProcessFilePath(processId, this.irsConfig.getTree().getFileName()); - TreeDataModel treeDataModel = new TreeDataModel( - Map.of( - digitalTwin.getIdentification(), - new Node( - digitalTwin - ) - ) - ); + String path = this.getTreeFilePath(processId); // Get filepath from tree + if(!fileUtil.pathExists(path)){ + this.createTreeFile(processId); // Create empty tree + return Map.of(); + } + return (Map) jsonUtil.fromJsonFileToObject(path, Map.class); // Store the plain JSON + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".loadTree()", e, "It was not possible to load the tree"); + } + } + + public String updateNode(String processId, String path, JobResponse job) { + try { + Map treeDataModel = this.loadTree(processId); + Node node = this.getNodeByPath(treeDataModel, path); // Get parent node + node.setJob(job); // Set the job in the node + List relationships = job.getRelationships(); + LogUtil.printMessage(jsonUtil.toJson(relationships, true)); + treeDataModel = this.setNodeByPath(treeDataModel, path, node); // Save the parent node in the tree + return this.saveTree(processId, treeDataModel); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName() + ".setChild()", e, "It was not possible to get the node from the tree"); + } + } + + public String saveTree(String processId, Map treeDataModel){ + try { + String path = this.getTreeFilePath(processId); // Get filepath from tree return jsonUtil.toJsonFile( path, - treeDataModel.dataModel, + treeDataModel, this.irsConfig.getTree().getIndent() ); // Store the plain JSON } catch (Exception e) { - throw new ManagerException(this.getClass().getName(), e, "It was not possible to create the tree data model file"); + throw new ManagerException(this.getClass().getName()+".saveTree()", e, "It was not possible to save the tree data model file"); + } + } + public Node getNodeByPath(Map treeDataModel, String path){ + try { + String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children + return (Node) this.jsonUtil.getValue(treeDataModel, translatedPath, ".", null); // Get the node + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".getNodeByPath()", e, "It was not possible to get the node from the tree"); + } + } + public Node getNodeByPath(String processId, String path){ + try { + Map treeDataModel = this.loadTree(processId); + String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children + return (Node) this.jsonUtil.getValue(treeDataModel, translatedPath, ".", null); // Get the node + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".getNodeByPath()", e, "It was not possible to get the node from the tree"); + } + } + public Map setNodeByPath(Map treeDataModel, String path, Node node){ + try { + String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children + treeDataModel = (Map) this.jsonUtil.setValue(treeDataModel, translatedPath, node, ".", null); // Set the node + if(treeDataModel == null){ // Check if the response was successful + throw new ManagerException(this.getClass().getName()+".setNodeByPath()", "It was not possible to set the node in path because the return was null"); + } + return treeDataModel; + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".setNodeByPath()", e, "It was not possible to get the node from the tree"); + } + } + public Object setNodeByPath(String processId, String path, Node node){ + try { + Map treeDataModel = this.loadTree(processId); + String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children + treeDataModel = (Map) this.jsonUtil.setValue(treeDataModel, translatedPath, node, ".", null); // Set the node + if(treeDataModel == null){ // Check if the response was successful + throw new ManagerException(this.getClass().getName()+".setNodeByPath()", "It was not possible to set the node in path because the return was null"); + } + return this.saveTree(processId, treeDataModel); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".setNodeByPath()", e, "It was not possible to get the node from the tree"); } } + public Object setChild(String processId, String parentPath, Node childNode){ + try { + Map treeDataModel = this.loadTree(processId); + Node parentNode = this.getNodeByPath(treeDataModel, parentPath); // Get parent node + parentNode.setChild(childNode); // Add the child to the parent node + treeDataModel = this.setNodeByPath(treeDataModel, parentPath, parentNode); // Save the parent node in the tree + return this.saveTree(processId, treeDataModel); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".setChild()", e, "It was not possible to get the node from the tree"); + } + } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java new file mode 100644 index 000000000..95bc3ac6b --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java @@ -0,0 +1,86 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.irs; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class JobHistory { + + @JsonProperty("jobId") + String jobId; + + @JsonProperty("globalAssetId") + String globalAssetId; + @JsonProperty("path") + String path; + @JsonProperty("created") + Long created; + + + + public JobHistory() { + } + + public JobHistory(String jobId, String globalAssetId, String path, Long created) { + this.jobId = jobId; + this.globalAssetId = globalAssetId; + this.path = path; + this.created = created; + } + + public String getJobId() { + return jobId; + } + + public void setJobId(String jobId) { + this.jobId = jobId; + } + + public String getGlobalAssetId() { + return globalAssetId; + } + + public void setGlobalAssetId(String globalAssetId) { + this.globalAssetId = globalAssetId; + } + + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java index 712276ff4..69fb260e4 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java @@ -28,8 +28,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import org.eclipse.tractusx.productpass.managers.TreeDataModel; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; +import org.eclipse.tractusx.productpass.models.irs.JobResponse; import java.util.Map; @JsonIgnoreProperties(ignoreUnknown = true) @@ -46,6 +46,10 @@ public class Node { String path; @JsonProperty("digitalTwin") DigitalTwin3 digitalTwin; + + @JsonProperty("job") + JobResponse job; + @JsonProperty("children") Map children; @@ -85,6 +89,16 @@ public Node(DigitalTwin3 digitalTwin){ this.children = Map.of(); } + public Node(String id, String globalAssetId, String idShort, String path, DigitalTwin3 digitalTwin, JobResponse job, Map children) { + this.id = id; + this.globalAssetId = globalAssetId; + this.idShort = idShort; + this.path = path; + this.digitalTwin = digitalTwin; + this.job = job; + this.children = children; + } + public void setup(DigitalTwin3 digitalTwin){ this.id = digitalTwin.getIdentification(); this.globalAssetId = digitalTwin.getGlobalAssetId(); @@ -152,4 +166,24 @@ public Map getChildren() { public void setChildren(Map children) { this.children = children; } + public void setChild(Node childNode){ + this.children.put(childNode.getId(), childNode); + } + + public Node getChild(String childId){ + return this.children.get(childId); + } + + + public void setPath(String path) { + this.path = path; + } + + public JobResponse getJob() { + return job; + } + + public void setJob(JobResponse job) { + this.job = job; + } } 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 3c1b9d1b5..0e1edf50a 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.eclipse.tractusx.productpass.models.irs.JobHistory; import utils.DateTimeUtil; import java.util.HashMap; @@ -48,13 +49,15 @@ public class Status { public Long modified; @JsonProperty("jobs") - public Map jobs; + public Map jobs; @JsonProperty("endpoint") public String endpoint; @JsonProperty("bpn") public String bpn; + @JsonProperty("treeState") + public String treeState; @JsonProperty("history") public Map history; @@ -158,7 +161,7 @@ public Status(String id, String status, Long created, Long modified, String endp this.history = Map.of(historyId, history); } - public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, Map history) { + public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, Map history) { this.id = id; this.status = status; this.created = created; @@ -169,6 +172,18 @@ public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, String treeState, Map history) { + this.id = id; + this.status = status; + this.created = created; + this.modified = modified; + this.jobs = jobs; + this.endpoint = endpoint; + this.bpn = bpn; + this.treeState = treeState; + this.history = history; + } + public String getId() { return id; } @@ -245,22 +260,30 @@ public void setBpn(String bpn) { this.bpn = bpn; } - public Map getJobs() { + public Map getJobs() { return jobs; } - public void setJobs(Map jobs) { + public void setJobs(Map jobs) { this.jobs = jobs; } - public void addJobId(String globalAssetId, String jobId){ + public void addJobHistory(String searchId, JobHistory jobHistory){ if(this.jobs == null){ this.jobs = Map.of(); } - this.jobs.put(globalAssetId, jobId); + this.jobs.put(searchId, jobHistory); + } + public JobHistory getJobId(String searchId){ + return this.jobs.get(searchId); } - public String getJobId(String globalAssetId){ - return this.jobs.get(globalAssetId); + + public String getTreeState() { + return treeState; + } + + public void setTreeState(String treeState) { + this.treeState = treeState; } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index c8fd42253..0d0b0291d 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -35,13 +35,16 @@ import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; import org.eclipse.tractusx.productpass.models.irs.Job; +import org.eclipse.tractusx.productpass.models.irs.JobHistory; import org.eclipse.tractusx.productpass.models.irs.JobRequest; +import org.eclipse.tractusx.productpass.models.irs.JobResponse; import org.eclipse.tractusx.productpass.models.service.BaseService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import utils.DateTimeUtil; import utils.HttpUtil; import utils.JsonUtil; import utils.LogUtil; @@ -88,10 +91,10 @@ public IrsService(Environment env, ProcessManager processManager, IrsConfig irsC public IrsService() { } - public Object startJob(String processId, String globalAssetId) throws ServiceException { + public Object startJob(String processId, String globalAssetId, String searchId) throws ServiceException { try { // In case the BPN is not known use the backend BPN. - return this.startJob(processId, globalAssetId, (String) this.vaultService.getLocalSecret("edc.bpn")); + return this.startJob(processId, globalAssetId, searchId, (String) this.vaultService.getLocalSecret("edc.bpn")); } catch (Exception e) { throw new ServiceException(this.getClass().getName() + "." + "startJob", e, @@ -99,13 +102,13 @@ public Object startJob(String processId, String globalAssetId) throws ServiceExc } } - public Map startJob(String processId, String globalAssetId, String bpn) { + public Map startJob(String processId, String globalAssetId, String searchId, String bpn) { try { this.checkEmptyVariables(); String url = this.irsEndpoint + "/" + this.irsJobPath; // Build the Job request for the IRS - String backendUrl = this.callbackUrl +"/" + processId; + String backendUrl = this.callbackUrl + "/" + processId + "/" + searchId; // Add process id and search id Map params = Map.of( "id", globalAssetId, "state", "COMPLETED" @@ -136,27 +139,36 @@ public Map startJob(String processId, String globalAssetId, Stri } } - public String getChildren(String processId, DigitalTwin3 digitalTwin, String bpn) { + public String getChildren(String processId, String path, String globalAssetId, String bpn) { try { - String globalAssetId = digitalTwin.getGlobalAssetId(); - Map irsResponse = this.startJob(processId,globalAssetId, bpn); - this.treeManager.newTreeFile(processId, digitalTwin); + String searchId = TreeManager.generateSearchId(processId, globalAssetId); + Long created = DateTimeUtil.getTimestamp(); + Map irsResponse = this.startJob(processId, globalAssetId, searchId, bpn); String jobId = irsResponse.get("id"); - this.processManager.setJobId(processId,globalAssetId,jobId); + this.processManager.addJobHistory( + processId, + searchId, + new JobHistory( + jobId, + globalAssetId, + path, + created + ) + ); return jobId; } catch (Exception e) { - throw new ServiceException(this.getClass().getName() + "." + "getChildren", e, "It was not possible to get the children for the digital twin [" + digitalTwin.getIdentification() + "]"); + throw new ServiceException(this.getClass().getName() + "." + "getChildren", e, "It was not possible to get the children for the digital twin"); } } - public Job getJob(String jobId) { + public JobResponse getJob(String jobId) { try { String url = this.irsEndpoint + "/" + this.irsJobPath + "/" + jobId; Map params = httpUtil.getParams(); HttpHeaders headers = httpUtil.getHeadersWithToken(this.authService.getToken().getAccessToken()); ResponseEntity response = httpUtil.doGet(url, String.class, headers, params, true, false); String responseBody = (String) response.getBody(); - return (Job) jsonUtil.bindJsonNode(jsonUtil.toJsonNode(responseBody), Job.class); + return (JobResponse) jsonUtil.bindJsonNode(jsonUtil.toJsonNode(responseBody), JobResponse.class); } catch (Exception e) { throw new ServiceException(this.getClass().getName() + "." + "getJob", e, diff --git a/consumer-backend/productpass/src/main/java/utils/JsonUtil.java b/consumer-backend/productpass/src/main/java/utils/JsonUtil.java index 699ef6488..97901fe83 100644 --- a/consumer-backend/productpass/src/main/java/utils/JsonUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/JsonUtil.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import io.netty.handler.codec.serialization.ObjectEncoder; +import org.eclipse.tractusx.productpass.exceptions.ManagerException; import org.eclipse.tractusx.productpass.models.catenax.EdcDiscoveryEndpoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; @@ -358,7 +359,18 @@ public JsonNode toJsonNode(Map json){ throw new UtilException(JsonUtil.class, "It was not possible to parse json -> [" + e.getMessage() + "]"); } } - + public String translatePathSep(String path, String pathSep, String newPathSep){ + try{ + String newPath = StringUtil.deepCopy(path); // Deep copy string + if(newPath.startsWith(pathSep)){ // If the path starts with the pathSep remove it so the search can be efficient + newPath = newPath.substring(1); + } + String[] parts = newPath.split(String.format("\\%s",pathSep)); // Split the path in order to get the parts + return String.join(String.format("\\%s",newPathSep), parts); // Join the path with the children + } catch (Exception e) { + throw new UtilException(JsonUtil.class, e, "It was not possible to translate te pathSep"); + } + } public Map toMap(Object obj){ ObjectMapper mapper = new ObjectMapper(); diff --git a/consumer-backend/productpass/src/main/java/utils/StringUtil.java b/consumer-backend/productpass/src/main/java/utils/StringUtil.java index 18003edf2..11a7818d8 100644 --- a/consumer-backend/productpass/src/main/java/utils/StringUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/StringUtil.java @@ -30,5 +30,7 @@ private StringUtil() { public static Boolean isEmpty(String s) { return s == null || s.length() == 0; } + + public static String deepCopy(String s){ return String.valueOf(s);} } From f0d2d7217869fad748a1780192fd9f4acae6d7e2 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Fri, 13 Oct 2023 17:39:58 +0200 Subject: [PATCH 09/25] feat: created algorithm to store the children from a digital twin from the job response --- .../http/controllers/api/IrsController.java | 2 +- .../productpass/managers/TreeManager.java | 38 ++++++++++++++++--- .../productpass/models/manager/Node.java | 2 +- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index db3349617..b261ddc2c 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -94,7 +94,7 @@ public Response endpoint(@PathVariable String processId,@PathVariable String sea LogUtil.printMessage("["+processId+"] Requesting Job ["+id+"] after state ["+state+"]"); JobResponse irsJob = this.irsService.getJob(id); LogUtil.printMessage(jsonUtil.toJson(irsJob, true)); - this.treeManager.updateNode(processId, jobHistory.getPath(), irsJob); + this.treeManager.populateTree(processId, jobHistory, irsJob); response = httpUtil.getResponse("IRS is not available at the moment!"); return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index 74f7c27d9..88e636eeb 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -27,8 +27,10 @@ import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.exceptions.ManagerException; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.irs.Job; +import org.eclipse.tractusx.productpass.models.irs.JobHistory; import org.eclipse.tractusx.productpass.models.irs.JobResponse; import org.eclipse.tractusx.productpass.models.irs.Relationship; import org.eclipse.tractusx.productpass.models.manager.Node; @@ -88,19 +90,43 @@ public Map loadTree(String processId){ } } - public String updateNode(String processId, String path, JobResponse job) { + public DigitalTwin3 searchDigitalTwin(JobResponse jobResponse, String digitalTwinId){ + return jobResponse.getShells().stream().filter(digitalTwin -> digitalTwin.getGlobalAssetId().equals(digitalTwinId)).findFirst().orElse(new DigitalTwin3()); + } + + public String populateTree(Map treeDataModel, String processId, JobHistory jobHistory, JobResponse job){ try { - Map treeDataModel = this.loadTree(processId); - Node node = this.getNodeByPath(treeDataModel, path); // Get parent node - node.setJob(job); // Set the job in the node List relationships = job.getRelationships(); - LogUtil.printMessage(jsonUtil.toJson(relationships, true)); - treeDataModel = this.setNodeByPath(treeDataModel, path, node); // Save the parent node in the tree + String parentPath = jobHistory.getPath(); + Node parent = this.getNodeByPath(treeDataModel, parentPath); + // All the relationships will be of depth one, so we just need to add them in the parent + for(Relationship relationship : relationships){ + String childId = relationship.getLinkedItem().getChildCatenaXId(); + // Search for the Digital Twin from the child or a new instance + DigitalTwin3 childDigitalTwin = this.searchDigitalTwin(job, childId); + if(childDigitalTwin.getGlobalAssetId().isEmpty()){ + childDigitalTwin.setGlobalAssetId(childId); + } + // Create child with the digital twin + Node child = new Node(childDigitalTwin); + // Add child to the parent + parent.setChild(child); + } + // Set node and save the tree + treeDataModel = this.setNodeByPath(treeDataModel, parentPath, parent); // Save the parent node in the tree return this.saveTree(processId, treeDataModel); } catch (Exception e) { throw new ManagerException(this.getClass().getName() + ".setChild()", e, "It was not possible to get the node from the tree"); } } + public String populateTree(String processId, JobHistory jobHistory, JobResponse job){ + try { + Map treeDataModel = this.loadTree(processId); + return this.populateTree(treeDataModel,processId, jobHistory, job); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName() + ".setChild()", e, "It was not possible to get the node from the tree"); + } + } public String saveTree(String processId, Map treeDataModel){ try { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java index 69fb260e4..b19c5ba9b 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java @@ -167,7 +167,7 @@ public void setChildren(Map children) { this.children = children; } public void setChild(Node childNode){ - this.children.put(childNode.getId(), childNode); + this.children.put(childNode.getGlobalAssetId(), childNode); } public Node getChild(String childId){ From 879ba7d90158fd6889c4cbd63efa8e29dd541f69 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Fri, 13 Oct 2023 17:46:54 +0200 Subject: [PATCH 10/25] feat: added parallel search for the digital twins in the job response --- .../productpass/managers/TreeManager.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index 88e636eeb..b7ad1ca7c 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -25,8 +25,11 @@ package org.eclipse.tractusx.productpass.managers; +import com.fasterxml.jackson.core.type.TypeReference; import org.eclipse.tractusx.productpass.config.IrsConfig; +import org.eclipse.tractusx.productpass.exceptions.DataModelException; import org.eclipse.tractusx.productpass.exceptions.ManagerException; +import org.eclipse.tractusx.productpass.models.catenax.EdcDiscoveryEndpoint; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.irs.Job; @@ -40,6 +43,7 @@ import org.springframework.stereotype.Component; import utils.*; +import java.util.ArrayList; import java.util.List; import java.util.Map; @Component @@ -90,8 +94,9 @@ public Map loadTree(String processId){ } } - public DigitalTwin3 searchDigitalTwin(JobResponse jobResponse, String digitalTwinId){ - return jobResponse.getShells().stream().filter(digitalTwin -> digitalTwin.getGlobalAssetId().equals(digitalTwinId)).findFirst().orElse(new DigitalTwin3()); + public DigitalTwin3 searchDigitalTwin(List digitalTwinList, String digitalTwinId){ + // Use a parallel search to make the search faster + return digitalTwinList.parallelStream().filter(digitalTwin -> digitalTwin.getGlobalAssetId().equals(digitalTwinId)).findFirst().orElse(new DigitalTwin3()); } public String populateTree(Map treeDataModel, String processId, JobHistory jobHistory, JobResponse job){ @@ -100,10 +105,17 @@ public String populateTree(Map treeDataModel, String processId, Jo String parentPath = jobHistory.getPath(); Node parent = this.getNodeByPath(treeDataModel, parentPath); // All the relationships will be of depth one, so we just need to add them in the parent + List digitalTwinList = null; + try { + digitalTwinList = (List) jsonUtil.bindReferenceType(job.getShells(), new TypeReference>() {}); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Digital Twin!"); + } + for(Relationship relationship : relationships){ String childId = relationship.getLinkedItem().getChildCatenaXId(); // Search for the Digital Twin from the child or a new instance - DigitalTwin3 childDigitalTwin = this.searchDigitalTwin(job, childId); + DigitalTwin3 childDigitalTwin = this.searchDigitalTwin(digitalTwinList, childId); if(childDigitalTwin.getGlobalAssetId().isEmpty()){ childDigitalTwin.setGlobalAssetId(childId); } From cec2fc71c0bb4ee5a6172918014ed61b6ad5fe64 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Mon, 16 Oct 2023 10:43:29 +0200 Subject: [PATCH 11/25] feat: added api to retrieve the tree of components --- .../productpass/http/controllers/api/IrsController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index b261ddc2c..7f7e59f04 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -112,7 +112,8 @@ public Response tree( @PathVariable String processId) { return httpUtil.buildResponse(response, httpResponse); } try { - response = httpUtil.getResponse("IRS is not available at the moment!"); + response = httpUtil.getResponse(); + response.data = this.treeManager.loadTree(processId); // Loads the tree for the process return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { response.message = e.getMessage(); From 10e93bcc6f7498b675f915a02a5dd1ab5a2f51d8 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Mon, 16 Oct 2023 15:44:17 +0200 Subject: [PATCH 12/25] feat: created recursive algorithm for getting tree components and tree --- .../http/controllers/api/IrsController.java | 21 +++- .../productpass/managers/TreeManager.java | 49 +++++++-- .../models/manager/NodeComponent.java | 100 ++++++++++++++++++ .../src/main/java/utils/JsonUtil.java | 11 ++ 4 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index 7f7e59f04..c38153894 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -103,6 +103,24 @@ public Response endpoint(@PathVariable String processId,@PathVariable String sea } } + @RequestMapping(value = "/{processId}/components", method = RequestMethod.GET) + @Operation(summary = "Api called by the frontend to obtain the tree of components") + public Response components( @PathVariable String processId) { + Response response = httpUtil.getInternalError(); + if (!authService.isAuthenticated(httpRequest)) { + response = httpUtil.getNotAuthorizedResponse(); + return httpUtil.buildResponse(response, httpResponse); + } + try { + response = httpUtil.getResponse(); + response.data = this.treeManager.getTreeComponents(processId); // Loads the tree components with a easy structure for frontend component + return httpUtil.buildResponse(response, httpResponse); + } catch (Exception e) { + response.message = e.getMessage(); + return httpUtil.buildResponse(response, httpResponse); + } + } + @RequestMapping(value = "/{processId}/tree", method = RequestMethod.GET) @Operation(summary = "Api called by the frontend to obtain the tree of components") public Response tree( @PathVariable String processId) { @@ -113,7 +131,7 @@ public Response tree( @PathVariable String processId) { } try { response = httpUtil.getResponse(); - response.data = this.treeManager.loadTree(processId); // Loads the tree for the process + response.data = this.treeManager.getTree(processId); // Loads the tree components with a easy structure for frontend component return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { response.message = e.getMessage(); @@ -123,5 +141,4 @@ public Response tree( @PathVariable String processId) { - } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index b7ad1ca7c..f8f044bb4 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -37,6 +37,7 @@ import org.eclipse.tractusx.productpass.models.irs.JobResponse; import org.eclipse.tractusx.productpass.models.irs.Relationship; import org.eclipse.tractusx.productpass.models.manager.Node; +import org.eclipse.tractusx.productpass.models.manager.NodeComponent; import org.eclipse.tractusx.productpass.models.manager.Status; import org.eclipse.tractusx.productpass.models.negotiation.Negotiation; import org.springframework.beans.factory.annotation.Autowired; @@ -81,7 +82,7 @@ public String createTreeFile(String processId){ public static String generateSearchId(String processId, String globalAssetId) { return CrypUtil.md5(DateTimeUtil.getDateTimeFormatted("yyyyMMddHHmmssSSS") + processId + globalAssetId); } - public Map loadTree(String processId){ + public Map getTree(String processId){ try { String path = this.getTreeFilePath(processId); // Get filepath from tree if(!fileUtil.pathExists(path)){ @@ -90,7 +91,43 @@ public Map loadTree(String processId){ } return (Map) jsonUtil.fromJsonFileToObject(path, Map.class); // Store the plain JSON } catch (Exception e) { - throw new ManagerException(this.getClass().getName()+".loadTree()", e, "It was not possible to load the tree"); + throw new ManagerException(this.getClass().getName()+".getTree()", e, "It was not possible to load the tree"); + } + } + + + public List parseChildren(Map children){ + List components = new ArrayList<>(); // Create a component list + if(children == null || children.size() == 0){ + return components; // Stop condition. Empty list when no children are available + } + List rawChildren = (List) jsonUtil.mapToList(children); // Pass the current node to list + rawChildren.forEach( + k -> { + List parsedChildren = this.parseChildren(k.getChildren()); // Parse the children below + NodeComponent childComponent = new NodeComponent(k,parsedChildren); // Add the existing children to a node component + components.add(childComponent); // Add to the list of components + } + ); + return components; // Return the components + } + + + public List recursiveParseChildren(Map currentNodes){ + try { + return this.parseChildren(currentNodes); + }catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".recursiveParseChildren()", e, "It was not possible to parse tree of nodes"); + } + + } + + public List getTreeComponents(String processId){ + try { + Map treeDataModel = this.getTree(processId); // Get filepath from tree + return this.recursiveParseChildren(treeDataModel); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName()+".getTreeComponents()", e, "It was not possible to get the tree components!"); } } @@ -133,7 +170,7 @@ public String populateTree(Map treeDataModel, String processId, Jo } public String populateTree(String processId, JobHistory jobHistory, JobResponse job){ try { - Map treeDataModel = this.loadTree(processId); + Map treeDataModel = this.getTree(processId); return this.populateTree(treeDataModel,processId, jobHistory, job); } catch (Exception e) { throw new ManagerException(this.getClass().getName() + ".setChild()", e, "It was not possible to get the node from the tree"); @@ -162,7 +199,7 @@ public Node getNodeByPath(Map treeDataModel, String path){ } public Node getNodeByPath(String processId, String path){ try { - Map treeDataModel = this.loadTree(processId); + Map treeDataModel = this.getTree(processId); String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children return (Node) this.jsonUtil.getValue(treeDataModel, translatedPath, ".", null); // Get the node } catch (Exception e) { @@ -183,7 +220,7 @@ public Map setNodeByPath(Map treeDataModel, String p } public Object setNodeByPath(String processId, String path, Node node){ try { - Map treeDataModel = this.loadTree(processId); + Map treeDataModel = this.getTree(processId); String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children treeDataModel = (Map) this.jsonUtil.setValue(treeDataModel, translatedPath, node, ".", null); // Set the node if(treeDataModel == null){ // Check if the response was successful @@ -197,7 +234,7 @@ public Object setNodeByPath(String processId, String path, Node node){ public Object setChild(String processId, String parentPath, Node childNode){ try { - Map treeDataModel = this.loadTree(processId); + Map treeDataModel = this.getTree(processId); Node parentNode = this.getNodeByPath(treeDataModel, parentPath); // Get parent node parentNode.setChild(childNode); // Add the child to the parent node treeDataModel = this.setNodeByPath(treeDataModel, parentPath, parentNode); // Save the parent node in the tree diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java new file mode 100644 index 000000000..f53a52d8a --- /dev/null +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java @@ -0,0 +1,100 @@ +/********************************************************************************* + * + * Catena-X - Product Passport Consumer Backend + * + * Copyright (c) 2022, 2023 BASF SE, BMW AG, Henkel AG & Co. KGaA + * Copyright (c) 2022, 2023 Contributors to the CatenaX (ng) GitHub Organisation. + * + * + * 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.manager; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class NodeComponent { + + @JsonProperty("id") + String id; + @JsonProperty("name") + String name; + @JsonProperty("path") + String path; + @JsonProperty("children") + List children; + + public NodeComponent() { + } + public NodeComponent(Node node, List children) { + this.id = node.globalAssetId; + this.path = node.path; + this.name = node.idShort; + this.children = children; + } + public NodeComponent(Node node) { + this.id = node.globalAssetId; + this.path = node.path; + this.name = node.idShort; + this.children = List.of(); + } + + public NodeComponent(String id, String idShort, String path, List children) { + this.id = id; + this.name = idShort; + this.path = path; + this.children = children; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } +} diff --git a/consumer-backend/productpass/src/main/java/utils/JsonUtil.java b/consumer-backend/productpass/src/main/java/utils/JsonUtil.java index 97901fe83..2850fab9c 100644 --- a/consumer-backend/productpass/src/main/java/utils/JsonUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/JsonUtil.java @@ -40,6 +40,7 @@ import java.io.File; import java.util.*; +import java.util.stream.Collectors; @Component @@ -414,4 +415,14 @@ public Object bindReferenceType (Object json, TypeReference reference) { throw new UtilException(JsonUtil.class, "It was not possible to get reference type -> [" + e.getMessage() + "]"); } } + + + public List mapToList(Map map){ + try{ + return Arrays.asList(map.values().toArray()); + } catch (Exception e) { + throw new UtilException(JsonUtil.class, "It was possible to the map to a list"); + } + } + } From 131079cd51f749b8d90b7ae2dffe9571e335b4e3 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Tue, 17 Oct 2023 14:49:30 +0200 Subject: [PATCH 13/25] feat: added disable condition in the backend configuration --- charts/digital-product-pass/values-beta.yaml | 10 ++++++ charts/digital-product-pass/values-dev.yaml | 10 ++++++ charts/digital-product-pass/values-int.yaml | 10 ++++++ charts/digital-product-pass/values.yaml | 10 ++++++ .../productpass/config/IrsConfig.java | 18 +++++++++++ .../http/controllers/AppController.java | 23 +++++++++----- .../http/controllers/api/IrsController.java | 31 +++++++++++++++++++ .../productpass/managers/ProcessManager.java | 17 ++++++++++ .../models/http/requests/Search.java | 22 +++++++++++++ .../productpass/models/manager/Status.java | 25 +++++++++++++++ .../src/main/resources/application.yml | 1 + 11 files changed, 169 insertions(+), 8 deletions(-) diff --git a/charts/digital-product-pass/values-beta.yaml b/charts/digital-product-pass/values-beta.yaml index d8ffaa0f7..c021c5120 100644 --- a/charts/digital-product-pass/values-beta.yaml +++ b/charts/digital-product-pass/values-beta.yaml @@ -124,6 +124,16 @@ backend: enabled: true bpn: true edc: true + + irs: + enabled: true + endpoint: "https://materialpass-irs.beta.demo.catena-x.net" + paths: + job: "/irs/jobs" + tree: + fileName: "treeDataModel" + indent: true + callbackUrl: "https://materialpass.beta.demo.catena-x.net/api/irs" dtr: central: false diff --git a/charts/digital-product-pass/values-dev.yaml b/charts/digital-product-pass/values-dev.yaml index ecd2d910d..08abf055e 100644 --- a/charts/digital-product-pass/values-dev.yaml +++ b/charts/digital-product-pass/values-dev.yaml @@ -125,6 +125,16 @@ backend: bpn: false edc: true + irs: + enabled: true + endpoint: "https://materialpass-irs.dev.demo.catena-x.net" + paths: + job: "/irs/jobs" + tree: + fileName: "treeDataModel" + indent: true + callbackUrl: "https://materialpass.dev.demo.catena-x.net/api/irs" + dtr: central: false centralUrl: 'https://semantics.dev.demo.catena-x.net/registry' diff --git a/charts/digital-product-pass/values-int.yaml b/charts/digital-product-pass/values-int.yaml index a06a4b030..75aa2f4c0 100644 --- a/charts/digital-product-pass/values-int.yaml +++ b/charts/digital-product-pass/values-int.yaml @@ -123,6 +123,16 @@ backend: bpn: true edc: true + irs: + enabled: true + endpoint: "https://materialpass-irs.int.demo.catena-x.net" + paths: + job: "/irs/jobs" + tree: + fileName: "treeDataModel" + indent: true + callbackUrl: "https://materialpass.int.demo.catena-x.net/api/irs" + dtr: central: false centralUrl: 'https://semantics.int.demo.catena-x.net/registry' diff --git a/charts/digital-product-pass/values.yaml b/charts/digital-product-pass/values.yaml index 377de0444..d4c38b73c 100644 --- a/charts/digital-product-pass/values.yaml +++ b/charts/digital-product-pass/values.yaml @@ -143,6 +143,16 @@ backend: enabled: false bpn: false edc: false + # -- irs configuration + irs: + enabled: true # -- Enable search for children in the requests + endpoint: "https://" # -- IRS endpoint + paths: + job: "/irs/jobs" # -- API path for calling in the IRS endpoints and staring/getting jobs + tree: + fileName: "treeDataModel" # -- Tree dataModel filename created in the processId directory + indent: true # -- Indent tree file + callbackUrl: "https:///api/irs" # -- Backend call back base url for the irs controller # -- digital twin registry configuration dtr: central: false diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java index f36092282..f7f38bfeb 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java @@ -32,6 +32,16 @@ @Configuration @ConfigurationProperties(prefix="configuration.irs") public class IrsConfig { + + public IrsConfig(Boolean enabled, String endpoint, TreeConfig tree, Paths paths, String callbackUrl) { + this.enabled = enabled; + this.endpoint = endpoint; + this.tree = tree; + this.paths = paths; + this.callbackUrl = callbackUrl; + } + + Boolean enabled; String endpoint; TreeConfig tree; @@ -90,6 +100,14 @@ public void setCallbackUrl(String callbackUrl) { this.callbackUrl = callbackUrl; } + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + public static class TreeConfig{ String fileName; 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 bd70c27c6..7377684a2 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 @@ -32,6 +32,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.juli.logging.Log; import org.eclipse.tractusx.productpass.config.DtrConfig; +import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.config.ProcessConfig; import org.eclipse.tractusx.productpass.exceptions.ControllerException; import org.eclipse.tractusx.productpass.managers.ProcessManager; @@ -92,7 +93,8 @@ public class AppController { @Autowired ProcessManager processManager; - + @Autowired + IrsConfig irsConfig; @Autowired DtrConfig dtrConfig; private @Autowired ProcessConfig processConfig; @@ -192,18 +194,23 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr LogUtil.printError("Failed to parse endpoint [" + connectorAddress + "] or the assetId is not found!"); } String bpn = dtr.getBpn(); + Boolean childrenCondition = search.getChildren(); processManager.setEndpoint(processId, connectorAddress); processManager.setBpn(processId,bpn); processManager.saveDigitalTwin3(processId, digitalTwin, dtRequestTime); + processManager.setChildrenCondition(processId, childrenCondition); - // Update tree - String globalAssetId = digitalTwin.getGlobalAssetId(); - String actualPath = status.getTreeState() + "/" + globalAssetId; - processManager.setTreeState(processId, actualPath); - this.treeManager.setNodeByPath(processId, actualPath, new Node(digitalTwin)); + // IRS FUNCTIONALITY START + if(this.irsConfig.getEnabled() && search.getChildren()) { + // Update tree + String globalAssetId = digitalTwin.getGlobalAssetId(); + String actualPath = status.getTreeState() + "/" + globalAssetId; + processManager.setTreeState(processId, actualPath); + this.treeManager.setNodeByPath(processId, actualPath, new Node(digitalTwin)); - // Get children from the node - this.irsService.getChildren(processId, actualPath, globalAssetId, bpn); + // Get children from the node + this.irsService.getChildren(processId, actualPath, globalAssetId, bpn); + } 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( assetId, diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index c38153894..713969a93 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -35,10 +35,12 @@ import org.eclipse.tractusx.productpass.managers.TreeManager; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.http.Response; +import org.eclipse.tractusx.productpass.models.http.requests.Search; import org.eclipse.tractusx.productpass.models.irs.Job; import org.eclipse.tractusx.productpass.models.irs.JobHistory; import org.eclipse.tractusx.productpass.models.irs.JobResponse; import org.eclipse.tractusx.productpass.models.manager.Node; +import org.eclipse.tractusx.productpass.models.manager.SearchStatus; import org.eclipse.tractusx.productpass.models.manager.Status; import org.eclipse.tractusx.productpass.services.AuthenticationService; import org.eclipse.tractusx.productpass.services.IrsService; @@ -112,6 +114,21 @@ public Response components( @PathVariable String processId) { return httpUtil.buildResponse(response, httpResponse); } try { + if (!processManager.checkProcess(processId)) { + return httpUtil.buildResponse(httpUtil.getNotFound("Process not found!"), httpResponse); + } + + Status status = processManager.getStatus(processId); + if(status == null){ + return httpUtil.buildResponse(httpUtil.getNotFound("No status is created"), httpResponse); + } + if(!this.irsConfig.getEnabled()){ + return httpUtil.buildResponse(httpUtil.getForbiddenResponse("The children drill down functionality is not available!"), httpResponse); + } + if(!status.getChildren()){ + return httpUtil.buildResponse(httpUtil.getForbiddenResponse("The children drill down functionality is not available for this process!"), httpResponse); + } + response = httpUtil.getResponse(); response.data = this.treeManager.getTreeComponents(processId); // Loads the tree components with a easy structure for frontend component return httpUtil.buildResponse(response, httpResponse); @@ -130,6 +147,20 @@ public Response tree( @PathVariable String processId) { return httpUtil.buildResponse(response, httpResponse); } try { + if (!processManager.checkProcess(processId)) { + return httpUtil.buildResponse(httpUtil.getNotFound("Process not found!"), httpResponse); + } + + Status status = processManager.getStatus(processId); + if(status == null){ + return httpUtil.buildResponse(httpUtil.getNotFound("No status is created"), httpResponse); + } + if(!this.irsConfig.getEnabled()){ + return httpUtil.buildResponse(httpUtil.getForbiddenResponse("The children drill down functionality is not available!"), httpResponse); + } + if(!status.getChildren()){ + return httpUtil.buildResponse(httpUtil.getForbiddenResponse("The children drill down functionality is not available for this process!"), httpResponse); + } response = httpUtil.getResponse(); response.data = this.treeManager.getTree(processId); // Loads the tree components with a easy structure for frontend component 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 47406e159..b57602b9f 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 @@ -336,6 +336,23 @@ public String setBpn(String processId, String bpn) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to create/update the status file"); } } + public String setChildrenCondition(String processId, Boolean childrenCondition) { + 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.setChildren(childrenCondition); + 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 create/update the status file"); + } + } + public String setTreeState(String processId, String state) { try { String path = this.getProcessFilePath(processId, this.metaFileName); diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/http/requests/Search.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/http/requests/Search.java index 63213e199..0915da042 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/http/requests/Search.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/http/requests/Search.java @@ -48,6 +48,10 @@ public class Search { String idType = "partInstanceId"; @JsonProperty(value = "dtIndex", defaultValue = "0") Integer dtIndex = 0; + + @JsonProperty(value = "children", defaultValue = "true") + Boolean children = true; + @JsonProperty(value = "idShort", defaultValue = "batteryPass") String idShort = "batteryPass"; @@ -64,6 +68,16 @@ public Search(String processId, String id, String version, String idType, Intege this.idShort = idShort; } + public Search(String processId, String id, String version, String idType, Integer dtIndex, Boolean children, String idShort) { + this.processId = processId; + this.id = id; + this.version = version; + this.idType = idType; + this.dtIndex = dtIndex; + this.children = children; + this.idShort = idShort; + } + public String getProcessId() { return processId; } @@ -110,4 +124,12 @@ public String getVersion() { public void setVersion(String version) { this.version = version; } + + public Boolean getChildren() { + return children; + } + + public void setChildren(Boolean children) { + this.children = children; + } } 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 0e1edf50a..667a7dbf7 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 @@ -56,6 +56,10 @@ public class Status { @JsonProperty("bpn") public String bpn; + + @JsonProperty("children") + public Boolean children; + @JsonProperty("treeState") public String treeState; @@ -184,6 +188,19 @@ public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, Boolean children, String treeState, Map history) { + this.id = id; + this.status = status; + this.created = created; + this.modified = modified; + this.jobs = jobs; + this.endpoint = endpoint; + this.bpn = bpn; + this.children = children; + this.treeState = treeState; + this.history = history; + } + public String getId() { return id; } @@ -285,6 +302,14 @@ public String getTreeState() { public void setTreeState(String treeState) { this.treeState = treeState; } + + public Boolean getChildren() { + return children; + } + + public void setChildren(Boolean children) { + this.children = children; + } } diff --git a/consumer-backend/productpass/src/main/resources/application.yml b/consumer-backend/productpass/src/main/resources/application.yml index 9537b0af2..9e44621d1 100644 --- a/consumer-backend/productpass/src/main/resources/application.yml +++ b/consumer-backend/productpass/src/main/resources/application.yml @@ -61,6 +61,7 @@ configuration: edc: true irs: + enabled: true endpoint: "https://materialpass-irs.int.demo.catena-x.net" paths: job: "/irs/jobs" From 1c362491f74dd6f79e8b0025afa51f32a085cf3f Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Tue, 17 Oct 2023 15:14:23 +0200 Subject: [PATCH 14/25] merge: resolved merge conflicts with develop --- consumer-backend/productpass/pom.xml | 2 +- .../productpass/config/DtrConfig.java | 7 +++-- .../http/controllers/AppController.java | 4 +-- .../http/controllers/api/IrsController.java | 1 - .../productpass/managers/TreeManager.java | 11 ++++---- .../productpass/models/irs/JobResponse.java | 10 +++---- .../productpass/models/manager/Node.java | 26 +++++++++---------- .../productpass/models/manager/Status.java | 1 + .../productpass/services/AasService.java | 4 +-- .../productpass/services/IrsService.java | 1 - 10 files changed, 32 insertions(+), 35 deletions(-) diff --git a/consumer-backend/productpass/pom.xml b/consumer-backend/productpass/pom.xml index 05270a8eb..d5d8b8712 100644 --- a/consumer-backend/productpass/pom.xml +++ b/consumer-backend/productpass/pom.xml @@ -33,7 +33,7 @@ org.eclipse.tractusx productpass - 1.2.0 + 1.3.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 d84cc686f..94617edda 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 @@ -52,14 +52,13 @@ public class DtrConfig { 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; + + public DtrConfig(String internalDtr, Timeouts timeouts, Boolean temporaryStorage, DecentralApis decentralApis, String assetType, String endpointInterface, String dspEndpointKey, String semanticIdTypeKey) { this.internalDtr = internalDtr; this.timeouts = timeouts; this.temporaryStorage = temporaryStorage; this.decentralApis = decentralApis; - this.assetId = assetId; + this.assetType = assetType; this.endpointInterface = endpointInterface; this.dspEndpointKey = dspEndpointKey; this.semanticIdTypeKey = semanticIdTypeKey; 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 5bdc15839..631cea928 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 @@ -96,7 +96,7 @@ public class AppController { @Autowired DataPlaneService dataPlaneService; @Autowired - ProcessManager processManager;n + ProcessManager processManager; @Autowired IrsConfig irsConfig; @Autowired @@ -223,7 +223,7 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr Boolean childrenCondition = search.getChildren(); processManager.setEndpoint(processId, connectorAddress); processManager.setBpn(processId,bpn); - processManager.saveDigitalTwin3(processId, digitalTwin, dtRequestTime); + processManager.saveDigitalTwin(processId, digitalTwin, dtRequestTime); processManager.setChildrenCondition(processId, childrenCondition); // IRS FUNCTIONALITY START diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index 713969a93..d57c6bfe9 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -33,7 +33,6 @@ import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.managers.ProcessManager; import org.eclipse.tractusx.productpass.managers.TreeManager; -import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.http.Response; import org.eclipse.tractusx.productpass.models.http.requests.Search; import org.eclipse.tractusx.productpass.models.irs.Job; diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index f8f044bb4..99e570227 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -31,7 +31,6 @@ import org.eclipse.tractusx.productpass.exceptions.ManagerException; import org.eclipse.tractusx.productpass.models.catenax.EdcDiscoveryEndpoint; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; -import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.irs.Job; import org.eclipse.tractusx.productpass.models.irs.JobHistory; import org.eclipse.tractusx.productpass.models.irs.JobResponse; @@ -131,9 +130,9 @@ public List getTreeComponents(String processId){ } } - public DigitalTwin3 searchDigitalTwin(List digitalTwinList, String digitalTwinId){ + public DigitalTwin searchDigitalTwin(List digitalTwinList, String digitalTwinId){ // Use a parallel search to make the search faster - return digitalTwinList.parallelStream().filter(digitalTwin -> digitalTwin.getGlobalAssetId().equals(digitalTwinId)).findFirst().orElse(new DigitalTwin3()); + return digitalTwinList.parallelStream().filter(digitalTwin -> digitalTwin.getGlobalAssetId().equals(digitalTwinId)).findFirst().orElse(new DigitalTwin()); } public String populateTree(Map treeDataModel, String processId, JobHistory jobHistory, JobResponse job){ @@ -142,9 +141,9 @@ public String populateTree(Map treeDataModel, String processId, Jo String parentPath = jobHistory.getPath(); Node parent = this.getNodeByPath(treeDataModel, parentPath); // All the relationships will be of depth one, so we just need to add them in the parent - List digitalTwinList = null; + List digitalTwinList = null; try { - digitalTwinList = (List) jsonUtil.bindReferenceType(job.getShells(), new TypeReference>() {}); + digitalTwinList = (List) jsonUtil.bindReferenceType(job.getShells(), new TypeReference>() {}); } catch (Exception e) { throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Digital Twin!"); } @@ -152,7 +151,7 @@ public String populateTree(Map treeDataModel, String processId, Jo for(Relationship relationship : relationships){ String childId = relationship.getLinkedItem().getChildCatenaXId(); // Search for the Digital Twin from the child or a new instance - DigitalTwin3 childDigitalTwin = this.searchDigitalTwin(digitalTwinList, childId); + DigitalTwin childDigitalTwin = this.searchDigitalTwin(digitalTwinList, childId); if(childDigitalTwin.getGlobalAssetId().isEmpty()){ childDigitalTwin.setGlobalAssetId(childId); } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java index 7014d87f1..c1eef7ed7 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java @@ -29,7 +29,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; -import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import java.util.ArrayList; @JsonIgnoreProperties(ignoreUnknown = true) @@ -41,7 +41,7 @@ public class JobResponse { @JsonProperty("relationships") ArrayList relationships; @JsonProperty("shells") - ArrayList shells; + ArrayList shells; @JsonProperty("tombstones") Object tombstones; @JsonProperty("submodels") @@ -49,7 +49,7 @@ public class JobResponse { @JsonProperty("bpns") ArrayList bpns; - public JobResponse(Job job, ArrayList relationships, ArrayList shells, Object tombstones, ArrayList submodels, ArrayList bpns) { + public JobResponse(Job job, ArrayList relationships, ArrayList shells, Object tombstones, ArrayList submodels, ArrayList bpns) { this.job = job; this.relationships = relationships; this.shells = shells; @@ -77,11 +77,11 @@ public void setRelationships(ArrayList relationships) { this.relationships = relationships; } - public ArrayList getShells() { + public ArrayList getShells() { return shells; } - public void setShells(ArrayList shells) { + public void setShells(ArrayList shells) { this.shells = shells; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java index b19c5ba9b..7bf4f6e39 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java @@ -28,7 +28,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import org.eclipse.tractusx.productpass.models.irs.JobResponse; import java.util.Map; @@ -45,7 +45,7 @@ public class Node { @JsonProperty("path") String path; @JsonProperty("digitalTwin") - DigitalTwin3 digitalTwin; + DigitalTwin digitalTwin; @JsonProperty("job") JobResponse job; @@ -54,42 +54,42 @@ public class Node { Map children; - public Node(Node parent, DigitalTwin3 digitalTwin, Map children){ + public Node(Node parent, DigitalTwin digitalTwin, Map children){ this.setup(digitalTwin); this.setPath(parent, digitalTwin.getIdentification()); this.children = children; } - public Node(String parentPath, DigitalTwin3 digitalTwin, Map children){ + public Node(String parentPath, DigitalTwin digitalTwin, Map children){ this.setup(digitalTwin); this.setPath(parentPath, digitalTwin.getIdentification()); this.children = children; } - public Node(DigitalTwin3 digitalTwin, Map children){ + public Node(DigitalTwin digitalTwin, Map children){ this.setup(digitalTwin); this.setPath("", digitalTwin.getIdentification()); this.children = children; } - public Node(Node parent, DigitalTwin3 digitalTwin){ + public Node(Node parent, DigitalTwin digitalTwin){ this.setup(digitalTwin); this.setPath(parent, digitalTwin.getIdentification()); this.children = Map.of(); } - public Node(String parentPath, DigitalTwin3 digitalTwin){ + public Node(String parentPath, DigitalTwin digitalTwin){ this.setup(digitalTwin); this.setPath(parentPath, digitalTwin.getIdentification()); this.children = Map.of(); } - public Node(DigitalTwin3 digitalTwin){ + public Node(DigitalTwin digitalTwin){ this.setup(digitalTwin); this.setPath("", digitalTwin.getIdentification()); this.children = Map.of(); } - public Node(String id, String globalAssetId, String idShort, String path, DigitalTwin3 digitalTwin, JobResponse job, Map children) { + public Node(String id, String globalAssetId, String idShort, String path, DigitalTwin digitalTwin, JobResponse job, Map children) { this.id = id; this.globalAssetId = globalAssetId; this.idShort = idShort; @@ -99,13 +99,13 @@ public Node(String id, String globalAssetId, String idShort, String path, Digita this.children = children; } - public void setup(DigitalTwin3 digitalTwin){ + public void setup(DigitalTwin digitalTwin){ this.id = digitalTwin.getIdentification(); this.globalAssetId = digitalTwin.getGlobalAssetId(); this.idShort = digitalTwin.getIdShort(); this.digitalTwin = digitalTwin; } - public Node(String id, String globalAssetId, String idShort, String path, DigitalTwin3 digitalTwin, Map children) { + public Node(String id, String globalAssetId, String idShort, String path, DigitalTwin digitalTwin, Map children) { this.id = id; this.globalAssetId = globalAssetId; this.idShort = idShort; @@ -151,11 +151,11 @@ public void setPath(String parentPath, String id) { this.path = parentPath+"/"+id; } - public DigitalTwin3 getDigitalTwin() { + public DigitalTwin getDigitalTwin() { return digitalTwin; } - public void setDigitalTwin(DigitalTwin3 digitalTwin) { + public void setDigitalTwin(DigitalTwin digitalTwin) { this.digitalTwin = digitalTwin; } 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 8e88a5eb1..2e6973898 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 @@ -332,6 +332,7 @@ public Boolean getChildren() { public void setChildren(Boolean children) { this.children = children; + } public String getSemanticId() { return semanticId; 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 c55070e36..4d6d9bfd5 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 @@ -310,7 +310,7 @@ public SubModel getSubModelBySemanticId(DigitalTwin digitalTwin) { * Gets the {@code Submodel} from a Digital Twin by a given semantic identification. *

* @param digitalTwin - * the {@code DigitalTwin3} object with its submodels. + * the {@code DigitalTwin} object with its submodels. * @param aspectSemanticId * the {@code String} semantic id of the intended submodel. * @@ -319,7 +319,7 @@ public SubModel getSubModelBySemanticId(DigitalTwin digitalTwin) { * @throws ServiceException * if unable to find a the {@code Submodel} for the given semantic id. */ - public SubModel3 getSubModel3BySemanticId(DigitalTwin3 digitalTwin, String aspectSemanticId) { + public SubModel getSubModelBySemanticId(DigitalTwin digitalTwin, String aspectSemanticId) { try { ArrayList subModels = digitalTwin.getSubmodelDescriptors(); if (subModels.size() < 1) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 0d0b0291d..4c50ea939 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -32,7 +32,6 @@ import org.eclipse.tractusx.productpass.managers.TreeManager; import org.eclipse.tractusx.productpass.models.catenax.Discovery; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; -import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin3; import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; import org.eclipse.tractusx.productpass.models.irs.Job; import org.eclipse.tractusx.productpass.models.irs.JobHistory; From 595de9f34faac3c7198f32cd6da65ccf0349bb85 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Tue, 17 Oct 2023 16:57:33 +0200 Subject: [PATCH 15/25] fix: fixed bugs related to the irs search and the tree components return --- .../http/controllers/api/IrsController.java | 5 ++--- .../tractusx/productpass/managers/TreeManager.java | 11 ++++++++++- .../tractusx/productpass/services/IrsService.java | 3 ++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index d57c6bfe9..34e19ae6e 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -73,9 +73,8 @@ public class IrsController { @RequestMapping(value = "/{processId}/{searchId}", method = RequestMethod.GET) @Operation(summary = "Endpoint called by the IRS to set status completed") - public Response endpoint(@PathVariable String processId,@PathVariable String searchId, @RequestParam String id, @RequestParam String state) { + public Response endpoint(@PathVariable String processId, @PathVariable String searchId, @RequestParam String id, @RequestParam String state) { Response response = httpUtil.getInternalError(); - LogUtil.printMessage(jsonUtil.toJson(httpRequest, true)); try { if (!processManager.checkProcess(processId)) { return httpUtil.buildResponse(httpUtil.getNotFound("Process not found!"), httpResponse); @@ -106,7 +105,7 @@ public Response endpoint(@PathVariable String processId,@PathVariable String sea @RequestMapping(value = "/{processId}/components", method = RequestMethod.GET) @Operation(summary = "Api called by the frontend to obtain the tree of components") - public Response components( @PathVariable String processId) { + public Response components(@PathVariable String processId) { Response response = httpUtil.getInternalError(); if (!authService.isAuthenticated(httpRequest)) { response = httpUtil.getNotAuthorizedResponse(); diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index 99e570227..24b66029d 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -100,7 +100,16 @@ public List parseChildren(Map children){ if(children == null || children.size() == 0){ return components; // Stop condition. Empty list when no children are available } - List rawChildren = (List) jsonUtil.mapToList(children); // Pass the current node to list + List rawChildren = null; + try { + rawChildren = (List) jsonUtil.bindReferenceType(jsonUtil.mapToList(children), new TypeReference>() {}); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Node!"); + } + if(rawChildren == null){ + LogUtil.printWarning(this.getClass().getName() + ".parseChildren() It was not possible to parse children as a list of Nodes"); + return components; + } rawChildren.forEach( k -> { List parsedChildren = this.parseChildren(k.getChildren()); // Parse the children below diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 4c50ea939..6200554a8 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -24,6 +24,7 @@ package org.eclipse.tractusx.productpass.services; import com.fasterxml.jackson.databind.JsonNode; +import org.apache.commons.logging.Log; import org.checkerframework.checker.units.qual.K; import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.exceptions.ServiceException; @@ -113,7 +114,6 @@ public Map startJob(String processId, String globalAssetId, Str "state", "COMPLETED" ); String callbackUrl = httpUtil.buildUrl(backendUrl, params, false); - LogUtil.printMessage("Backend CallBack Url: "+callbackUrl); JobRequest body = new JobRequest( new ArrayList<>(), "asBuilt", @@ -144,6 +144,7 @@ public String getChildren(String processId, String path, String globalAssetId, S Long created = DateTimeUtil.getTimestamp(); Map irsResponse = this.startJob(processId, globalAssetId, searchId, bpn); String jobId = irsResponse.get("id"); + LogUtil.printMessage("[PROCESS "+ processId + "] Job with id [" + jobId + "] created in the IRS for the globalAssetId [" + globalAssetId+"]"); this.processManager.addJobHistory( processId, searchId, From 43077be38dee348c1f183ccf552db6d1594da17a Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Tue, 17 Oct 2023 17:22:32 +0200 Subject: [PATCH 16/25] fix: fixed bug related with the parse of subprotocol body --- .../tractusx/productpass/http/controllers/AppController.java | 2 +- .../tractusx/productpass/models/dtregistry/EndPoint.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) 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 631cea928..a7be5db97 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 @@ -201,7 +201,7 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr if (endpoint == null) { throw new ControllerException(this.getClass().getName(), "No EDC endpoint found in DTR SubModel!"); } - Map subProtocolBody = endpoint.getProtocolInformation().getParsedSubprotocolBody(); + Map subProtocolBody = endpoint.getProtocolInformation().parseSubProtocolBody(); connectorAddress = subProtocolBody.get(dtrConfig.getDspEndpointKey()); // Get DSP endpoint address assetId = subProtocolBody.get("id"); // Get Asset Id } catch (Exception e) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/EndPoint.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/EndPoint.java index d31749912..4a0aa63b2 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/EndPoint.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/EndPoint.java @@ -65,6 +65,8 @@ public void setProtocolInformation(String endpointAddress, String endpointProtoc /** * This class consists exclusively to define attributes related to the needed protocol information for the improved version. **/ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) public static class ProtocolInformation3 { /** ATTRIBUTES **/ @@ -156,7 +158,7 @@ public void setSubprotocol(String subprotocol) { public String getSubprotocolBody() { return subprotocolBody; } - public Map getParsedSubprotocolBody() { + public Map parseSubProtocolBody() { try { return Splitter.on(';').withKeyValueSeparator('=').split(this.subprotocolBody); }catch (Exception e){ From 22e317f0bc24544899a1f19dc404449c7f75e19b Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Tue, 17 Oct 2023 17:57:27 +0200 Subject: [PATCH 17/25] feat: allow search of submodel payload by href following tracex standard --- .../http/controllers/AppController.java | 15 ++++-- .../http/controllers/api/IrsController.java | 7 ++- .../productpass/managers/ProcessManager.java | 32 +++++++++++++ .../productpass/models/manager/Status.java | 26 +++++++++++ .../services/DataPlaneService.java | 46 +++++++++++++++++++ 5 files changed, 117 insertions(+), 9 deletions(-) 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 a7be5db97..c27f8377c 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 @@ -191,7 +191,7 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr String assetId = null; String connectorAddress = null; String semanticId = null; - + String dataPlaneUrl = null; try { digitalTwin = digitalTwinRegistry.getDigitalTwin(); subModel = digitalTwinRegistry.getSubModel(); @@ -204,6 +204,7 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr Map subProtocolBody = endpoint.getProtocolInformation().parseSubProtocolBody(); connectorAddress = subProtocolBody.get(dtrConfig.getDspEndpointKey()); // Get DSP endpoint address assetId = subProtocolBody.get("id"); // Get Asset Id + dataPlaneUrl = endpoint.getProtocolInformation().getEndpointAddress(); // Get the HREF endpoint } catch (Exception e) { return httpUtil.buildResponse(httpUtil.getNotFound("No endpoint address found"), httpResponse); } @@ -221,10 +222,8 @@ public Response getDigitalTwin(@RequestBody Object body, @PathVariable String pr } String bpn = dtr.getBpn(); Boolean childrenCondition = search.getChildren(); - processManager.setEndpoint(processId, connectorAddress); - processManager.setBpn(processId,bpn); + processManager.saveTransferInfo(processId, connectorAddress, semanticId, dataPlaneUrl, bpn, childrenCondition); processManager.saveDigitalTwin(processId, digitalTwin, dtRequestTime); - processManager.setChildrenCondition(processId, childrenCondition); // IRS FUNCTIONALITY START if(this.irsConfig.getEnabled() && search.getChildren()) { @@ -315,7 +314,13 @@ public Response endpoint(@RequestBody Object body, @PathVariable String processI return httpUtil.buildResponse(httpUtil.getNotFound("Process not found!"), httpResponse); } - JsonNode passport = dataPlaneService.getPassport(endpointData); + Status status = processManager.getStatus(processId); + if(status == null){ + return httpUtil.buildResponse(httpUtil.getNotFound("No status is created"), httpResponse); + } + + + JsonNode passport = dataPlaneService.getPassportFromEndpoint(endpointData, status.getDataPlaneUrl()); 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/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index 34e19ae6e..34ad56bfc 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -91,11 +91,10 @@ public Response endpoint(@PathVariable String processId, @PathVariable String se JobHistory jobHistory = status.getJobId(searchId); - LogUtil.printMessage("["+processId+"] Requesting Job ["+id+"] after state ["+state+"]"); - JobResponse irsJob = this.irsService.getJob(id); - LogUtil.printMessage(jsonUtil.toJson(irsJob, true)); + LogUtil.printMessage("["+processId+"] Job callback received with state ["+ state+"]. Requesting Job ["+jobHistory.getJobId()+"]!"); + JobResponse irsJob = this.irsService.getJob(jobHistory.getJobId()); this.treeManager.populateTree(processId, jobHistory, irsJob); - response = httpUtil.getResponse("IRS is not available at the moment!"); + response = httpUtil.getResponse("OK"); return httpUtil.buildResponse(response, httpResponse); } catch (Exception e) { response.message = e.getMessage(); 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 00408b713..1a8cf58d2 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 @@ -805,7 +805,39 @@ public String setSemanticId(String processId, String semanticId) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to set the semanticId!"); } } + /** + * Sets the semantic id in the status file + *

+ * @param processId + * the {@code String} id of the application's process. + * @param semanticId + * the {@code String} semantic ID in the status file + * + * @return a {@code String} file path of the process status file. + * + * @throws ManagerException + * if unable to update the status file. + */ + public String saveTransferInfo(String processId, String connectorAddress, String semanticId, String dataPlaneUrl, String bpn, Boolean childrenCondition) { + 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.setEndpoint(connectorAddress); + statusFile.setDataPlaneUrl(dataPlaneUrl); + statusFile.setBpn(bpn); + statusFile.setChildren(childrenCondition); + 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. *

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 2e6973898..26c5876fb 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 @@ -59,6 +59,9 @@ public class Status { @JsonProperty("endpoint") public String endpoint; + @JsonProperty("dataPlaneUrl") + public String dataPlaneUrl; + @JsonProperty("bpn") public String bpn; @@ -222,6 +225,21 @@ public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String dataPlaneUrl, String bpn, Boolean children, String treeState, Map history, String semanticId) { + this.id = id; + this.status = status; + this.created = created; + this.modified = modified; + this.jobs = jobs; + this.endpoint = endpoint; + this.dataPlaneUrl = dataPlaneUrl; + this.bpn = bpn; + this.children = children; + this.treeState = treeState; + this.history = history; + this.semanticId = semanticId; + } + public String getId() { return id; } @@ -341,6 +359,14 @@ public String getSemanticId() { public void setSemanticId(String semanticId) { this.semanticId = semanticId; } + + public String getDataPlaneUrl() { + return dataPlaneUrl; + } + + public void setDataPlaneUrl(String dataPlaneUrl) { + this.dataPlaneUrl = dataPlaneUrl; + } } 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 025de684c..2a3f43219 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 @@ -84,6 +84,30 @@ public Object getTransferData(DataPlaneEndpoint endpointData) { "It was not possible to get transfer from transfer id ["+endpointData.getId()+"]"); } } + /** + * Gets the Transfer data from the given data plane endpoint. + *

+ * @param endpointData + * the {@code DataPlaneEndpoint} object with data plane endpoint data. + * + * @return a {@code Object} object with the body of the response. + * + * @throws ServiceException + * if unable to get the transfer data. + */ + public Object getTransferDataFromEndpoint(DataPlaneEndpoint endpointData, String dataPlaneEndpoint) { + try { + Map params = httpUtil.getParams(); + HttpHeaders headers = new HttpHeaders(); + headers.add(endpointData.getAuthKey(), endpointData.getAuthCode()); + ResponseEntity response = httpUtil.doGet(dataPlaneEndpoint, Object.class, headers, params, true, true); + return response.getBody(); + }catch (Exception e){ + throw new ServiceException(this.getClass().getName()+"."+"getTransferData", + e, + "It was not possible to get transfer from transfer id ["+endpointData.getId()+"]"); + } + } /** * Parses the Transfer Data to a Passport from the given data plane endpoint. @@ -105,6 +129,28 @@ public JsonNode getPassport(DataPlaneEndpoint endpointData) { "It was not possible to get and parse passport for transfer ["+endpointData.getId()+"]"); } } + /** + * Parses the Transfer Data to a Passport from the given data plane endpoint string. + *

+ * @param endpointData + * the {@code DataPlaneEndpoint} object with data plane endpoint data. + * @param dataPlaneEndpoint + * the {@code String} is the data plane endpoint url + * + * @return a {@code Passport} object parsed with transfer data. + * + * @throws ServiceException + * if unable to parse the data to the passport. + */ + public JsonNode getPassportFromEndpoint(DataPlaneEndpoint endpointData, String dataPlaneEndpoint) { + try { + return jsonUtil.toJsonNode(this.getTransferDataFromEndpoint(endpointData, dataPlaneEndpoint)); + }catch (Exception e){ + throw new ServiceException(this.getClass().getName()+"."+"getPassport", + e, + "It was not possible to get and parse passport for transfer ["+endpointData.getId()+"]"); + } + } /** * Creates an empty variables List. From f77916e1da227484857cea90ca2d1e1f8ccd92cc Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Wed, 18 Oct 2023 10:14:43 +0200 Subject: [PATCH 18/25] fix: fixed irs node parsing and casting bug --- .../productpass/managers/TreeManager.java | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index 24b66029d..6da664252 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -200,7 +200,17 @@ public String saveTree(String processId, Map treeDataModel){ public Node getNodeByPath(Map treeDataModel, String path){ try { String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children - return (Node) this.jsonUtil.getValue(treeDataModel, translatedPath, ".", null); // Get the node + Object rawNode = this.jsonUtil.getValue(treeDataModel, translatedPath, ".", null); // Get the node; + Node node = null; + try { + node = (Node) jsonUtil.bindReferenceType(rawNode, new TypeReference() {}); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Node!"); + } + if(node == null){ // Check if the response was successful + throw new ManagerException(this.getClass().getName()+".getNodeByPath()", "It was not possible to set the node in path because the return was null"); + } + return node; } catch (Exception e) { throw new ManagerException(this.getClass().getName()+".getNodeByPath()", e, "It was not possible to get the node from the tree"); } @@ -209,7 +219,17 @@ public Node getNodeByPath(String processId, String path){ try { Map treeDataModel = this.getTree(processId); String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children - return (Node) this.jsonUtil.getValue(treeDataModel, translatedPath, ".", null); // Get the node + Object rawNode = this.jsonUtil.getValue(treeDataModel, translatedPath, ".", null); // Get the node; + Node node = null; + try { + node = (Node) jsonUtil.bindReferenceType(rawNode, new TypeReference() {}); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Node!"); + } + if(node == null){ // Check if the response was successful + throw new ManagerException(this.getClass().getName()+".getNodeByPath()", "It was not possible to set the node in path because the return was null"); + } + return node; } catch (Exception e) { throw new ManagerException(this.getClass().getName()+".getNodeByPath()", e, "It was not possible to get the node from the tree"); } @@ -217,7 +237,12 @@ public Node getNodeByPath(String processId, String path){ public Map setNodeByPath(Map treeDataModel, String path, Node node){ try { String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children - treeDataModel = (Map) this.jsonUtil.setValue(treeDataModel, translatedPath, node, ".", null); // Set the node + Object rawDataModel = this.jsonUtil.setValue(treeDataModel, translatedPath, node, ".", null); // Set the node + try { + treeDataModel = (Map) jsonUtil.bindReferenceType(rawDataModel, new TypeReference>() {}); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Node!"); + } if(treeDataModel == null){ // Check if the response was successful throw new ManagerException(this.getClass().getName()+".setNodeByPath()", "It was not possible to set the node in path because the return was null"); } @@ -230,9 +255,11 @@ public Object setNodeByPath(String processId, String path, Node node){ try { Map treeDataModel = this.getTree(processId); String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children - treeDataModel = (Map) this.jsonUtil.setValue(treeDataModel, translatedPath, node, ".", null); // Set the node - if(treeDataModel == null){ // Check if the response was successful - throw new ManagerException(this.getClass().getName()+".setNodeByPath()", "It was not possible to set the node in path because the return was null"); + Object rawDataModel = this.jsonUtil.setValue(treeDataModel, translatedPath, node, ".", null); // Set the node + try { + treeDataModel = (Map) jsonUtil.bindReferenceType(rawDataModel, new TypeReference>() {}); + } catch (Exception e) { + throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Tree Data Model!"); } return this.saveTree(processId, treeDataModel); } catch (Exception e) { From fb51a9251a05bea29817e1b4c023d7e8e4be4942 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Wed, 18 Oct 2023 17:49:36 +0200 Subject: [PATCH 19/25] feat: finished the comments for the irs functionality --- .../productpass/config/IrsConfig.java | 35 ++- .../controllers/api/ContractController.java | 3 +- .../http/controllers/api/IrsController.java | 42 +++- .../productpass/managers/TreeManager.java | 238 +++++++++++++++++- .../tractusx/productpass/models/irs/Job.java | 31 ++- .../productpass/models/irs/JobHistory.java | 14 +- .../productpass/models/irs/JobRequest.java | 22 +- .../productpass/models/irs/JobResponse.java | 19 +- .../productpass/models/irs/Relationship.java | 16 +- .../productpass/models/manager/Node.java | 37 +-- .../models/manager/NodeComponent.java | 22 +- .../services/DataTransferService.java | 8 +- .../productpass/services/IrsService.java | 121 +++++++-- 13 files changed, 481 insertions(+), 127 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java index f7f38bfeb..cc0780782 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/config/IrsConfig.java @@ -29,10 +29,21 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; +/** + * This class consists exclusively to define the attributes and methods needed for the IRS configuration. + **/ @Configuration @ConfigurationProperties(prefix="configuration.irs") public class IrsConfig { + /** ATTRIBUTES **/ + Boolean enabled; + String endpoint; + TreeConfig tree; + Paths paths; + String callbackUrl; + + /** CONSTRUCTOR(S) **/ public IrsConfig(Boolean enabled, String endpoint, TreeConfig tree, Paths paths, String callbackUrl) { this.enabled = enabled; this.endpoint = endpoint; @@ -40,17 +51,6 @@ public IrsConfig(Boolean enabled, String endpoint, TreeConfig tree, Paths paths, this.paths = paths; this.callbackUrl = callbackUrl; } - - Boolean enabled; - String endpoint; - - TreeConfig tree; - - Paths paths; - - String callbackUrl; - - public IrsConfig() { } @@ -67,6 +67,7 @@ public IrsConfig(String endpoint, TreeConfig tree, Paths paths, String callbackU this.callbackUrl = callbackUrl; } + /** GETTERS AND SETTERS **/ public String getEndpoint() { return endpoint; @@ -108,12 +109,19 @@ public void setEnabled(Boolean enabled) { this.enabled = enabled; } + /** INNER CLASSES **/ + /** + * This class consists exclusively to define the attributes and methods needed for the IRS Tree configurations. + **/ public static class TreeConfig{ + + /** ATTRIBUTES **/ String fileName; Boolean indent; + public TreeConfig(String fileName) { this.fileName = fileName; } @@ -126,6 +134,7 @@ public TreeConfig(String fileName, Boolean indent) { public TreeConfig() { } + /** GETTERS AND SETTERS **/ public String getFileName() { return fileName; } @@ -143,6 +152,10 @@ public void setIndent(Boolean indent) { } } + + /** + * This class consists exclusively to define the attributes and methods needed for the job path configuration. + **/ public static class Paths{ String job; 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 6ac9780d6..17c667930 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 @@ -38,6 +38,7 @@ import org.eclipse.tractusx.productpass.config.PassportConfig; import org.eclipse.tractusx.productpass.config.ProcessConfig; import org.eclipse.tractusx.productpass.exceptions.ControllerException; +import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.managers.DtrSearchManager; import org.eclipse.tractusx.productpass.managers.ProcessManager; import org.eclipse.tractusx.productpass.models.catenax.BpnDiscovery; @@ -299,7 +300,7 @@ public Response search(@Valid @RequestBody Search searchBody) { Long startedTime = DateTimeUtil.getTimestamp(); try { dataset = dataService.getContractOfferByAssetId(assetId, connectorAddress); - } catch (ControllerException e) { + } catch (ServiceException e) { response.message = "The EDC is not reachable, it was not possible to retrieve catalog!"; response.status = 502; response.statusText = "Bad Gateway"; diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index 34ad56bfc..cb0ed76e0 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -50,13 +50,16 @@ import utils.LogUtil; import java.util.Map; - +/** + * This class consists exclusively to define the HTTP methods needed for the IRS component. + **/ @RestController @RequestMapping("/api/irs") @Tag(name = "IRS Controller") @SecurityRequirement(name = "BearerAuthentication") public class IrsController { + /** ATTRIBUTES **/ private @Autowired HttpServletRequest httpRequest; private @Autowired HttpServletResponse httpResponse; @@ -71,6 +74,23 @@ public class IrsController { private @Autowired TreeManager treeManager; private @Autowired ProcessManager processManager; + /** METHODS **/ + + /** + * HTTP GET method which receives and handles the call back from the IRS + *

+ * @param processId + * the {@code String} process id contained in the path of the url + * @param searchId + * the {@code String} unique hash which identifies the callback search + * @param id + * the {@code String} id from the globalAssetId given by the IRS + * @param state + * the {@code String} state of the IRS callback event + * + * @return this {@code Response} HTTP response with an OK message and 200 status code + * + */ @RequestMapping(value = "/{processId}/{searchId}", method = RequestMethod.GET) @Operation(summary = "Endpoint called by the IRS to set status completed") public Response endpoint(@PathVariable String processId, @PathVariable String searchId, @RequestParam String id, @RequestParam String state) { @@ -101,7 +121,15 @@ public Response endpoint(@PathVariable String processId, @PathVariable String se return httpUtil.buildResponse(response, httpResponse); } } - + /** + * HTTP GET method which returns the current component tree in a simplified structure + *

+ * @param processId + * the {@code String} process id contained in the path of the url + * + * @return this {@code Response} HTTP response with the current component tree of the process + * + */ @RequestMapping(value = "/{processId}/components", method = RequestMethod.GET) @Operation(summary = "Api called by the frontend to obtain the tree of components") public Response components(@PathVariable String processId) { @@ -134,7 +162,15 @@ public Response components(@PathVariable String processId) { return httpUtil.buildResponse(response, httpResponse); } } - + /** + * HTTP GET method which returns the current tree of digital twins which are found in this process + *

+ * @param processId + * the {@code String} process id contained in the path of the url + * + * @return this {@code Response} HTTP response with the current complete tree data model of the process id + * + */ @RequestMapping(value = "/{processId}/tree", method = RequestMethod.GET) @Operation(summary = "Api called by the frontend to obtain the tree of components") public Response tree( @PathVariable String processId) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index 6da664252..b34f9aed7 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -46,16 +46,23 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +/** + * This class consists exclusively of methods to operate on managing the Tree Structure for the IRS component. + * + *

The methods defined here are intended to do every needed operations to run the processes. + * + */ @Component public class TreeManager { + + /** ATTRIBUTES **/ private FileUtil fileUtil; private JsonUtil jsonUtil; - private ProcessManager processManager; - private IrsConfig irsConfig; - private final String PATH_SEP = "/"; + + /** CONSTRUCTOR(S) **/ @Autowired public TreeManager(FileUtil fileUtil, JsonUtil jsonUtil, ProcessManager processManager, IrsConfig irsConfig) { this.fileUtil = fileUtil; @@ -64,13 +71,44 @@ public TreeManager(FileUtil fileUtil, JsonUtil jsonUtil, ProcessManager processM this.irsConfig = irsConfig; } + /** METHODS **/ + + /** + * Gets the Tree File Path by processId + *

+ * @param processId + * the {@code String} id of the application's process. + * + * @return a {@code String} Absolute file path for the tree file + * + */ public String getTreeFilePath(String processId){ return processManager.getProcessFilePath(processId, this.irsConfig.getTree().getFileName()); } + /** + * Checks if the tree data model exists + *

+ * @param processId + * id from the process + * + * @return a {@code Boolean} Confirms if the tree data model exists + * + */ public Boolean treeExists(String processId){ String path = this.getTreeFilePath(processId); return fileUtil.pathExists(path); } + /** + * Creates a new tree file + *

+ * @param processId + * the {@code String} id of the application's process. + * + * @return a {@code String} Path to the tree file created + * + * @throws ManagerException + * if unable to create the file + */ public String createTreeFile(String processId){ try { return this.saveTree(processId, Map.of()); // Save the tree @@ -78,9 +116,31 @@ public String createTreeFile(String processId){ throw new ManagerException(this.getClass().getName()+".newTree()", e, "It was not possible to create the tree data model file"); } } + /** + * Generates a new unique md5 hash (searchId) which is bounded by the globalAssetId and the ProcessId + *

+ * @param processId + * the {@code String} id of the application's process. + * @param globalAssetId + * global asset id {@code String} found in the digital twin asset + * + * @return a {@code String} Search id hash generated + * + */ public static String generateSearchId(String processId, String globalAssetId) { return CrypUtil.md5(DateTimeUtil.getDateTimeFormatted("yyyyMMddHHmmssSSS") + processId + globalAssetId); } + /** + * Returns the tree component from the file system + *

+ * @param processId + * the {@code String} id of the application's process. + * + * @return a {@code Map} Map with the tree content + * + * @throws ManagerException + * if unable to get the tree + */ public Map getTree(String processId){ try { String path = this.getTreeFilePath(processId); // Get filepath from tree @@ -94,7 +154,15 @@ public Map getTree(String processId){ } } - + /** + * Recursive function to parse children from a node data model structure + *

+ * @param children + * the {@code Map} children objects to translate to list + * + * @return a {@code List} List of objects simplified from the tree + * + */ public List parseChildren(Map children){ List components = new ArrayList<>(); // Create a component list if(children == null || children.size() == 0){ @@ -120,7 +188,17 @@ public List parseChildren(Map children){ return components; // Return the components } - + /** + * Recursive parsing of the current nodes, main parent function. + *

+ * @param currentNodes + * the {@code Map} objects to be translated to a list of children + * + * @return a {@code List} List of objects simplified from the tree + * + * @throws ManagerException + * if unable to parse the children recursively + */ public List recursiveParseChildren(Map currentNodes){ try { return this.parseChildren(currentNodes); @@ -129,7 +207,17 @@ public List recursiveParseChildren(Map currentNodes } } - + /** + * Gets the children components from the tree dataModel simplified + *

+ * @param processId + * the {@code String} id of the application's process. + * + * @return a {@code List} List of objects simplified from the tree + * + * @throws ManagerException + * if unable to get the tree components + */ public List getTreeComponents(String processId){ try { Map treeDataModel = this.getTree(processId); // Get filepath from tree @@ -138,12 +226,39 @@ public List getTreeComponents(String processId){ throw new ManagerException(this.getClass().getName()+".getTreeComponents()", e, "It was not possible to get the tree components!"); } } - + /** + * This method can search a digital twin inside of a digital twin list by id + *

+ * @param digitalTwinList + * the {@code List} id of the application's process. + * @param digitalTwinId + * the {@code String} id from the digital twin to be searched + * + * @return a {@code DigitalTwin} from the search result OR {@code null} if not found + * + */ public DigitalTwin searchDigitalTwin(List digitalTwinList, String digitalTwinId){ // Use a parallel search to make the search faster return digitalTwinList.parallelStream().filter(digitalTwin -> digitalTwin.getGlobalAssetId().equals(digitalTwinId)).findFirst().orElse(new DigitalTwin()); } - + /** + * Populates a tree with the Job content and the relationships from an specific data model + *

+ * + * @param treeDataModel + * the {@code Map} tree data model to populate with children + * @param processId + * the {@code String} id of the application's process. + * @param jobHistory + * the {@code JobHistory} job history which contains the identification of the job + * @param job + * the {@code JobResponse} job response containing the IRS content + * + * @return a {@code String} data model file path + * + * @throws ManagerException + * if unable to populate the tree + */ public String populateTree(Map treeDataModel, String processId, JobHistory jobHistory, JobResponse job){ try { List relationships = job.getRelationships(); @@ -165,7 +280,7 @@ public String populateTree(Map treeDataModel, String processId, Jo childDigitalTwin.setGlobalAssetId(childId); } // Create child with the digital twin - Node child = new Node(childDigitalTwin); + Node child = new Node(parentPath, childDigitalTwin); // Add child to the parent parent.setChild(child); } @@ -176,6 +291,21 @@ public String populateTree(Map treeDataModel, String processId, Jo throw new ManagerException(this.getClass().getName() + ".setChild()", e, "It was not possible to get the node from the tree"); } } + /** + * Populates a tree with the Job content and the relationships from the data model in the process file + *

+ * @param processId + * the {@code String} id of the application's process. + * @param jobHistory + * the {@code JobHistory} job history which contains the identification of the job + * @param job + * the {@code JobResponse} job response containing the IRS content + * + * @return a {@code String} data model file path + * + * @throws ManagerException + * if unable to populate the tree + */ public String populateTree(String processId, JobHistory jobHistory, JobResponse job){ try { Map treeDataModel = this.getTree(processId); @@ -184,7 +314,19 @@ public String populateTree(String processId, JobHistory jobHistory, JobResponse throw new ManagerException(this.getClass().getName() + ".setChild()", e, "It was not possible to get the node from the tree"); } } - + /** + * Saves the tree data model in the processId file + *

+ * @param processId + * the {@code String} id of the application's process. + * @param treeDataModel + * the {@code Map} tree data model to be saved + * + * @return a {@code String} data model file path + * + * @throws ManagerException + * if unable to save the tree data model + */ public String saveTree(String processId, Map treeDataModel){ try { String path = this.getTreeFilePath(processId); // Get filepath from tree @@ -197,6 +339,19 @@ public String saveTree(String processId, Map treeDataModel){ throw new ManagerException(this.getClass().getName()+".saveTree()", e, "It was not possible to save the tree data model file"); } } + /** + * Gets a node in the specified tree by path + *

+ * @param treeDataModel + * the {@code Map} tree data model in which the node will be searched + * @param path + * the {@code String} unique path separated by "/" of the node in the tree "example: /node1/node2" + * + * @return a {@code Node} Node if found or {@code null} otherwise + * + * @throws ManagerException + * if unable to get the node by path + */ public Node getNodeByPath(Map treeDataModel, String path){ try { String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children @@ -215,6 +370,19 @@ public Node getNodeByPath(Map treeDataModel, String path){ throw new ManagerException(this.getClass().getName()+".getNodeByPath()", e, "It was not possible to get the node from the tree"); } } + /** + * Gets a node in the specified tree by path + *

+ * @param processId + * the {@code String} process id in which the data model will be retrieved and then searched + * @param path + * the {@code String} unique path separated by "/" of the node in the tree "example: /node1/node2" + * + * @return a {@code Node} Node if found or {@code null} otherwise + * + * @throws ManagerException + * if unable to get the node by path + */ public Node getNodeByPath(String processId, String path){ try { Map treeDataModel = this.getTree(processId); @@ -234,6 +402,21 @@ public Node getNodeByPath(String processId, String path){ throw new ManagerException(this.getClass().getName()+".getNodeByPath()", e, "It was not possible to get the node from the tree"); } } + /** + * Gets a node in the specified tree by path + *

+ * @param treeDataModel + * the {@code Map} tree data model in which the node will be added + * @param path + * the {@code String} unique path separated by "/" of the node in the tree "example: /node1/node2" + * @param node + * the {@code Node} Node object which needs to be added in the data model + * + * @return a {@code (Map)} Data Model in which the node was stored + * + * @throws ManagerException + * if unable to save in the data model the node + */ public Map setNodeByPath(Map treeDataModel, String path, Node node){ try { String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children @@ -251,7 +434,22 @@ public Map setNodeByPath(Map treeDataModel, String p throw new ManagerException(this.getClass().getName()+".setNodeByPath()", e, "It was not possible to get the node from the tree"); } } - public Object setNodeByPath(String processId, String path, Node node){ + /** + * Gets a node in the specified tree by path + *

+ * @param processId + * the {@code String} process id in which the data model will be retrieved and then substituted + * @param path + * the {@code String} unique path separated by "/" of the node in the tree "example: /node1/node2" + * @param node + * the {@code Node} Node object which needs to be added in the data model + * + * @return a {@code String} Data Model File Path where the node was stored + * + * @throws ManagerException + * if unable to save in the data model the node + */ + public String setNodeByPath(String processId, String path, Node node){ try { Map treeDataModel = this.getTree(processId); String translatedPath = jsonUtil.translatePathSep(path, PATH_SEP, ".children."); // Join the path with the children @@ -266,8 +464,22 @@ public Object setNodeByPath(String processId, String path, Node node){ throw new ManagerException(this.getClass().getName()+".setNodeByPath()", e, "It was not possible to get the node from the tree"); } } - - public Object setChild(String processId, String parentPath, Node childNode){ + /** + * Gets a node in the specified tree by path + *

+ * @param processId + * the {@code String} process id in which the data model will be retrieved and then substituted + * @param parentPath + * the {@code String} parent node unique path separated by "/" of the node in the tree "example: /node1/node2" + * @param childNode + * the {@code Node} children node which will be added to the father + * + * @return a {@code String} Data Model File Path where the node was stored + * + * @throws ManagerException + * if unable to save in the data model and in the parent the child node + */ + public String setChild(String processId, String parentPath, Node childNode){ try { Map treeDataModel = this.getTree(processId); Node parentNode = this.getNodeByPath(treeDataModel, parentPath); // Get parent node diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java index 166c6281d..c6f136399 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/Job.java @@ -30,43 +30,48 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; - +/** + * This class consists exclusively to define attributes related to the Job. + **/ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Job { + + /** ATTRIBUTES **/ @JsonProperty("id") - String id; + public String id; @JsonProperty("globalAssetId") - String globalAssetId; + public String globalAssetId; @JsonProperty("state") - String state; + public String state; @JsonProperty("exception") - Object exception; + public Object exception; @JsonProperty("createdOn") - String createdOn; + public String createdOn; @JsonProperty("startedOn") - String startedOn; + public String startedOn; @JsonProperty("lastModifiedOn") - String lastModifiedOn; + public String lastModifiedOn; @JsonProperty("completedOn") - String completedOn; + public String completedOn; @JsonProperty("owner") - String owner; + public String owner; @JsonProperty("summary") - Object summary; + public Object summary; @JsonProperty("parameter") - JobRequest parameter; + public JobRequest parameter; + /** CONSTRUCTOR(S) **/ public Job() { } @@ -84,6 +89,8 @@ public Job(String id, String globalAssetId, String state, Object exception, Stri this.parameter = parameter; } + /** GETTERS AND SETTERS **/ + public String getId() { return id; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java index 95bc3ac6b..1c21fe896 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java @@ -29,18 +29,18 @@ public class JobHistory { + /** ATTRIBUTES **/ @JsonProperty("jobId") - String jobId; - + public String jobId; @JsonProperty("globalAssetId") - String globalAssetId; + public String globalAssetId; @JsonProperty("path") - String path; + public String path; @JsonProperty("created") - Long created; - + public Long created; + /** CONSTRUCTOR(S) **/ public JobHistory() { } @@ -50,7 +50,7 @@ public JobHistory(String jobId, String globalAssetId, String path, Long created) this.path = path; this.created = created; } - + /** GETTERS AND SETTERS **/ public String getJobId() { return jobId; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java index c3a4450ae..db4522f46 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobRequest.java @@ -41,33 +41,34 @@ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class JobRequest { - + /** ATTRIBUTES **/ @JsonProperty("aspects") - ArrayList aspects; + public ArrayList aspects; @JsonProperty("bomLifecycle") - String bomLifecycle; + public String bomLifecycle; @JsonProperty("lookupBPNs") - Boolean lookupBPNs; + public Boolean lookupBPNs; @JsonProperty("collectAspects") - Boolean collectAspects; + public Boolean collectAspects; @JsonProperty("direction") - String direction; + public String direction; @JsonProperty("callbackUrl") - String callbackUrl; + public String callbackUrl; @JsonProperty("depth") - Integer depth; + public Integer depth; @JsonProperty("integrityCheck") - Boolean integrityCheck; + public Boolean integrityCheck; @JsonProperty("key") - Key key; + public Key key; + /** CONSTRUCTOR(S) **/ public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookupBPNs, Boolean collectAspects, String direction, Integer depth, Boolean integrityCheck, Key key) { this.aspects = aspects; this.bomLifecycle = bomLifecycle; @@ -113,6 +114,7 @@ public JobRequest(ArrayList aspects, String bomLifecycle, Boolean lookup this.key = key; } + /** GETTERS AND SETTERS **/ public ArrayList getAspects() { return aspects; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java index c1eef7ed7..a4ea1d454 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobResponse.java @@ -32,23 +32,29 @@ import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import java.util.ArrayList; + +/** + * This class consists exclusively to define attributes related to the Job Response coming from the IRS. + **/ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class JobResponse { + /** ATTRIBUTES **/ @JsonProperty("job") - Job job; + public Job job; @JsonProperty("relationships") - ArrayList relationships; + public ArrayList relationships; @JsonProperty("shells") - ArrayList shells; + public ArrayList shells; @JsonProperty("tombstones") - Object tombstones; + public Object tombstones; @JsonProperty("submodels") - ArrayList submodels; + public ArrayList submodels; @JsonProperty("bpns") - ArrayList bpns; + public ArrayList bpns; + /** CONSTRUCTOR(S) **/ public JobResponse(Job job, ArrayList relationships, ArrayList shells, Object tombstones, ArrayList submodels, ArrayList bpns) { this.job = job; this.relationships = relationships; @@ -61,6 +67,7 @@ public JobResponse(Job job, ArrayList relationships, ArrayList children; - + public Map children; + /** CONSTRUCTOR(S) **/ public Node(Node parent, DigitalTwin digitalTwin, Map children){ this.setup(digitalTwin); this.setPath(parent, digitalTwin.getIdentification()); @@ -99,12 +101,6 @@ public Node(String id, String globalAssetId, String idShort, String path, Digita this.children = children; } - public void setup(DigitalTwin digitalTwin){ - this.id = digitalTwin.getIdentification(); - this.globalAssetId = digitalTwin.getGlobalAssetId(); - this.idShort = digitalTwin.getIdShort(); - this.digitalTwin = digitalTwin; - } public Node(String id, String globalAssetId, String idShort, String path, DigitalTwin digitalTwin, Map children) { this.id = id; this.globalAssetId = globalAssetId; @@ -117,6 +113,15 @@ public Node(String id, String globalAssetId, String idShort, String path, Digita public Node() { } + /** GETTERS AND SETTERS **/ + + public void setup(DigitalTwin digitalTwin){ + this.id = digitalTwin.getIdentification(); + this.globalAssetId = digitalTwin.getGlobalAssetId(); + this.idShort = digitalTwin.getIdShort(); + this.digitalTwin = digitalTwin; + } + public String getId() { return id; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java index f53a52d8a..572f00694 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java @@ -30,20 +30,24 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; - +/** + * This class consists exclusively to define attributes related to the Node Component. + **/ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class NodeComponent { + /** ATTRIBUTES **/ @JsonProperty("id") - String id; + public String id; @JsonProperty("name") - String name; + public String name; @JsonProperty("path") - String path; + public String path; @JsonProperty("children") - List children; + public List children; + /** CONSTRUCTOR(S) **/ public NodeComponent() { } public NodeComponent(Node node, List children) { @@ -66,34 +70,28 @@ public NodeComponent(String id, String idShort, String path, List this.children = children; } + /** GETTERS AND SETTERS **/ public String getId() { return id; } - public void setId(String id) { this.id = id; } - public String getName() { return name; } - public void setName(String name) { this.name = name; } - public String getPath() { return path; } - public void setPath(String path) { this.path = path; } - public List getChildren() { return children; } - public void setChildren(List children) { this.children = children; } 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 bb782a0f3..50f9c3299 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 @@ -145,7 +145,7 @@ public List getEmptyVariables() { * @throws ControllerException * if unable to check the EDC consumer connection. */ - public String checkEdcConsumerConnection() throws ControllerException { + public String checkEdcConsumerConnection() throws ServiceException { try { String edcConsumerDsp = this.edcEndpoint + CatenaXUtil.edcDataEndpoint; Catalog catalog = this.getContractOfferCatalog(edcConsumerDsp, ""); // Get empty catalog @@ -154,7 +154,7 @@ public String checkEdcConsumerConnection() throws ControllerException { } return catalog.getParticipantId(); } catch (Exception e) { - throw new ControllerException(this.getClass().getName()+".checkEdcConsumerConnection", e, "It was not possible to establish connection with the EDC consumer endpoint [" + this.edcEndpoint+"]"); + throw new ServiceException(this.getClass().getName()+".checkEdcConsumerConnection", e, "It was not possible to establish connection with the EDC consumer endpoint [" + this.edcEndpoint+"]"); } } @@ -171,7 +171,7 @@ public String checkEdcConsumerConnection() throws ControllerException { * @throws ControllerException * if unable to get the contract offer for the assetId. */ - public Dataset getContractOfferByAssetId(String assetId, String providerUrl) throws ControllerException { + public Dataset getContractOfferByAssetId(String assetId, String providerUrl) throws ServiceException { /* * This method receives the assetId and looks up for targets with the same name. */ @@ -205,7 +205,7 @@ public Dataset getContractOfferByAssetId(String assetId, String providerUrl) thr Integer index = contractOffersMap.get(assetId); return contractOffers.get(index); } catch (Exception e) { - throw new ControllerException(this.getClass().getName(), e, "It was not possible to get Contract Offer for assetId [" + assetId + "]"); + throw new ServiceException(this.getClass().getName(), e, "It was not possible to get Contract Offer for assetId [" + assetId + "]"); } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 6200554a8..785395379 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -24,17 +24,11 @@ package org.eclipse.tractusx.productpass.services; import com.fasterxml.jackson.databind.JsonNode; -import org.apache.commons.logging.Log; -import org.checkerframework.checker.units.qual.K; import org.eclipse.tractusx.productpass.config.IrsConfig; import org.eclipse.tractusx.productpass.exceptions.ServiceException; import org.eclipse.tractusx.productpass.exceptions.ServiceInitializationException; import org.eclipse.tractusx.productpass.managers.ProcessManager; import org.eclipse.tractusx.productpass.managers.TreeManager; -import org.eclipse.tractusx.productpass.models.catenax.Discovery; -import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; -import org.eclipse.tractusx.productpass.models.edc.DataPlaneEndpoint; -import org.eclipse.tractusx.productpass.models.irs.Job; import org.eclipse.tractusx.productpass.models.irs.JobHistory; import org.eclipse.tractusx.productpass.models.irs.JobRequest; import org.eclipse.tractusx.productpass.models.irs.JobResponse; @@ -49,7 +43,6 @@ import utils.JsonUtil; import utils.LogUtil; -import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -63,6 +56,7 @@ @Service public class IrsService extends BaseService { + /** ATTRIBUTES **/ HttpUtil httpUtil; JsonUtil jsonUtil; @@ -76,6 +70,7 @@ public class IrsService extends BaseService { TreeManager treeManager; VaultService vaultService; + /** CONSTRUCTOR(S) **/ @Autowired public IrsService(Environment env, ProcessManager processManager, IrsConfig irsConfig, TreeManager treeManager, HttpUtil httpUtil, VaultService vaultService, JsonUtil jsonUtil, AuthenticationService authService) throws ServiceInitializationException { this.httpUtil = httpUtil; @@ -91,7 +86,53 @@ public IrsService(Environment env, ProcessManager processManager, IrsConfig irsC public IrsService() { } - public Object startJob(String processId, String globalAssetId, String searchId) throws ServiceException { + /** METHODS **/ + + /** + * Initiates the main needed variables for Data Transfer Service by loading from the environment variables and Vault. + **/ + public void init(Environment env) { + this.irsEndpoint = this.irsConfig.getEndpoint(); + this.irsJobPath = this.irsConfig.getPaths().getJob(); + this.callbackUrl = this.irsConfig.getCallbackUrl(); + } + /** + * Creates a List of missing variables needed to proceed with the request. + *

+ * + * @return an {@code Arraylist} with the environment variables missing in the configuration for the request. + * + */ + @Override + public List getEmptyVariables() { + List missingVariables = new ArrayList<>(); + if (this.irsEndpoint.isEmpty()) { + missingVariables.add("irs.endpoint"); + } + if (this.irsJobPath.isEmpty()) { + missingVariables.add("irs.paths.job"); + } + if (this.callbackUrl.isEmpty()) { + missingVariables.add("irs.callbackUrl"); + } + return missingVariables; + } + /** + * Starts a Job in the IRS for a specific globalAssetId with the backend BPN + *

+ * @param processId + * the {@code String} process id of the job + * @param globalAssetId + * the {@code String} global asset id from the digital twin + * @param searchId + * the {@code String} search id provided by the backend to identify the job + * + * @return a {@code Map} map object with the irs first response + * + * @throws ServiceException + * if unable to start the IRS job + */ + public Map startJob(String processId, String globalAssetId, String searchId) throws ServiceException { try { // In case the BPN is not known use the backend BPN. return this.startJob(processId, globalAssetId, searchId, (String) this.vaultService.getLocalSecret("edc.bpn")); @@ -101,7 +142,23 @@ public Object startJob(String processId, String globalAssetId, String searchId) "It was not possible to start a IRS job! Because of invalid BPN configuration!"); } } - + /** + * Starts a Job in the IRS for a specific globalAssetId with the param BPN + *

+ * @param processId + * the {@code String} process id of the job + * @param globalAssetId + * the {@code String} global asset id from the digital twin + * @param searchId + * the {@code String} search id provided by the backend to identify the job + * @param bpn + * the {@code String} bpn number from the provider to search + * + * @return a {@code Map} map object with the irs first response + * + * @throws ServiceException + * if unable to start the IRS job + */ public Map startJob(String processId, String globalAssetId, String searchId, String bpn) { try { this.checkEmptyVariables(); @@ -137,7 +194,23 @@ public Map startJob(String processId, String globalAssetId, Str "It was not possible to start a IRS job!"); } } - + /** + * Gets the children from a specific node in the tree + *

+ * @param processId + * the {@code String} process id of the job + * @param path + * the {@code String} path of the current node in the tree + * @param globalAssetId + * the {@code String} global asset id from the digital twin + * @param bpn + * the {@code String} bpn number from the provider to search + * + * @return a {@code String} of the Job Id created to get the children asynchronously + * + * @throws ServiceException + * if unable go request the children + */ public String getChildren(String processId, String path, String globalAssetId, String bpn) { try { String searchId = TreeManager.generateSearchId(processId, globalAssetId); @@ -160,7 +233,17 @@ public String getChildren(String processId, String path, String globalAssetId, S throw new ServiceException(this.getClass().getName() + "." + "getChildren", e, "It was not possible to get the children for the digital twin"); } } - + /** + * Retrieves a Job from the IRS by id + *

+ * @param jobId + * the {@code String} id from the job to retrieve + * + * @return a {@code JobResponse} object which contains the job information + * + * @throws ServiceException + * if unable to retrieve the job + */ public JobResponse getJob(String jobId) { try { String url = this.irsEndpoint + "/" + this.irsJobPath + "/" + jobId; @@ -177,21 +260,5 @@ public JobResponse getJob(String jobId) { } - @Override - public List getEmptyVariables() { - List missingVariables = new ArrayList<>(); - if (this.irsEndpoint.isEmpty()) { - missingVariables.add("irs.endpoint"); - } - if (this.irsJobPath.isEmpty()) { - missingVariables.add("irs.paths.job"); - } - return missingVariables; - } - public void init(Environment env) { - this.irsEndpoint = this.irsConfig.getEndpoint(); - this.irsJobPath = this.irsConfig.getPaths().getJob(); - this.callbackUrl = this.irsConfig.getCallbackUrl(); - } } From 254894b1bbc8eadeef914845b5e22fc617e9d76a Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Thu, 19 Oct 2023 12:27:35 +0200 Subject: [PATCH 20/25] fix: applied fix when searching semanticIds --- .../org/eclipse/tractusx/productpass/services/AasService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4d6d9bfd5..a0baade3e 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 @@ -622,7 +622,7 @@ public Integer getDtIndex() { @Override public void run() { this.setDigitalTwin(searchDigitalTwin(this.getIdType(), this.getAssetId(), this.getDtIndex(), this.getEdr().getEndpoint(), this.getEdr())); - if(semanticId.isEmpty()){ + if(this.semanticId == null || this.semanticId.isEmpty()){ this.setSubModel(searchSubModelBySemanticId(this.getDigitalTwin())); }else { this.setSubModel(searchSubModelBySemanticId(this.getDigitalTwin(), semanticId)); From 5ce6b2c5894ae928097dc2f70adbd59b394df5c3 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Thu, 19 Oct 2023 15:21:09 +0200 Subject: [PATCH 21/25] fix: fixed bug with the catena-x id --- .../eclipse/tractusx/productpass/managers/TreeManager.java | 6 +++--- .../eclipse/tractusx/productpass/models/manager/Node.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index b34f9aed7..aa49e4c76 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -282,7 +282,7 @@ public String populateTree(Map treeDataModel, String processId, Jo // Create child with the digital twin Node child = new Node(parentPath, childDigitalTwin); // Add child to the parent - parent.setChild(child); + parent.setChild(child, childId); } // Set node and save the tree treeDataModel = this.setNodeByPath(treeDataModel, parentPath, parent); // Save the parent node in the tree @@ -479,11 +479,11 @@ public String setNodeByPath(String processId, String path, Node node){ * @throws ManagerException * if unable to save in the data model and in the parent the child node */ - public String setChild(String processId, String parentPath, Node childNode){ + public String setChild(String processId, String parentPath, Node childNode, String globalAssetId){ try { Map treeDataModel = this.getTree(processId); Node parentNode = this.getNodeByPath(treeDataModel, parentPath); // Get parent node - parentNode.setChild(childNode); // Add the child to the parent node + parentNode.setChild(childNode, globalAssetId); // Add the child to the parent node treeDataModel = this.setNodeByPath(treeDataModel, parentPath, parentNode); // Save the parent node in the tree return this.saveTree(processId, treeDataModel); } catch (Exception e) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java index 3bbf30b0f..02620458c 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java @@ -171,8 +171,8 @@ public Map getChildren() { public void setChildren(Map children) { this.children = children; } - public void setChild(Node childNode){ - this.children.put(childNode.getGlobalAssetId(), childNode); + public void setChild(Node childNode, String globalAssetId){ + this.children.put(globalAssetId, childNode); } public Node getChild(String childId){ From 0154d87db361943090fc74e8fec3ab0c9eece149 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Mon, 23 Oct 2023 16:29:21 +0200 Subject: [PATCH 22/25] feat: added search id to node and component tree --- .../models/dtregistry/DigitalTwin.java | 135 ++++++++++++------ .../productpass/models/manager/Node.java | 28 ++++ .../models/manager/NodeComponent.java | 12 ++ .../src/main/java/utils/CatenaXUtil.java | 41 +++++- 4 files changed, 172 insertions(+), 44 deletions(-) diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/DigitalTwin.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/DigitalTwin.java index 6462e2313..79bdc0363 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/DigitalTwin.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/dtregistry/DigitalTwin.java @@ -29,6 +29,9 @@ import com.fasterxml.jackson.databind.JsonNode; import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * This class consists exclusively to define attributes related to the designed model of the Digital Twin's improved version. @@ -53,43 +56,11 @@ public class DigitalTwin { @JsonProperty("id") String identification; @JsonProperty("specificAssetIds") - ArrayList specificAssetIds; + ArrayList specificAssetIds; @JsonProperty("submodelDescriptors") ArrayList submodelDescriptors; - /** CONSTRUCTOR(S) **/ - @SuppressWarnings("Unused") - public DigitalTwin() { - } - @SuppressWarnings("Unused") - public DigitalTwin(ArrayList description, String idShort, String identification, ArrayList specificAssetIds, ArrayList submodelDescriptors) { - this.description = description; - this.idShort = idShort; - this.identification = identification; - this.specificAssetIds = specificAssetIds; - this.submodelDescriptors = submodelDescriptors; - } - @SuppressWarnings("Unused") - public DigitalTwin(ArrayList description, String idShort, Object displayName, String identification, ArrayList specificAssetIds, ArrayList submodelDescriptors) { - this.description = description; - this.idShort = idShort; - this.displayName = displayName; - this.identification = identification; - this.specificAssetIds = specificAssetIds; - this.submodelDescriptors = submodelDescriptors; - } - @SuppressWarnings("Unused") - public DigitalTwin(ArrayList description, String idShort, String globalAssetId, Object displayName, String identification, ArrayList specificAssetIds, ArrayList submodelDescriptors) { - this.description = description; - this.idShort = idShort; - this.globalAssetId = globalAssetId; - this.displayName = displayName; - this.identification = identification; - this.specificAssetIds = specificAssetIds; - this.submodelDescriptors = submodelDescriptors; - } - @SuppressWarnings("Unused") - public DigitalTwin(ArrayList description, String idShort, String assetKind, String assetType, String globalAssetId, Object displayName, String identification, ArrayList specificAssetIds, ArrayList submodelDescriptors) { + public DigitalTwin(ArrayList description, String idShort, String assetKind, String assetType, String globalAssetId, Object displayName, String identification, ArrayList specificAssetIds, ArrayList submodelDescriptors) { this.description = description; this.idShort = idShort; this.assetKind = assetKind; @@ -101,7 +72,94 @@ public DigitalTwin(ArrayList description, String idShort, String asset this.submodelDescriptors = submodelDescriptors; } + /** INNER CLASSES **/ + + /** + * This class consists exclusively to define attributes and methods related to the digital twin specific asset ids + **/ + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + static class SpecificAssetId{ + /** ATTRIBUTES **/ + + @JsonProperty("supplementalSemanticIds") + List supplementalSemanticIds; + + @JsonProperty("name") + String name; + + @JsonProperty("value") + String value; + + @JsonProperty("externalSubjectId") + Object externalSubjectId; + /** CONSTRUCTOR(S) **/ + public SpecificAssetId(List supplementalSemanticIds, String name, String value, Object externalSubjectId) { + this.supplementalSemanticIds = supplementalSemanticIds; + this.name = name; + this.value = value; + this.externalSubjectId = externalSubjectId; + } + /** GETTERS AND SETTERS **/ + public List getSupplementalSemanticIds() { + return supplementalSemanticIds; + } + + public void setSupplementalSemanticIds(List supplementalSemanticIds) { + this.supplementalSemanticIds = supplementalSemanticIds; + } + + public String getName() { + return name; + } + + public String parseLowerCaseName() { + return name.toLowerCase(); + } + + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Object getExternalSubjectId() { + return externalSubjectId; + } + + public void setExternalSubjectId(Object externalSubjectId) { + this.externalSubjectId = externalSubjectId; + } + } + + /** CONSTRUCTOR(S) **/ + @SuppressWarnings("Unused") + public DigitalTwin() { + } + + /** GETTERS AND SETTERS **/ + public ArrayList getSpecificAssetIds() { + return specificAssetIds; + } + + public void setSpecificAssetIds(ArrayList specificAssetIds) { + this.specificAssetIds = specificAssetIds; + } + + public Map mapSpecificAssetIds() { + return this.getSpecificAssetIds().stream().collect( + Collectors.toMap(SpecificAssetId::parseLowerCaseName, SpecificAssetId::getValue) + ); + } + public ArrayList getDescription() { return description; } @@ -121,14 +179,7 @@ public String getIdentification() { public void setIdentification(String identification) { this.identification = identification; } - @SuppressWarnings("Unused") - public ArrayList getSpecificAssetIds() { - return specificAssetIds; - } - @SuppressWarnings("Unused") - public void setSpecificAssetIds(ArrayList specificAssetIds) { - this.specificAssetIds = specificAssetIds; - } + public ArrayList getSubmodelDescriptors() { return submodelDescriptors; } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java index 02620458c..d2b425fd7 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/Node.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import org.eclipse.tractusx.productpass.models.irs.JobResponse; +import utils.CatenaXUtil; import java.util.Map; /** @@ -46,6 +47,8 @@ public class Node { public String globalAssetId; @JsonProperty("idShort") public String idShort; + @JsonProperty("searchId") + public String searchId; @JsonProperty("path") public String path; @JsonProperty("digitalTwin") @@ -113,13 +116,26 @@ public Node(String id, String globalAssetId, String idShort, String path, Digita public Node() { } + public Node(String id, String globalAssetId, String idShort, String searchId, String path, DigitalTwin digitalTwin, JobResponse job, Map children) { + this.id = id; + this.globalAssetId = globalAssetId; + this.idShort = idShort; + this.searchId = searchId; + this.path = path; + this.digitalTwin = digitalTwin; + this.job = job; + this.children = children; + } + /** GETTERS AND SETTERS **/ public void setup(DigitalTwin digitalTwin){ this.id = digitalTwin.getIdentification(); this.globalAssetId = digitalTwin.getGlobalAssetId(); this.idShort = digitalTwin.getIdShort(); + this.setSearchId(digitalTwin); this.digitalTwin = digitalTwin; + } public String getId() { @@ -191,4 +207,16 @@ public JobResponse getJob() { public void setJob(JobResponse job) { this.job = job; } + + public String getSearchId() { + return searchId; + } + + public void setSearchId(String searchId) { + this.searchId = searchId; + } + + public void setSearchId(DigitalTwin digitalTwin) { + this.searchId = CatenaXUtil.buildDppSearchId(digitalTwin, null); + } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java index 572f00694..03eb47923 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/manager/NodeComponent.java @@ -42,6 +42,8 @@ public class NodeComponent { public String id; @JsonProperty("name") public String name; + @JsonProperty("searchId") + public String searchId; @JsonProperty("path") public String path; @JsonProperty("children") @@ -53,12 +55,14 @@ public NodeComponent() { public NodeComponent(Node node, List children) { this.id = node.globalAssetId; this.path = node.path; + this.searchId = node.searchId; this.name = node.idShort; this.children = children; } public NodeComponent(Node node) { this.id = node.globalAssetId; this.path = node.path; + this.searchId = node.searchId; this.name = node.idShort; this.children = List.of(); } @@ -95,4 +99,12 @@ public List getChildren() { public void setChildren(List children) { this.children = children; } + + public String getSearchId() { + return searchId; + } + + public void setSearchId(String searchId) { + this.searchId = searchId; + } } diff --git a/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java b/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java index d7ded75c3..14c5b70a6 100644 --- a/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java +++ b/consumer-backend/productpass/src/main/java/utils/CatenaXUtil.java @@ -23,10 +23,12 @@ package utils; +import org.eclipse.tractusx.productpass.models.dtregistry.DigitalTwin; import org.springframework.core.env.Environment; import utils.exceptions.UtilException; import java.nio.file.Paths; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -42,6 +44,8 @@ public final class CatenaXUtil { public final static String bpnNumberPattern = "BPN[LSA][A-Z0-9]{12}"; public final static String edcDataEndpoint = "/api/v1/dsp"; + public final static String catenaXPrefix = "CX"; + /** * Checks if the given String contains a BPN number pattern in it. *

@@ -83,9 +87,9 @@ public static String buildDataEndpoint(String endpoint) { } /** - * Gets the BPN number from a given String, if exists. + * Gets an aspect name from the semantic id *

- * @param str + * @param semanticId * the {@code String} object to get BPN number from. * * @return the {@code String} BPN number found in the given String or null if it doesn't exist. @@ -99,6 +103,39 @@ public static String getAspectNameFromSemanticId(String semanticId){ } } + /** + * Build the search id from a digital twin. + *

+ * @param digitalTwin + * the {@code DigitalTwin} digital twin to build the dpp search id + * + * @return the {@code String} BPN number found in the given String or null if it doesn't exist. + * + */ + public static String buildDppSearchId(DigitalTwin digitalTwin, String defaultValue){ + try { + Map mappedSpecificAssetIds = digitalTwin.mapSpecificAssetIds(); + // all the mapped values are in lowercase to avoid case sensitivity + String partInstanceId = mappedSpecificAssetIds.get("partinstanceid"); + String manufacturerPartId = mappedSpecificAssetIds.get("manufacturerpartid"); + if(partInstanceId == null || manufacturerPartId == null){ + return defaultValue; // Return default value + } + return String.join(":", catenaXPrefix, manufacturerPartId, partInstanceId); + }catch(Exception e){ + throw new UtilException(CatenaXUtil.class, e, "[ERROR] It was not possible to build the dpp search id"); + } + } + + /** + * Gets the BPN number from a given String, if exists. + *

+ * @param str + * the {@code String} object to get BPN number from. + * + * @return the {@code String} BPN number found in the given String or null if it doesn't exist. + * + */ public static String getBPN(String str) { Pattern pattern = Pattern.compile(bpnNumberPattern); Matcher matcher = pattern.matcher(str); From 2797d1f4842ad3c02b488972b2a5e89149647982 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Tue, 24 Oct 2023 18:39:45 +0200 Subject: [PATCH 23/25] feat: added recount of children in job to verify if it has children or not --- .../controllers/api/ContractController.java | 8 +- .../http/controllers/api/IrsController.java | 71 +++++++++++++++- .../productpass/managers/ProcessManager.java | 76 +++++++++++++----- .../productpass/managers/TreeManager.java | 8 +- .../productpass/models/irs/JobHistory.java | 41 +++++++++- .../productpass/models/manager/Status.java | 80 ++++--------------- .../productpass/services/IrsService.java | 8 +- 7 files changed, 193 insertions(+), 99 deletions(-) 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 17c667930..819540629 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 @@ -276,7 +276,12 @@ public Response search(@Valid @RequestBody Search searchBody) { response = httpUtil.getBadRequest("No digital twins are available for this process!"); return httpUtil.buildResponse(response, httpResponse); } - process = processManager.createProcess(processId, httpRequest); + Boolean childrenCondition = searchBody.getChildren(); + if(childrenCondition != null){ + process = processManager.createProcess(processId, childrenCondition, httpRequest); // Store the children condition + }else { + process = processManager.createProcess(processId, httpRequest); + } Status status = processManager.getStatus(processId); if (status == null) { response = httpUtil.getBadRequest("The status is not available!"); @@ -288,7 +293,6 @@ public Response search(@Valid @RequestBody Search searchBody) { response = httpUtil.getBadRequest("No digital twin was found!"); return httpUtil.buildResponse(response, httpResponse); } - // Assing the variables with the content String assetId = assetSearch.getAssetId(); String connectorAddress = assetSearch.getConnectorAddress(); diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java index cb0ed76e0..666f76790 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/http/controllers/api/IrsController.java @@ -105,11 +105,11 @@ public Response endpoint(@PathVariable String processId, @PathVariable String se return httpUtil.buildResponse(httpUtil.getNotFound("No status is created"), httpResponse); } - if(!status.getJobs().containsKey(searchId)){ - return httpUtil.buildResponse(httpUtil.getNotFound("The search id is invalid!"), httpResponse); + if(!status.getJob().getSearchId().equals(searchId)){ + return httpUtil.buildResponse(httpUtil.getNotAuthorizedResponse(), httpResponse); } - JobHistory jobHistory = status.getJobId(searchId); + JobHistory jobHistory = status.getJob(); LogUtil.printMessage("["+processId+"] Job callback received with state ["+ state+"]. Requesting Job ["+jobHistory.getJobId()+"]!"); JobResponse irsJob = this.irsService.getJob(jobHistory.getJobId()); @@ -203,6 +203,71 @@ public Response tree( @PathVariable String processId) { } } + /** + * HTTP GET method which returns the current tree of digital twins which are found in this process + *

+ * @param processId + * the {@code String} process id contained in the path of the url + * + * @return this {@code Response} HTTP response with the current complete tree data model of the process id + * + */ + @RequestMapping(value = "/{processId}/state", method = RequestMethod.GET) + @Operation(summary = "Api called by the frontend to check if the process is finished") + public Response state( @PathVariable String processId) { + Response response = httpUtil.getInternalError(); + if (!authService.isAuthenticated(httpRequest)) { + response = httpUtil.getNotAuthorizedResponse(); + return httpUtil.buildResponse(response, httpResponse); + } + try { + if (!processManager.checkProcess(processId)) { + return httpUtil.buildResponse(httpUtil.getNotFound("Process not found!"), httpResponse); + } + + Status status = processManager.getStatus(processId); + if(status == null){ + return httpUtil.buildResponse(httpUtil.getNotFound("No status is created"), httpResponse); + } + if(!this.irsConfig.getEnabled()){ + response = httpUtil.getResponse("The children drill down functionality is not available!"); + response.status = 503; + response.statusText = "Service Unavailable"; + return httpUtil.buildResponse(response, httpResponse); + } + if(!status.getChildren()){ + response = httpUtil.getResponse("The children drill down functionality is not available for this process!"); + response.status = 503; + response.statusText = "Service Unavailable"; + return httpUtil.buildResponse(response, httpResponse); + } + response = httpUtil.getResponse(); + Integer jobStatus = status.getJob().getChildren(); + + switch (jobStatus){ + case -1: + response.status = 100; + response.statusText = "Continue"; + response.message = "Still searching for the children!"; + break; + case 0: + response.status = 404; + response.statusText = "Not Found"; + response.message = "No children is available"; + break; + + default: + response.status = 200; + response.statusText = "Success"; + response.message = "Children available!"; + + } + return httpUtil.buildResponse(response, httpResponse); + } catch (Exception e) { + response.message = e.getMessage(); + 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 1a8cf58d2..a72296245 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 @@ -385,7 +385,7 @@ public Process createProcess(HttpServletRequest httpRequest, String connectorAdd Process process = new Process(CrypUtil.getUUID(), "CREATED", createdTime); LogUtil.printMessage("Process Created [" + process.id + "], waiting for user to sign or decline..."); this.setProcess(httpRequest, process); // Add process to session storage - this.newStatusFile(process.id, connectorAddress, createdTime); // Set the status from the process in file system logs. + this.newStatusFile(process.id, connectorAddress, createdTime, true); // Set the status from the process in file system logs. return process; } @@ -509,10 +509,32 @@ public Process createProcess(String processId, HttpServletRequest httpRequest) { Process process = new Process(processId, "CREATED", createdTime); LogUtil.printMessage("Process Created [" + process.id + "], waiting for user to sign or decline..."); this.setProcess(httpRequest, process); // Add process to session storage - this.newStatusFile(process.id,"", createdTime); // Set the status from the process in file system logs. + this.newStatusFile(process.id,"", createdTime, true); // Set the status from the process in file system logs. + return process; + } + /** + * Creates a new Process with the given processId into the given HTTP session. + *

+ * @param processId + * the {@code String} id of the application's process. + * @param childrenCondition + * the {@code Boolean} condition which enables if the search will request the irs for children + * @param httpRequest + * the HTTP request. + * + * @return a {@code Process} object created. + * + * @throws ManagerException + * if unable to create the process. + */ + public Process createProcess(String processId,Boolean childrenCondition, HttpServletRequest httpRequest) { + Long createdTime = DateTimeUtil.getTimestamp(); + Process process = new Process(processId, "CREATED", createdTime); + LogUtil.printMessage("Process Created [" + process.id + "], waiting for user to sign or decline..."); + this.setProcess(httpRequest, process); // Add process to session storage + this.newStatusFile(process.id,"", createdTime, childrenCondition); // Set the status from the process in file system logs. return process; } - /** * Creates a new Process with the given processId into the given HTTP session, * setting the process with the given BPN number. @@ -535,7 +557,7 @@ public Process createProcess(HttpServletRequest httpRequest, String processId, S Process process = new Process(processId, "CREATED", createdTime); LogUtil.printMessage("Process Created [" + process.id + "], waiting for user to sign or decline..."); this.setProcess(httpRequest, process); // Add process to session storage - this.newStatusFile(process.id,"", createdTime); // Set the status from the process in file system logs. + this.newStatusFile(process.id,"", createdTime, true); // Set the status from the process in file system logs. this.setBpn(process.id, bpn); return process; } @@ -549,6 +571,8 @@ public Process createProcess(HttpServletRequest httpRequest, String processId, S * the {@code String} URL address the of the connector. * @param created * the {@code Long} timestamp of the creation. + * @param childrenCondition + * the {@code Boolean} condition which enables if the search will request the irs for children * * @return a {@code String} file path of the created file. * @@ -556,7 +580,7 @@ public Process createProcess(HttpServletRequest httpRequest, String processId, S * if unable to create the status file. */ - public String newStatusFile(String processId, String connectorAddress, Long created){ + public String newStatusFile(String processId, String connectorAddress, Long created, Boolean childrenCondition){ try { String path = this.getProcessFilePath(processId, this.metaFileName); return jsonUtil.toJsonFile( @@ -566,11 +590,13 @@ public String newStatusFile(String processId, String connectorAddress, Long crea "CREATED", created, DateTimeUtil.getTimestamp(), - Map.of(), + new JobHistory(), connectorAddress, "", "", - Map.of() + childrenCondition, + "", + Map.of(), "" ), processConfig.getIndent()); // Store the plain JSON } catch (Exception e) { @@ -717,20 +743,21 @@ public String setTreeState(String processId, String state) { throw new ManagerException(this.getClass().getName(), e, "It was not possible to create/update the status file"); } } - /** - * Gets the job history for an globalAssetId + + /** + * Adds the job history in the status file *

* @param processId * the {@code String} id of the application's process. - * @param globalAssetId - * the {@code String} global asset id from the history + * @param jobHistory + * the {@code JobHistory} job history from the irs * - * @return a {@code JobHistory} history from the job search in the IRS + * @return a {@code String} file path of the process status file. * * @throws ManagerException * if unable to update the status file. */ - public JobHistory getJobHistoryById(String processId, String globalAssetId) { + public String setJobHistory(String processId, JobHistory jobHistory) { try { String path = this.getProcessFilePath(processId, this.metaFileName); Status statusFile = null; @@ -739,27 +766,29 @@ public JobHistory getJobHistoryById(String processId, String globalAssetId) { } statusFile = (Status) jsonUtil.fromJsonFileToObject(path, Status.class); - return statusFile.getJobId(globalAssetId); + statusFile.setJob(jobHistory); + String searchId = jobHistory.searchId; + statusFile.setHistory(jobHistory.searchId, new History(searchId, searchId+"-DRILLDOWN-STARTED")); + 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 create/update the status file"); } } /** - * Adds the job history in the status file + * Adds the job history in the status file *

* @param processId * the {@code String} id of the application's process. - * @param searchId - * the {@code String} search id for the irs job - * @param jobHistory - * the {@code JobHistory} job history from the irs + * @param children + * the {@code Integer} number of children found * * @return a {@code String} file path of the process status file. * * @throws ManagerException * if unable to update the status file. */ - public String addJobHistory(String processId, String searchId, JobHistory jobHistory) { + public String setJobChildrenFound(String processId, Integer children) { try { String path = this.getProcessFilePath(processId, this.metaFileName); Status statusFile = null; @@ -768,8 +797,11 @@ public String addJobHistory(String processId, String searchId, JobHistory jobHis } statusFile = (Status) jsonUtil.fromJsonFileToObject(path, Status.class); - statusFile.addJobHistory(searchId, jobHistory); - statusFile.setHistory(searchId, new History(searchId, searchId+"-DRILLDOWN-STARTED")); + JobHistory jobHistory = statusFile.getJob(); + jobHistory.setChildren(children); + statusFile.setJob(jobHistory); + String searchId = jobHistory.searchId; + statusFile.setHistory(searchId, new History(searchId, searchId+"-DRILLDOWN-COMPLETED")); statusFile.setModified(DateTimeUtil.getTimestamp()); return jsonUtil.toJsonFile(path, statusFile, processConfig.getIndent()); // Store the plain JSON } catch (Exception e) { diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java index aa49e4c76..0f9679673 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/managers/TreeManager.java @@ -271,7 +271,13 @@ public String populateTree(Map treeDataModel, String processId, Jo } catch (Exception e) { throw new ManagerException(this.getClass().getName(), e, "Could not bind the reference type for the Digital Twin!"); } - + int childrenFound = relationships.size(); + this.processManager.setJobChildrenFound(processId, childrenFound); + if(childrenFound == 0){ + parent.setChildren(null); // If there is no children return null; + treeDataModel = this.setNodeByPath(treeDataModel, parentPath, parent); // Save the parent node in the tree + return this.saveTree(processId, treeDataModel); + } for(Relationship relationship : relationships){ String childId = relationship.getLinkedItem().getChildCatenaXId(); // Search for the Digital Twin from the child or a new instance diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java index 1c21fe896..a01c03e3a 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/models/irs/JobHistory.java @@ -32,24 +32,35 @@ public class JobHistory { /** ATTRIBUTES **/ @JsonProperty("jobId") public String jobId; + @JsonProperty("searchId") + public String searchId; + @JsonProperty("globalAssetId") public String globalAssetId; @JsonProperty("path") public String path; @JsonProperty("created") public Long created; - + @JsonProperty("updated") + public Long updated; + @JsonProperty("children") + public Integer children; /** CONSTRUCTOR(S) **/ public JobHistory() { } - public JobHistory(String jobId, String globalAssetId, String path, Long created) { + public JobHistory(String jobId, String searchId, String globalAssetId, String path, Long created, Long updated, Integer children) { this.jobId = jobId; + this.searchId = searchId; this.globalAssetId = globalAssetId; this.path = path; this.created = created; + this.updated = updated; + this.children = children; } + + /** GETTERS AND SETTERS **/ public String getJobId() { return jobId; @@ -59,6 +70,7 @@ public void setJobId(String jobId) { this.jobId = jobId; } + public String getGlobalAssetId() { return globalAssetId; } @@ -83,4 +95,29 @@ public String getPath() { public void setPath(String path) { this.path = path; } + + public Long getUpdated() { + return updated; + } + + public void setUpdated(Long updated) { + this.updated = updated; + } + + + public String getSearchId() { + return searchId; + } + + public void setSearchId(String searchId) { + this.searchId = searchId; + } + + public Integer getChildren() { + return children; + } + + public void setChildren(Integer children) { + this.children = children; + } } 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 26c5876fb..db5686064 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 @@ -53,8 +53,8 @@ public class Status { @JsonProperty("modified") public Long modified; - @JsonProperty("jobs") - public Map jobs; + @JsonProperty("job") + public JobHistory job; @JsonProperty("endpoint") public String endpoint; @@ -174,63 +174,18 @@ public Status(String id, String status, Long created, Long modified, String endp this.bpn = bpn; this.history = new HashMap(); } - @SuppressWarnings("Unused") - public Status(String id, String status, Long created, Long modified, String endpoint, String bpn, String historyId, History history) { - this.id = id; - this.status = status; - this.created = created; - this.modified = modified; - this.endpoint = endpoint; - this.bpn = bpn; - this.history = Map.of(historyId, history); - } - public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, Map history) { - this.id = id; - this.status = status; - this.created = created; - this.modified = modified; - this.jobs = jobs; - this.endpoint = endpoint; - this.bpn = bpn; - this.history = history; - } - - public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, String treeState, Map history) { - this.id = id; - this.status = status; - this.created = created; - this.modified = modified; - this.jobs = jobs; - this.endpoint = endpoint; - this.bpn = bpn; - this.treeState = treeState; - this.history = history; - } - - public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String bpn, Boolean children, String treeState, Map history) { - this.id = id; - this.status = status; - this.created = created; - this.modified = modified; - this.jobs = jobs; - this.endpoint = endpoint; - this.bpn = bpn; - this.children = children; - this.treeState = treeState; - this.history = history; - } public Status() { } - public Status(String id, String status, Long created, Long modified, Map jobs, String endpoint, String dataPlaneUrl, String bpn, Boolean children, String treeState, Map history, String semanticId) { + public Status(String id, String status, Long created, Long modified, JobHistory job, String endpoint, String dataPlaneUrl, String bpn, Boolean children, String treeState, Map history, String semanticId) { this.id = id; this.status = status; this.created = created; this.modified = modified; - this.jobs = jobs; + this.job = job; this.endpoint = endpoint; this.dataPlaneUrl = dataPlaneUrl; this.bpn = bpn; @@ -240,6 +195,8 @@ public Status(String id, String status, Long created, Long modified, Map getJobs() { - return jobs; - } - - public void setJobs(Map jobs) { - this.jobs = jobs; - } - - public void addJobHistory(String searchId, JobHistory jobHistory){ - if(this.jobs == null){ - this.jobs = Map.of(); - } - this.jobs.put(searchId, jobHistory); - } - public JobHistory getJobId(String searchId){ - return this.jobs.get(searchId); - } public String getTreeState() { return treeState; @@ -367,6 +307,14 @@ public String getDataPlaneUrl() { public void setDataPlaneUrl(String dataPlaneUrl) { this.dataPlaneUrl = dataPlaneUrl; } + + public JobHistory getJob() { + return job; + } + + public void setJob(JobHistory job) { + this.job = job; + } } diff --git a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java index 785395379..cb8422579 100644 --- a/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java +++ b/consumer-backend/productpass/src/main/java/org/eclipse/tractusx/productpass/services/IrsService.java @@ -218,14 +218,16 @@ public String getChildren(String processId, String path, String globalAssetId, S Map irsResponse = this.startJob(processId, globalAssetId, searchId, bpn); String jobId = irsResponse.get("id"); LogUtil.printMessage("[PROCESS "+ processId + "] Job with id [" + jobId + "] created in the IRS for the globalAssetId [" + globalAssetId+"]"); - this.processManager.addJobHistory( + this.processManager.setJobHistory( processId, - searchId, new JobHistory( jobId, + searchId, globalAssetId, path, - created + created, + created, + 0 ) ); return jobId; From 31365be9da44eaebd36d19e825825d449a3cdc76 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Tue, 31 Oct 2023 12:39:09 +0100 Subject: [PATCH 24/25] merge: fixed merged changes --- .../productpass/managers/ProcessManager.java | 14 +------------- .../productpass/models/manager/Status.java | 8 -------- 2 files changed, 1 insertion(+), 21 deletions(-) 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 4a76c9a82..4e71c5275 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 @@ -356,18 +356,6 @@ private String getTmpProcessDir(String processId, Boolean absolute) { } } - /** - * Creates a new process in the given HTTP session. - *

- * @param httpRequest - * the HTTP request. - * - * @return a {@code Process} object representing the created process. - * - */ - public Process createProcess(HttpServletRequest httpRequest) { - return this.createProcess(httpRequest, "", ""); - } /** * Creates a new process in the given HTTP session and set its status in the file system logs. @@ -380,7 +368,7 @@ public Process createProcess(HttpServletRequest httpRequest) { * @return a {@code Process} object representing the created process. * */ - public Process createProcess(HttpServletRequest httpRequest, String connectorAddress, String dataPlaneUrl) { + public Process createProcess(HttpServletRequest httpRequest, String connectorAddress) { Long createdTime = DateTimeUtil.getTimestamp(); Process process = new Process(CrypUtil.getUUID(), "CREATED", createdTime); LogUtil.printMessage("Process Created [" + process.id + "], waiting for user to sign or decline..."); 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 5f6bcea4e..df2c1ab57 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 @@ -318,14 +318,6 @@ public void setSemanticId(String semanticId) { this.semanticId = semanticId; } - public String getDataPlaneUrl() { - return dataPlaneUrl; - } - - public void setDataPlaneUrl(String dataPlaneUrl) { - this.dataPlaneUrl = dataPlaneUrl; - } - public JobHistory getJob() { return job; } From 97581c994826eaa4db3e46bc301d372818a41822 Mon Sep 17 00:00:00 2001 From: Mathias Brunkow Moser Date: Fri, 3 Nov 2023 09:36:57 +0100 Subject: [PATCH 25/25] chore: updated readmes and runned ip check --- CHANGELOG.md | 13 +++++++++++++ DEPENDENCIES_FRONTEND | 1 - docs/RELEASE_USER.md | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39b995183..637a3140e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,19 @@ The changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [pre-released] +## [v1.3.0] - 03-11-2023 + + +## Added +- New IRS Service which is able to communicate with the IRS component api. +- Added condition to deactivate the IRS +- Added tree manager to manage the tree of components used by each irs process +- Added structure to manage the information coming from the IRS and jobs initiated +- Enabled callback mechanism with the IRS component +- Created `/api/irs/{processId}/tree` and `/api/irs/{processId}/components` APIs + + ## [released] ## [1.2.1] - 31-10-2023 diff --git a/DEPENDENCIES_FRONTEND b/DEPENDENCIES_FRONTEND index b9bfdd228..edd0ee959 100644 --- a/DEPENDENCIES_FRONTEND +++ b/DEPENDENCIES_FRONTEND @@ -37,7 +37,6 @@ npm/npmjs/-/cross-spawn/7.0.3, MIT, approved, clearlydefined npm/npmjs/-/crypto-js/4.2.0, MIT AND BSD-2-Clause, approved, #11347 npm/npmjs/-/cssesc/3.0.0, MIT, approved, clearlydefined npm/npmjs/-/csstype/2.6.21, MIT, approved, clearlydefined -npm/npmjs/-/cypress-keycloak/1.9.0, MIT, approved, #6952 npm/npmjs/-/de-indent/1.0.2, MIT, approved, clearlydefined npm/npmjs/-/debug/4.3.4, MIT, approved, clearlydefined npm/npmjs/-/deep-is/0.1.4, MIT, approved, #2130 diff --git a/docs/RELEASE_USER.md b/docs/RELEASE_USER.md index 0e9139368..ecb0a949c 100644 --- a/docs/RELEASE_USER.md +++ b/docs/RELEASE_USER.md @@ -23,6 +23,17 @@ # Release Notes Digital Product Pass Application User friendly relase notes without especific technical details. +**November 03 2023 (Version 1.3.0)** +*03.11.2023* + +### Added +#### Added drill down functionality with `IRS` for the Digital Product Pass Aspect +Now the application is able to drill down into its components one level down. +The backend application is communicating with the IRS and managing the job. +Once the IRS completes its job the backend is able to parse it and inform the frontend that the job has completed. + + + **October 31 2023 (Version 1.2.1)** *31.10.2023*