diff --git a/CHANGELOG.md b/CHANGELOG.md index 6608f6fde..9bc7cbbd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Security config changes. - Updated changelog and dependency file. - Dependencies jar versions updated. +- PCF exchange changes for 2408 version. + +### Fixed +- Dependabot bump jar version fixed. +- Trivy high security issue fixed for CVE-2024-34750. ### Fixed - Dependabot bump jar version fixed. diff --git a/DEPENDENCIES b/DEPENDENCIES index ef1538368..3efcfed68 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -148,6 +148,7 @@ maven/mavencentral/org.springframework.cloud/spring-cloud-starter-openfeign/4.1. maven/mavencentral/org.springframework.cloud/spring-cloud-starter/4.1.2, Apache-2.0, approved, clearlydefined maven/mavencentral/org.springframework.data/spring-data-commons/3.2.5, Apache-2.0, approved, #15202 maven/mavencentral/org.springframework.data/spring-data-jpa/3.2.5, Apache-2.0, approved, #15183 +maven/mavencentral/org.springframework.retry/spring-retry/2.0.5, Apache-2.0, approved, clearlydefined maven/mavencentral/org.springframework.security/spring-security-config/6.1.2, Apache-2.0, approved, #9736 maven/mavencentral/org.springframework.security/spring-security-core/6.2.4, Apache-2.0, approved, #11904 maven/mavencentral/org.springframework.security/spring-security-crypto/6.2.4, Apache-2.0 AND ISC, approved, #11908 diff --git a/modules/pcf-exchange/src/main/java/org/eclipse/tractusx/sde/pcfexchange/service/impl/ProxyRequestInterface.java b/modules/pcf-exchange/src/main/java/org/eclipse/tractusx/sde/pcfexchange/service/impl/ProxyRequestInterface.java index 7dd9d5e25..90b33f654 100644 --- a/modules/pcf-exchange/src/main/java/org/eclipse/tractusx/sde/pcfexchange/service/impl/ProxyRequestInterface.java +++ b/modules/pcf-exchange/src/main/java/org/eclipse/tractusx/sde/pcfexchange/service/impl/ProxyRequestInterface.java @@ -100,7 +100,7 @@ public void requestToProviderForPCFValue(String productId, StringBuilder reponse reponseMap.append(errorMsg); } } catch (FeignException e) { - log.error(LogUtil.encode("FeignRequest requestToProviderForPCFValue:" + e.request())); + log.error("FeignRequest requestToProviderForPCFValue:" + e.request()); String error= StringUtils.isBlank(e.contentUTF8()) ? e.getMessage() : e.contentUTF8(); String errorMsg= "Unable to request to provider '"+ dataset.getConnectorOfferUrl()+"' for '"+productId+"' product PCF value beacuse error in remote service execution"; log.error(LogUtil.encode("FeignException requestToProviderForPCFValue: " + errorMsg + ", because: " +error)); diff --git a/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/configuration/properties/PCFAssetStaticPropertyHolder.java b/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/configuration/properties/PCFAssetStaticPropertyHolder.java index 9a9f2a338..f12f910ee 100644 --- a/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/configuration/properties/PCFAssetStaticPropertyHolder.java +++ b/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/configuration/properties/PCFAssetStaticPropertyHolder.java @@ -24,21 +24,39 @@ import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; +import lombok.Getter; + +import java.util.List; + @Component @Configuration +@Getter public class PCFAssetStaticPropertyHolder { @Value(value = "${digital-twin.pcf.sematicid:}") public String sematicId; - @Value(value = "${digital-twin.pcf.sematicid:}") + @Value(value = "${digital-twin.pcf.sematicid-part:}") public String sematicIdPart; + + @Value("${edc.asset.prop.type.pcfexchange.value:PcfExchange}") + private String assetPropTypePCFExchangeType; + + @Value("${edc.policy.pcf.access:tx:BusinessPartnerGroup@odrl:eq@pcf-business-partner-group;Membership@active}") + private String pcfExchangeAccessPolicy; - private String pcfExchangeAssetId; + @Value("#{'${edc.policy.pcf.bpn:}'.split(',')}") + private List whiteListBusinessList; + private static String PCF_BG = "pcf-business-partner-group"; + + @Value("${edc.policy.pcf.usage:FrameworkAgreement@DataExchangeGovernance:1.0;Membership@active;UsagePurpose@cx.pcf.base:1}") + private String pcfExchangeUsagePolicy; + private String pcfExchangeAssetId; + public String getSematicId() { if (StringUtils.isAllBlank(sematicId)) - sematicId = "urn:samm:io.catenax.pcf:6.0.0#Pcf"; + sematicId = "urn:samm:io.catenax.pcf:7.0.0#Pcf"; return sematicId; } @@ -63,5 +81,9 @@ public String getPcfExchangeAssetId() { public void setPcfExchangeAssetId(String pcfExchangeAssetId) { this.pcfExchangeAssetId = pcfExchangeAssetId; } + + public String getPcfBusinessPartnerGroup() { + return PCF_BG; + } } diff --git a/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/entities/Policies.java b/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/entities/Policies.java index f4f9e532e..b8275ece4 100644 --- a/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/entities/Policies.java +++ b/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/entities/Policies.java @@ -39,6 +39,7 @@ public class Policies { private String technicalKey; + private String operator; private List value; } diff --git a/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/utils/PolicyOperationUtil.java b/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/utils/PolicyOperationUtil.java index 5232b3366..530caa873 100644 --- a/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/utils/PolicyOperationUtil.java +++ b/modules/sde-common/src/main/java/org/eclipse/tractusx/sde/common/utils/PolicyOperationUtil.java @@ -33,7 +33,7 @@ public class PolicyOperationUtil { private PolicyOperationUtil() { } - private static List getBPNList(List policies) { + public static List getBPNList(List policies) { return policies.stream().filter(e -> e.getTechnicalKey().equals(BUSINESS_PARTNER_NUMBER)) .flatMap(e -> e.getValue().stream().filter(StringUtils::isNotBlank)).toList(); } @@ -54,7 +54,12 @@ public static List getStringPolicyAsPolicyList(String policyStr){ String[] split = policyStr.split(";"); for (int i = 0; i < split.length; i++) { String[] split1 = split[i].split("@"); - if (split1.length == 2) { + + if (split1.length == 3) { + policies.add(Policies.builder().technicalKey(split1[0]).operator(split1[1]).value(List.of(split1[2])).build()); + } + + else if (split1.length == 2) { policies.add(Policies.builder().technicalKey(split1[0]).value(List.of(split1[1])).build()); } } diff --git a/modules/sde-core/pom.xml b/modules/sde-core/pom.xml index 10273ec8a..9cda47569 100644 --- a/modules/sde-core/pom.xml +++ b/modules/sde-core/pom.xml @@ -60,6 +60,10 @@ commons-codec commons-codec + + org.springframework.retry + spring-retry + commons-io commons-io @@ -187,13 +191,13 @@ pcf 0.0.1 - + org.eclipse.tractusx pcf-exchange 0.0.1 - + com.opencsv opencsv @@ -222,6 +226,7 @@ spring-security-test test + diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/SdeApplication.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/SdeApplication.java index 513e1891e..b6142462c 100644 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/SdeApplication.java +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/SdeApplication.java @@ -29,6 +29,7 @@ import org.springframework.cache.annotation.EnableCaching; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignAutoConfiguration; +import org.springframework.retry.annotation.EnableRetry; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @@ -36,6 +37,7 @@ @SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class}) @EnableFeignClients @EnableAsync +@EnableRetry @ImportAutoConfiguration({FeignAutoConfiguration.class}) @EnableCaching @EnableScheduling diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/BPDMExchangeAssetConsumer.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/BPDMExchangeAssetConsumer.java new file mode 100644 index 000000000..b3c520b57 --- /dev/null +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/BPDMExchangeAssetConsumer.java @@ -0,0 +1,55 @@ +/******************************************************************************** + * Copyright (c) 2023,2024 T-Systems International GmbH + * Copyright (c) 2023,2024 Contributors to the Eclipse Foundation + * + * 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 governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +package org.eclipse.tractusx.sde.configuration; + +import java.util.List; + +import org.eclipse.tractusx.sde.core.service.PartnerPoolService; +import org.eclipse.tractusx.sde.portal.model.response.LegalEntityResponse; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Configuration +@RequiredArgsConstructor +@Profile("default") +public class BPDMExchangeAssetConsumer { + + private final PartnerPoolService partnerPoolService; + + @PostConstruct + @SneakyThrows + public void init() { + try { + List legalEntitiesResponse = partnerPoolService.fetchLegalEntitiesData(null, "test", 0, + 10); + log.info("BPDM service ready to use, 'test' company found leagal entity =>" + legalEntitiesResponse.size()); + } catch (Exception e) { + log.error("Unable to perform auto negotiation for BPDM service for legal entiry search"); + } + } + +} \ No newline at end of file diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/PCFExchangeAssetProvider.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/PCFExchangeAssetProvider.java index f4058fca4..8c8e46197 100644 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/PCFExchangeAssetProvider.java +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/configuration/PCFExchangeAssetProvider.java @@ -31,7 +31,6 @@ import org.eclipse.tractusx.sde.common.utils.PolicyOperationUtil; import org.eclipse.tractusx.sde.common.utils.UUIdGenerator; import org.eclipse.tractusx.sde.core.utils.ValueReplacerUtility; -import org.eclipse.tractusx.sde.edc.constants.EDCAssetConfigurableConstant; import org.eclipse.tractusx.sde.edc.constants.EDCAssetConstant; import org.eclipse.tractusx.sde.edc.entities.request.asset.AssetEntryRequest; import org.eclipse.tractusx.sde.edc.entities.request.asset.AssetEntryRequestFactory; @@ -61,7 +60,6 @@ public class PCFExchangeAssetProvider { private final CreateEDCAssetFacilator createEDCAssetFacilator; private final ValueReplacerUtility valueReplacerUtility; private final SDEConfigurationProperties sdeConfigurationProperties; - private final EDCAssetConfigurableConstant edcAssetConfigurableConstant; private final PCFAssetStaticPropertyHolder pcfAssetStaticPropertyHolder; @PostConstruct @@ -70,7 +68,7 @@ public void init() { String assetId = UUIdGenerator.getUuid(); AssetEntryRequest assetEntryRequest = assetFactory.getAssetRequest("", "PCF Exchange endpoint information", - assetId, "1", "", "", pcfAssetStaticPropertyHolder.getSematicId(), edcAssetConfigurableConstant.getAssetPropTypePCFExchangeType()); + assetId, "1", "", "", pcfAssetStaticPropertyHolder.getSematicId(), pcfAssetStaticPropertyHolder.getAssetPropTypePCFExchangeType()); String baseUrl = sdeConfigurationProperties.getSdeHostname() + "/pcf"; assetEntryRequest.getDataAddress().getProperties().put("baseUrl", baseUrl); @@ -81,7 +79,7 @@ public void init() { Map inputData = new HashMap<>(); inputData.put("baseUrl", baseUrl); inputData.put(REGISTRY_TYPE, REGISTRY_TYPE); - inputData.put("assetType", edcAssetConfigurableConstant.getAssetPropTypePCFExchangeType()); + inputData.put("assetType", pcfAssetStaticPropertyHolder.getAssetPropTypePCFExchangeType()); ObjectNode requestBody = (ObjectNode) new ObjectMapper().readTree(valueReplacerUtility .valueReplacerUsingFileTemplate("/edc_request_template/edc_asset_lookup.json", inputData)); @@ -91,12 +89,19 @@ public void init() { if (assetExistsLookupBasedOnTypeGetAsAsset == null || assetExistsLookupBasedOnTypeGetAsAsset.isNull() || (assetExistsLookupBasedOnTypeGetAsAsset.isArray() && assetExistsLookupBasedOnTypeGetAsAsset.isEmpty())) { - + + List pcfBPNList = pcfAssetStaticPropertyHolder.getWhiteListBusinessList(); + + //iterate over pcfBPNList and create business partner group + for (String pcfBPN : pcfBPNList) { + edcGateway.addBPNintoPCFBusinessPartnerGroup(pcfBPN, pcfAssetStaticPropertyHolder.getPcfBusinessPartnerGroup()); + } + List accessPolicy = PolicyOperationUtil - .getStringPolicyAsPolicyList(edcAssetConfigurableConstant.getPcfExcahngeAccessPolicy()); + .getStringPolicyAsPolicyList(pcfAssetStaticPropertyHolder.getPcfExchangeAccessPolicy()); List usagePolicy = PolicyOperationUtil - .getStringPolicyAsPolicyList(edcAssetConfigurableConstant.getPcfExcahngeUsagePolicy()); + .getStringPolicyAsPolicyList(pcfAssetStaticPropertyHolder.getPcfExchangeUsagePolicy()); PolicyModel policy= PolicyModel.builder() .accessPolicies(accessPolicy) diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/properties/SdeCommonProperties.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/properties/SdeCommonProperties.java deleted file mode 100644 index 4478ed7c9..000000000 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/properties/SdeCommonProperties.java +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2024 T-Systems International GmbH - * Copyright (c) 2024 Contributors to the Eclipse Foundation - * - * 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 governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ -package org.eclipse.tractusx.sde.core.properties; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Configuration -@RequiredArgsConstructor -@Getter -public class SdeCommonProperties { - - //DigitalTwin properties - @Value("${digital-twins.hostname:default}") - private String digitalTwinRegistry; - - @Value("${digital-twins.managed.thirdparty:false}") - private boolean dDTRManagedThirdparty; - - @Value("${digital-twins.registry.uri:/api/v3.0}") - private String digitalTwinRegistryURI; - - @Value("${digital-twins.registry.lookup.uri:/api/v3.0}") - private String digitalTwinRegistryLookUpURI; - - @Value("${digital-twins.authentication.url:default}") - private String digitalTwinTokenUrl; - - @Value("${digital-twins.authentication.clientId:default}") - private String digitalTwinClientId; - - @Value("${digital-twins.authentication.clientSecret:default}") - private String digitalTwinClientSecret; - - @Value("${digital-twins.authentication.scope:}") - private String digitalTwinAuthenticationScope; - - //manufacturer Id properties - @Value(value = "${manufacturerId}") - private String manufacturerId; -} \ No newline at end of file diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/registry/SubmodelRegistration.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/registry/SubmodelRegistration.java index 08042f46b..d48f8de72 100644 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/registry/SubmodelRegistration.java +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/registry/SubmodelRegistration.java @@ -51,9 +51,9 @@ public SubmodelRegistration(SubmodelCustomHistoryGenerator submodelCustomHistory } @SneakyThrows - public void register(SubmodelExtension subomdelService) { - Submodel submodel = subomdelService.submodel(); - log.info(submodel.toString()); + public void register(SubmodelExtension submodelService) { + Submodel submodel = submodelService.submodel(); + log.debug(submodel.toString()); List columns = submoduleUtility.getTableColomnHeader(submodel); @@ -74,7 +74,7 @@ public void register(SubmodelExtension subomdelService) { submodelCustomHistoryGenerator.checkTableIfNotExistCreate(submodel.getSchema(), columns, tableName, pkCol, databaseIdentifierCols); } - + log.info(submodel.getSchema().get("id") + " sub model registered successfully"); submodelList.add(submodel); } diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/ConsumerService.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/ConsumerService.java index e6ab9c20d..b55672b63 100644 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/ConsumerService.java +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/ConsumerService.java @@ -133,7 +133,7 @@ public Map subscribeAndDownloadDataOffers(ConsumerRequest consum // Save consumer Download history in DB consumerDownloadHistoryRepository.save(entity); - ActionRequest action = policyConstraintBuilderService + List action = policyConstraintBuilderService .getUsagePoliciesConstraints(consumerRequest.getUsagePolicies()); entry.getValue().parallelStream().forEach(offer -> { diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/PartnerPoolService.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/PartnerPoolService.java index f07f05d7a..490509702 100644 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/PartnerPoolService.java +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/service/PartnerPoolService.java @@ -20,6 +20,7 @@ package org.eclipse.tractusx.sde.core.service; +import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -91,8 +92,9 @@ private LegalEntityData fetchLegalEntityDataByEdrToken(String bpnLs, String lega Map header = new HashMap<>(); header.put("authorization", edrToken.getAuthorization()); - - legalEntityData = partnerPoolExternalServiceApi.fetchLegalEntityData(bpnLs, legalName, page, size, header); + URI endpoint = new URI(edrToken.getEndpoint()); + + legalEntityData = partnerPoolExternalServiceApi.fetchLegalEntityData(endpoint, bpnLs, legalName, page, size, header); } catch (FeignException e) { String err = e.contentUTF8(); diff --git a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/submodel/executor/step/DigitalTwinUseCaseHandler.java b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/submodel/executor/step/DigitalTwinUseCaseHandler.java index 4460a58f6..ae1220070 100644 --- a/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/submodel/executor/step/DigitalTwinUseCaseHandler.java +++ b/modules/sde-core/src/main/java/org/eclipse/tractusx/sde/core/submodel/executor/step/DigitalTwinUseCaseHandler.java @@ -173,7 +173,7 @@ private String createShell(Map specificAssetIds, ShellDescriptor public JsonNode checkAndCreateSubmodulIfNotExist(Integer rowIndex, ObjectNode jsonObject, String shellId, ShellDescriptorRequest aasDescriptorRequest, SubModelResponse foundSubmodel) { - Map identification = findIdentificationForSubmodule(rowIndex, jsonObject); + Map identification = findIdentificationForSubmodule(rowIndex, jsonObject, foundSubmodel); String path = getUriPathOfSubmodule(); String submodelDataPlaneUrl = getDataPlaneUrlOfSubmodule(); @@ -275,7 +275,7 @@ private SubModelResponse findSubmoduleInShells(ObjectNode jsonObject, List findIdentificationForSubmodule(Integer rowIndex, ObjectNode jsonObject) { + private Map findIdentificationForSubmodule(Integer rowIndex, ObjectNode jsonObject, SubModelResponse foundSubmodel) { String submodelIdentifier =null; String identificationField = extractExactFieldName(getIdentifierOfModel()); @@ -306,7 +306,10 @@ private Map findIdentificationForSubmodule(Integer rowIndex, Obj } } } - + + if(foundSubmodel != null) + submodelIdentifier = foundSubmodel.getId(); + if(submodelIdentifier == null) { submodelIdentifier = UUIdGenerator.getUrnUuid(); } diff --git a/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/PostgreSQLInitializer.java b/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/PostgreSQLInitializer.java index 0dd060a7a..e30dac6c9 100644 --- a/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/PostgreSQLInitializer.java +++ b/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/PostgreSQLInitializer.java @@ -45,4 +45,4 @@ public void initialize(ConfigurableApplicationContext applicationContext) { "spring.datasource.password="+postgres.getPassword() ).applyTo(applicationContext); } -} \ No newline at end of file +} diff --git a/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/controllers/PcfExchangeControllerTest.java b/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/controllers/PcfExchangeControllerTest.java index 61c9fcd25..fb60fa647 100644 --- a/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/controllers/PcfExchangeControllerTest.java +++ b/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/controllers/PcfExchangeControllerTest.java @@ -298,4 +298,4 @@ private String getPCFJsonResponse() { return bodyRequest; } -} \ No newline at end of file +} diff --git a/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/service/ConsumerControlPanelServiceTest.java b/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/service/ConsumerControlPanelServiceTest.java index d7175281e..d2907f366 100644 --- a/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/service/ConsumerControlPanelServiceTest.java +++ b/modules/sde-core/src/test/java/org/eclipse/tractusx/sde/service/ConsumerControlPanelServiceTest.java @@ -31,17 +31,13 @@ import java.util.Set; import java.util.UUID; +import org.eclipse.tractusx.sde.EnablePostgreSQL; import org.eclipse.tractusx.sde.bpndiscovery.handler.BpnDiscoveryProxyService; -import org.eclipse.tractusx.sde.bpndiscovery.model.response.BpnDiscoveryResponse; import org.eclipse.tractusx.sde.bpndiscovery.model.response.BpnDiscoverySearchResponse; import org.eclipse.tractusx.sde.common.entities.Policies; import org.eclipse.tractusx.sde.common.utils.TokenUtility; import org.eclipse.tractusx.sde.core.service.ConsumerService; import org.eclipse.tractusx.sde.edc.api.ContractOfferCatalogApi; -import org.eclipse.tractusx.sde.edc.entities.request.policies.ActionRequest; -import org.eclipse.tractusx.sde.edc.entities.request.policies.ConstraintRequest; -import org.eclipse.tractusx.sde.edc.entities.request.policies.Operator; -import org.eclipse.tractusx.sde.edc.entities.request.policies.PolicyConstraintBuilderService; import org.eclipse.tractusx.sde.edc.facilitator.ContractNegotiateManagementHelper; import org.eclipse.tractusx.sde.edc.facilitator.EDRRequestHelper; import org.eclipse.tractusx.sde.edc.gateways.database.ContractNegotiationInfoRepository; @@ -56,21 +52,30 @@ import org.eclipse.tractusx.sde.edc.util.EDCAssetUrlCacheService; import org.eclipse.tractusx.sde.portal.api.IPartnerPoolExternalServiceApi; import org.eclipse.tractusx.sde.portal.api.IPortalExternalServiceApi; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -@ContextConfiguration(classes = { ConsumerControlPanelService.class, String.class }) -@ExtendWith(SpringExtension.class) +import lombok.extern.slf4j.Slf4j; + +//@ContextConfiguration(classes = { ConsumerControlPanelService.class, String.class, PolicyConstraintBuilderService.class }) +//@ExtendWith(SpringExtension.class) +@Slf4j +@EnablePostgreSQL +@SpringBootTest +@Execution(ExecutionMode.SAME_THREAD) +@WithMockUser(username = "Admin", authorities = { "Admin" }) +@ActiveProfiles("test") class ConsumerControlPanelServiceTest { @MockBean @@ -93,13 +98,10 @@ class ConsumerControlPanelServiceTest { @Autowired private ConsumerControlPanelService consumerControlPanelService; - + @MockBean private ContractOfferCatalogApi contractOfferCatalogApi; - @MockBean - private PolicyConstraintBuilderService policyConstraintBuilderService; - @MockBean private ContractOfferRequestFactory contractOfferRequestFactory; @@ -121,28 +123,16 @@ class ConsumerControlPanelServiceTest { @MockBean private LookUpDTTwin lookUpDTTwin; + @MockBean + private BpnDiscoverySearchResponse bpnDiscoverySearchResponse; - @BeforeEach - public void setup() { - when(bpnDiscoveryProxyService.bpnDiscoverySearchData(any())) - .thenReturn(BpnDiscoverySearchResponse.builder() - .bpns(List.of(BpnDiscoveryResponse.builder() - .value("fooo") - .build())) - .build()); - - when(eDCAssetUrlCacheService.getDDTRUrl(any())) - .thenReturn(List.of(QueryDataOfferModel.builder() - .assetId("foo") - .connectorId("test") - .offerId("offer") - .build())); - when(eDCAssetUrlCacheService.verifyAndGetToken(any(),any())).thenReturn(any()); - } - - @Test + + @Test void testQueryOnDataOfferEmpty() throws Exception { - + BpnDiscoverySearchResponse build = BpnDiscoverySearchResponse.builder() + .bpns(List.of()) + .build(); + when(bpnDiscoveryProxyService.bpnDiscoverySearchData(any())).thenReturn(build); Set queryOnDataOffers = consumerControlPanelService.queryOnDataOffers("example", "", "", 0, 0); @@ -159,24 +149,37 @@ void testQueryOnDataOffersWithUsagePolicies() throws Exception { verify(contractOfferCatalogApi).getContractOffersCatalog((JsonNode) any()); } - //@Test + @Test void testSubscribeDataOffers1() { ArrayList offerRequestList = new ArrayList<>(); List usagePolicies = new ArrayList<>(); - Policies usagePolicy = Policies.builder().technicalKey("BusinessPartnerNumber").value(List.of("BPN123456789")) + Policies usagePolicy = Policies.builder() + .technicalKey("BusinessPartnerNumber") + .value(List.of("BPN123456789")) .build(); + usagePolicies.add(usagePolicy); + + Policies usagePolicy1 = Policies.builder() + .technicalKey("A") + .value(List.of("A")) + .build(); + + usagePolicies.add(usagePolicy1); + + Policies usagePolicy2 = Policies.builder() + .technicalKey("B") + .value(List.of("B")) + .build(); + usagePolicies.add(usagePolicy2); + ConsumerRequest consumerRequest = new ConsumerRequest(offerRequestList, usagePolicies, "csv"); String processId = UUID.randomUUID().toString(); + consumerControlPanelService.subscribeDataOffers(consumerRequest, processId); - List policies = consumerRequest.getUsagePolicies(); - ActionRequest list = ActionRequest.builder().build(); - ConstraintRequest constraintRequest = ConstraintRequest.builder().leftOperand("A").rightOperand("A") - .operator(Operator.builder().id("odrl:eq").build()).build(); - list.addProperty("odrl:and", constraintRequest); - when(policyConstraintBuilderService.getUsagePoliciesConstraints(List.of())).thenReturn(list); - assertEquals(usagePolicies, policies); + + assertEquals(usagePolicies, usagePolicies); } private JsonNode getCatalogResponse() throws JsonProcessingException, JsonMappingException { @@ -198,7 +201,7 @@ private JsonNode getCatalogResponse() throws JsonProcessingException, JsonMappin }, "odrl:constraint": { "odrl:or": { - "odrl:leftOperand": "BusinessPartnerNumber", + "odrl:leftOperand": {"@id","BusinessPartnerNumber"}, "odrl:operator": {"@id": "odrl:eq"}, "odrl:rightOperand": "BPNL001000TS0100" } diff --git a/modules/sde-core/src/test/resources/application-test.properties b/modules/sde-core/src/test/resources/application-test.properties index ca540bb7f..d64599020 100644 --- a/modules/sde-core/src/test/resources/application-test.properties +++ b/modules/sde-core/src/test/resources/application-test.properties @@ -98,9 +98,8 @@ partner.pool.clientSecret=test partner.pool.grantType=client_credentials -bpdm.provider.edc.dataspace.api=test +bpdm.provider.edc.dsp.api=test bpdm.provider.bpnl=test -bpdm.provider.edc.public.api=test ## Portal backend and Connector discovery @@ -120,18 +119,6 @@ discovery.grantType=client_credentials springdoc.api-docs.path=/api-docs springdoc.swagger-ui.oauth.client-id=test -## Notification Email server info -mail.smtp.username=test -mail.smtp.password=test -mail.smtp.host=test -mail.smtp.port=587 -mail.from.address=test -mail.to.address=test -mail.cc.address=test -mail.replyto.address=test -mail.smtp.starttls.enable=true -mail.smtp.auth=true - # policy-hub config policy.hub.hostname=test policy.hub.authentication.url=test diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java index 59083f948..136e8f048 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/api/EDCFeignClientApi.java @@ -21,6 +21,7 @@ package org.eclipse.tractusx.sde.edc.api; import org.eclipse.tractusx.sde.edc.entities.request.asset.AssetEntryRequest; +import org.eclipse.tractusx.sde.edc.entities.request.businesspartnergroup.BusinessPartnerGroupRequest; import org.eclipse.tractusx.sde.edc.entities.request.contractdefinition.ContractDefinitionRequest; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.ResponseEntity; @@ -56,6 +57,9 @@ public interface EDCFeignClientApi { //Policy & Contract + @GetMapping("${edc.managementpath.apiversion:/v2}/policydefinitions/{id}") + public JsonNode getPolicy(@PathVariable("id") String policyId); + @PostMapping("${edc.managementpath.apiversion:/v2}/policydefinitions") public JsonNode createPolicy(@RequestBody JsonNode requestBody); @@ -70,7 +74,6 @@ public interface EDCFeignClientApi { @PutMapping("${edc.managementpath.apiversion:/v2}/contractdefinitions") public void updateContractDefination(@RequestBody ContractDefinitionRequest requestBody); - @GetMapping("${edc.managementpath.apiversion:/v2}/contractdefinitions/{id}") public JsonNode getContractDefination(@PathVariable("id") String id); @@ -81,4 +84,18 @@ public interface EDCFeignClientApi { @DeleteMapping(path = "${edc.managementpath.apiversion:/v2}/policydefinitions/{id}") public ResponseEntity deletePolicyDefinitions(@PathVariable("id") String policydefinitionsId); + + //Business Partner Group + @GetMapping("/business-partner-groups/{bpn}") + public JsonNode getBusinessPartnerGroups(@PathVariable("bpn") String bpn); + + @PutMapping("/business-partner-groups") + public void updateBusinessPartnerGroups(@RequestBody BusinessPartnerGroupRequest requestBody); + + @PostMapping("/business-partner-groups") + public void createBusinessPartnerGroups(@RequestBody BusinessPartnerGroupRequest requestBody); + + @DeleteMapping("/business-partner-groups/{bpn}") + public void deleteBusinessPartnerGroups(@PathVariable("bpn") String bpn); + } \ No newline at end of file diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/constants/EDCAssetConfigurableConstant.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/constants/EDCAssetConfigurableConstant.java index a55bd4dff..2ce817870 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/constants/EDCAssetConfigurableConstant.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/constants/EDCAssetConfigurableConstant.java @@ -46,9 +46,6 @@ public class EDCAssetConfigurableConstant { @Value("${edc.asset.prop.type.digital-twin.value:DigitalTwinRegistry}") private String assetPropTypeDigitalTwin; - @Value("${edc.asset.prop.type.pcfexchange.value:PcfExchange}") - private String assetPropTypePCFExchangeType; - @Value("${edc.policy.prefix:cx-policy:}") private String cxPolicyPrefix; @@ -58,12 +55,6 @@ public class EDCAssetConfigurableConstant { @Value("${edc.policy.pcf.auto-applied:false}") private boolean autoApplyPCFEDCPolicy; - @Value("${edc.policy.pcf.access:Membership@active}") - private String pcfExcahngeAccessPolicy; - - @Value("${edc.policy.pcf.usage:FrameworkAgreement@Pcf:1.0;Membership@active;UsagePurpose@cx.pcf.base:1}") - private String pcfExcahngeUsagePolicy; - @Value("${edc.policy.digital-twin.access:Membership@active}") private String digitalTwinExchangeAccessPolicy; @@ -73,12 +64,9 @@ public class EDCAssetConfigurableConstant { @Value("#{'${edc.bpdm.asset.search.criteria:https://purl.org/dc/terms/subject@cx-taxo:ReadAccessPoolForCatenaXMember;https://w3id.org/catenax/ontology/common/version@6.0}'.split(';')}") private List edcBPDMSearchCriteria; - @Value("${bpdm.provider.edc.dataspace.api}") + @Value("${bpdm.provider.edc.dsp.api}") private String bpdmProviderEdcDataspaceApi; - @Value("${bpdm.provider.edc.public.api}") - private String bpdmProviderEdcPublicApi; - @Value("${bpdm.provider.bpnl}") private String bpdmProviderBpnl; diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/accesspolicy/AccessPolicyDTO.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/businesspartnergroup/BusinessPartnerGroupRequest.java similarity index 53% rename from modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/accesspolicy/AccessPolicyDTO.java rename to modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/businesspartnergroup/BusinessPartnerGroupRequest.java index a7d2c923e..1a8d1b3b8 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/accesspolicy/AccessPolicyDTO.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/businesspartnergroup/BusinessPartnerGroupRequest.java @@ -1,6 +1,6 @@ /******************************************************************************** - * Copyright (c) 2022, 2023 T-Systems International GmbH - * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation + * Copyright (c) 2024 T-Systems International GmbH + * Copyright (c) 2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -18,31 +18,41 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -package org.eclipse.tractusx.sde.edc.entities.request.policies.accesspolicy; +package org.eclipse.tractusx.sde.edc.entities.request.businesspartnergroup; -import org.eclipse.tractusx.sde.edc.entities.request.policies.ConstraintRequest; -import org.eclipse.tractusx.sde.edc.entities.request.policies.Operator; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.SneakyThrows; @Data -@AllArgsConstructor @NoArgsConstructor +@AllArgsConstructor @Builder -public class AccessPolicyDTO { - - Object bpnNumber; - - public ConstraintRequest toConstraint() { +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BusinessPartnerGroupRequest { + + @JsonProperty("@context") + @Builder.Default + private Map context = Map.of("tx", "https://w3id.org/tractusx/v0.0.1/ns/"); - String operator = "odrl:eq"; - return ConstraintRequest.builder() - .leftOperand("BusinessPartnerNumber") - .operator(Operator.builder().id(operator).build()) - .rightOperand(bpnNumber) - .build(); + @JsonProperty("@id") + private String id; + + @JsonProperty("tx:groups") + private List groups; + + @SneakyThrows + public String toJsonString() { + final ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(this); } -} +} \ No newline at end of file diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/contractdefinition/ContractDefinitionRequestFactory.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/contractdefinition/ContractDefinitionRequestFactory.java index c5cf36ae0..8f7d99a50 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/contractdefinition/ContractDefinitionRequestFactory.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/contractdefinition/ContractDefinitionRequestFactory.java @@ -29,7 +29,7 @@ @Service public class ContractDefinitionRequestFactory { - public ContractDefinitionRequest getContractDefinitionRequest(String uuid, String accessPolicyId, + public ContractDefinitionRequest getContractDefinitionRequest(String uuid, String assetId, String accessPolicyId, String usagePolicyId) { String submodelId = uuid; @@ -42,7 +42,7 @@ public ContractDefinitionRequest getContractDefinitionRequest(String uuid, Strin criteria.add(Criterion.builder() .operandLeft("https://w3id.org/edc/v0.0.1/ns/id") .operator("=") - .operandRight(uuid) + .operandRight(assetId) .build()); return ContractDefinitionRequest.builder() diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/ConstraintRequest.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/ConstraintRequest.java index 415a19cc4..4b0133841 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/ConstraintRequest.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/ConstraintRequest.java @@ -42,13 +42,13 @@ public class ConstraintRequest { private String type = "Constraint"; @JsonProperty("odrl:leftOperand") - private String leftOperand; + private LinkJsonLDId leftOperand; @JsonProperty("odrl:rightOperand") private Object rightOperand; @JsonProperty("odrl:operator") - private Operator operator; + private LinkJsonLDId operator; @SneakyThrows public String toJsonString() { diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/Operator.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/LinkJsonLDId.java similarity index 98% rename from modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/Operator.java rename to modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/LinkJsonLDId.java index 231e78cb9..128a6a88f 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/Operator.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/LinkJsonLDId.java @@ -33,7 +33,7 @@ @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) -public class Operator { +public class LinkJsonLDId { @JsonProperty("@id") private String id; diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PermissionRequest.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PermissionRequest.java index e6ab481d1..74250dd08 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PermissionRequest.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PermissionRequest.java @@ -44,8 +44,7 @@ public class PermissionRequest { // private String target; @JsonProperty("odrl:action") - @Builder.Default - private Map action = Map.of("odrl:type", "USE"); + private LinkJsonLDId action; @JsonProperty("odrl:constraint") private Map constraint; diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyConstraintBuilderService.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyConstraintBuilderService.java index b733fd2d3..326b4087c 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyConstraintBuilderService.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyConstraintBuilderService.java @@ -40,6 +40,10 @@ @RequiredArgsConstructor public class PolicyConstraintBuilderService { + private static final String U = "u"; + + private static final String A = "a"; + private final PolicyRequestFactory policyRequestFactory; private final JsonObjectMapper jsonobjectMapper; @@ -49,23 +53,23 @@ public class PolicyConstraintBuilderService { private final SDEConfigurationProperties sdeConfigurationProperties; // private final IPolicyHubProxyService policyHubProxyService; - +// // public JsonNode getAccessPolicy(String assetId, PolicyModel policy) { // -// return policyRequestFactory.setPolicyIdAndGetObject(assetId, +// return jsonobjectMapper.objectToJsonNode(policyRequestFactory.setPolicyIdAndGetObject(assetId, // policyHubProxyService.getPolicyContent( -// mapPolicy(PolicyTypeIdEnum.ACCESS, ConstraintOperandIdEnum.OR, policy.getAccessPolicies(), "a")).get("content"), -// "a"); +// mapPolicy(PolicyTypeIdEnum.ACCESS, ConstraintOperandIdEnum.OR, policy.getAccessPolicies(), "a")), +// "a")); // } // // public JsonNode getUsagePolicy(String assetId, PolicyModel policy) { // -// return policyRequestFactory.setPolicyIdAndGetObject(assetId, +// return jsonobjectMapper.objectToJsonNode(policyRequestFactory.setPolicyIdAndGetObject(assetId, // policyHubProxyService.getPolicyContent( -// mapPolicy(PolicyTypeIdEnum.USAGE, ConstraintOperandIdEnum.AND, policy.getUsagePolicies(), "u")).get("content"), -// "u"); +// mapPolicy(PolicyTypeIdEnum.USAGE, ConstraintOperandIdEnum.AND, policy.getUsagePolicies(), "u")), +// "u")); // } - +// // private PolicyContentRequest mapPolicy(PolicyTypeIdEnum policyType, ConstraintOperandIdEnum constraintOperandId, // List policies, String type) { // @@ -74,8 +78,8 @@ public class PolicyConstraintBuilderService { // // List valueList = policy.getValue(); // -// if (type.equals("a")) -// valueList = getAndOwnerBPNIfNotExist(policy, valueList); +// //if (type.equals("a")) +// // valueList = getAndOwnerBPNIfNotExist(policy, valueList); // // OperatorIdEnum operator = OperatorIdEnum.EQUALS; // @@ -102,75 +106,93 @@ public class PolicyConstraintBuilderService { // .build(); // } - public JsonNode getAccessPolicy(String assetId, PolicyModel policy) { - return jsonobjectMapper.objectToJsonNode(policyRequestFactory.getPolicy(assetId, - getPoliciesConstraints(policy.getAccessPolicies(), "odrl:or", "a"), "a")); + public JsonNode getAccessPolicy(String policyId, String assetId, PolicyModel policy) { + return jsonobjectMapper.objectToJsonNode( + policyRequestFactory.getPolicy(policyId, assetId, getPoliciesConstraints(policy.getAccessPolicies(), A), A)); } - public JsonNode getUsagePolicy(String assetId, PolicyModel policy) { - return jsonobjectMapper.objectToJsonNode(policyRequestFactory.getPolicy(assetId, - getPoliciesConstraints(policy.getUsagePolicies(), "odrl:and", "u"), "u")); + public JsonNode getUsagePolicy( String policyId, String assetId, PolicyModel policy) { + return jsonobjectMapper.objectToJsonNode( + policyRequestFactory.getPolicy(policyId, assetId, getPoliciesConstraints(policy.getUsagePolicies(), U), U)); } - public ActionRequest getUsagePoliciesConstraints(List policies) { - return getPoliciesConstraints(policies, "odrl:and", "u"); + public List getUsagePoliciesConstraints(List policies) { + return getPoliciesConstraints(policies, U); } - public ActionRequest getPoliciesConstraints(List usagePolicies, String operator, String type) { + public List getPoliciesConstraints(List policies, String type) { + List constraintList = new ArrayList<>(); - if (usagePolicies != null && !usagePolicies.isEmpty()) { - usagePolicies.forEach(policy -> preparePolicyConstraint(constraintList, policy, type)); - } + List bpnConstraintList = new ArrayList<>(); - constraintList.sort(Comparator.comparing(ConstraintRequest::getLeftOperand)); + if (policies != null && !policies.isEmpty()) { + policies.forEach(policy -> { + if (type.equals(A) + && policy.getTechnicalKey().equals(edcAssetConfigurableConstant.getBpnNumberTechnicalKey())) { + preparePolicyConstraint(bpnConstraintList, policy, getAndOwnerBPNIfNotExist(policy.getValue())); + } else { + preparePolicyConstraint(constraintList, policy, policy.getValue()); + } + }); + } + List actionList = new ArrayList<>(); if (!constraintList.isEmpty()) { - ActionRequest action = ActionRequest.builder().build(); - action.addProperty("@type", "LogicalConstraint"); - action.addProperty(operator, constraintList); - return action; + actionList.add(prepareActionRequest("odrl:and", constraintList)); } - return null; - } + if (!bpnConstraintList.isEmpty()) { + actionList.add(prepareActionRequest("odrl:or", bpnConstraintList)); + } - private void preparePolicyConstraint(List policies, Policies policy, String type) { + return actionList; - String operator = "odrl:eq"; + } + + private ActionRequest prepareActionRequest(String operator, List constraintList) { + constraintList.sort(Comparator.comparing(a -> a.getLeftOperand().getId())); + ActionRequest action = ActionRequest.builder().build(); + action.addProperty("@type", "LogicalConstraint"); + action.addProperty(operator, constraintList); + return action; + } - List values = policy.getValue(); + private void preparePolicyConstraint(List policies, Policies policy, List values) { - if (type.equals("a")) - values = getAndOwnerBPNIfNotExist(policy, values); + String operator = "odrl:eq"; for (String value : values) { + if (StringUtils.isNotBlank(value)) { String policyPrefix = ""; - if (!policy.getTechnicalKey().startsWith(edcAssetConfigurableConstant.getCxPolicyPrefix())) { + if (!policy.getTechnicalKey().startsWith(edcAssetConfigurableConstant.getCxPolicyPrefix()) + && !policy.getTechnicalKey().contains(":")) { policyPrefix = edcAssetConfigurableConstant.getCxPolicyPrefix(); } + if (StringUtils.isNotBlank(policy.getOperator())) { + operator = policy.getOperator(); + } + ConstraintRequest request = ConstraintRequest.builder() - .leftOperand(policyPrefix + policy.getTechnicalKey()) - .operator(Operator.builder().id(operator).build()).rightOperand(value).build(); + .leftOperand(LinkJsonLDId.builder().id(policyPrefix + policy.getTechnicalKey()).build()) + .operator(LinkJsonLDId.builder().id(operator).build()).rightOperand(value).build(); policies.add(request); } } } - private List getAndOwnerBPNIfNotExist(Policies policy, List values) { + private List getAndOwnerBPNIfNotExist(List values) { - if (policy.getTechnicalKey().equals(edcAssetConfigurableConstant.getBpnNumberTechnicalKey()) - && !values.isEmpty() && !values.contains(sdeConfigurationProperties.getManufacturerId()) + if (!values.isEmpty() && !values.contains(sdeConfigurationProperties.getManufacturerId()) && (values.size() == 1 && !values.get(0).equals(""))) { List temp = new ArrayList<>(); values.stream().forEach(temp::add); temp.add(sdeConfigurationProperties.getManufacturerId()); values = temp; - } return values; diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyDefinitionRequest.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyDefinitionRequest.java index 9a505669e..45ceee8de 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyDefinitionRequest.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyDefinitionRequest.java @@ -21,8 +21,8 @@ package org.eclipse.tractusx.sde.edc.entities.request.policies; -import java.util.Map; - +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; @@ -36,29 +36,21 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@JsonInclude(value = Include.NON_NULL) public class PolicyDefinitionRequest { @JsonProperty("@context") - @Builder.Default - private Map context = Map.of( - "@vocab", "https://w3id.org/edc/v0.0.1/ns/", - "edc", "https://w3id.org/edc/v0.0.1/ns/", - "odrl","http://www.w3.org/ns/odrl/2/", - "tx", "https://w3id.org/tractusx/v0.0.1/ns/", - "cx-common", "https://w3id.org/catenax/ontology/common#", - "cx-taxo", "https://w3id.org/catenax/taxonomy#", - "cx-policy", "https://w3id.org/catenax/policy/" - ); + private Object context; @JsonProperty("@type") @Builder.Default - private String polityRootType = "PolicyDefinitionRequestDto"; + private String polityRootType = "PolicyDefinition"; @JsonProperty("@id") private String id; @JsonProperty("policy") - private PolicyRequest policyRequest; + private Object policyRequest; @SneakyThrows public String toJsonString() { diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequest.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequest.java index 220d817b9..9835119b3 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequest.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequest.java @@ -27,6 +27,7 @@ import org.eclipse.tractusx.sde.edc.model.policies.Obligation; import org.eclipse.tractusx.sde.edc.model.policies.Prohibition; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; @@ -43,15 +44,15 @@ @NoArgsConstructor @AllArgsConstructor @JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) public class PolicyRequest { @JsonProperty("@type") @Builder.Default - private String type = "Set"; + private String type = "odrl:Set"; @JsonProperty("@context") - @Builder.Default - private String context = "http://www.w3.org/ns/odrl.jsonld"; + private Object context; @JsonProperty("@id") private String id; @@ -65,7 +66,7 @@ public class PolicyRequest { @JsonProperty("odrl:obligation") private List obligations; - @JsonProperty("profile") + @JsonProperty("odrl:profile") private String profile; @JsonProperty("odrl:target") diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequestFactory.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequestFactory.java index ce4ae03f5..5aacfc35d 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequestFactory.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/entities/request/policies/PolicyRequestFactory.java @@ -32,6 +32,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; @Service @RequiredArgsConstructor @@ -39,32 +40,58 @@ public class PolicyRequestFactory { private final EDCAssetConfigurableConstant edcAssetConfigurableConstant; - public PolicyDefinitionRequest getPolicy(String assetId, ActionRequest action, String type) { + public PolicyDefinitionRequest getPolicy(String policyId, String assetId, List action, String type) { List permissions = getPermissions(assetId, action); + Map contextMap = Map.of( + "@vocab", "https://w3id.org/edc/v0.0.1/ns/" + ); + + Map contextMapPolicy= Map.of( + "cx-policy", "https://w3id.org/catenax/policy/", + "tx", "https://w3id.org/tractusx/v0.0.1/ns/" + ); + PolicyRequest policyRequest = PolicyRequest.builder() + .context(List.of("http://www.w3.org/ns/odrl.jsonld", contextMapPolicy)) .permissions(permissions) .profile(edcAssetConfigurableConstant.getCxPolicyPrefix() + edcAssetConfigurableConstant.getCxPolicyProfile()) .obligations(new ArrayList<>()) .prohibitions(new ArrayList<>()) - .profile(edcAssetConfigurableConstant.getCxPolicyPrefix() - + edcAssetConfigurableConstant.getCxPolicyProfile()) .target(Map.of("@id", assetId)) .build(); //Use submodel id to generate unique policy id for asset use policy type as prefix asset/usage - String policyId = getGeneratedPolicyId(assetId, type); + policyId = getGeneratedPolicyId(policyId, type); return PolicyDefinitionRequest.builder() .id(policyId) - .policyRequest(policyRequest).build(); + .context(contextMap) + .policyRequest(policyRequest) + .build(); } - public JsonNode setPolicyIdAndGetObject(String assetId, JsonNode jsonNode, String type) { + @SneakyThrows + public PolicyDefinitionRequest setPolicyIdAndGetObject(String assetId, JsonNode jsonNode, String type) { + + JsonNode contentPolicy= ((ObjectNode) jsonNode).get("content"); + + ((ObjectNode) contentPolicy).remove("@id"); + + //Use submodel id to generate unique policy id for asset use policy type as prefix asset/usage String policyId = getGeneratedPolicyId(assetId, type); - return ((ObjectNode) jsonNode).put("@id", policyId); + + Map contextMap = Map.of( + "@vocab", "https://w3id.org/edc/v0.0.1/ns/" + ); + + return PolicyDefinitionRequest.builder() + .id(policyId) + .context(contextMap) + .policyRequest(contentPolicy) + .build(); } private String getGeneratedPolicyId(String assetId, String type) { @@ -77,16 +104,19 @@ private String getGeneratedPolicyId(String assetId, String type) { } - public List getPermissions(String assetId, ActionRequest action) { + public List getPermissions(String assetId, List actions) { ArrayList permissions = new ArrayList<>(); - if (action != null) { - PermissionRequest permissionRequest = PermissionRequest - .builder().action(Map.of("odrl:type", "USE")) -// .target(assetId) - .constraint(action.getAction()) - .build(); - permissions.add(permissionRequest); + if (actions != null) { + actions.forEach(action -> { + PermissionRequest permissionRequest = PermissionRequest + .builder() + .action(LinkJsonLDId.builder().id("odrl:use").build()) +// .target(assetId) + .constraint(action.getAction()) + .build(); + permissions.add(permissionRequest); + }); } return permissions; } diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java index 4b2a75ddb..94be6f661 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/AbstractEDCStepsHelper.java @@ -53,6 +53,9 @@ public class AbstractEDCStepsHelper { @Value("${edc.consumer.protocol.path:/api/v1/dsp}") protected String protocolPath; + + @Value("${edc.consumer.protocol.path.append:true}") + protected boolean appendProtocolPath; @Value("${edc.apiKeyHeader}") private String edcProviderApiKeyHeader; diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/ContractNegotiateManagementHelper.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/ContractNegotiateManagementHelper.java index fcd2bfdd5..d36e9dbda 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/ContractNegotiateManagementHelper.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/ContractNegotiateManagementHelper.java @@ -61,7 +61,7 @@ public class ContractNegotiateManagementHelper extends AbstractEDCStepsHelper { @SneakyThrows public String negotiateContract(String providerUrl, String providerId, String offerId, String assetId, - ActionRequest action, Map extensibleProperty) { + List action, Map extensibleProperty) { var recipientURL = UtilityFunctions.removeLastSlashOfUrl(providerUrl); if (!recipientURL.endsWith(protocolPath)) diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/CreateEDCAssetFacilator.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/CreateEDCAssetFacilator.java index 9e775a5ff..a041ccc31 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/CreateEDCAssetFacilator.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/CreateEDCAssetFacilator.java @@ -52,16 +52,16 @@ public Map createEDCAsset(AssetEntryRequest assetEntryRequest, P String assetId = assetEntryRequest.getId(); - JsonNode accessPolicyDefinitionRequest = policyConstraintBuilderService.getAccessPolicy(assetId, policy); + JsonNode accessPolicyDefinitionRequest = policyConstraintBuilderService.getAccessPolicy(assetId, assetId, policy); String accessPolicyUUId = accessPolicyDefinitionRequest.get("@id").asText(); edcGateway.createPolicyDefinition(accessPolicyDefinitionRequest); - JsonNode usagePolicyDefinitionRequest = policyConstraintBuilderService.getUsagePolicy(assetId, policy); + JsonNode usagePolicyDefinitionRequest = policyConstraintBuilderService.getUsagePolicy(assetId ,assetId, policy); String usagePolicyUUId = usagePolicyDefinitionRequest.get("@id").asText(); edcGateway.createPolicyDefinition(usagePolicyDefinitionRequest); ContractDefinitionRequest contractDefinitionRequest = contractFactory.getContractDefinitionRequest(assetId, - accessPolicyUUId, usagePolicyUUId); + assetId, accessPolicyUUId, usagePolicyUUId); edcGateway.createContractDefinition(contractDefinitionRequest); @@ -81,16 +81,16 @@ public Map updateEDCAsset(AssetEntryRequest assetEntryRequest, P String assetId = assetEntryRequest.getId(); - JsonNode accessPolicyDefinitionRequest = policyConstraintBuilderService.getAccessPolicy(assetId, policy); + JsonNode accessPolicyDefinitionRequest = policyConstraintBuilderService.getAccessPolicy(assetId, assetId, policy); String accessPolicyUUId = accessPolicyDefinitionRequest.get("@id").asText(); edcGateway.updatePolicyDefinition(accessPolicyUUId, accessPolicyDefinitionRequest); - JsonNode usagePolicyDefinitionRequest = policyConstraintBuilderService.getUsagePolicy(assetId, policy); + JsonNode usagePolicyDefinitionRequest = policyConstraintBuilderService.getUsagePolicy(assetId, assetId, policy); String usagePolicyUUId = usagePolicyDefinitionRequest.get("@id").asText(); edcGateway.updatePolicyDefinition(usagePolicyUUId, usagePolicyDefinitionRequest); ContractDefinitionRequest contractDefinitionRequest = contractFactory.getContractDefinitionRequest(assetId, - accessPolicyUUId, usagePolicyUUId); + assetId, accessPolicyUUId, usagePolicyUUId); edcGateway.updateContractDefinition(contractDefinitionRequest); diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/EDRRequestHelper.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/EDRRequestHelper.java index 1546da735..25968a7c3 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/EDRRequestHelper.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/facilitator/EDRRequestHelper.java @@ -56,17 +56,29 @@ public class EDRRequestHelper extends AbstractEDCStepsHelper { @SneakyThrows public String edrRequestInitiate(String providerUrl, String providerId, Offer offer, String assetId, - ActionRequest action, Map extensibleProperty) { + List action, Map extensibleProperty) { + Map contextMap= Map.of( + "@vocab", "https://w3id.org/edc/v0.0.1/ns/", + "edc", "https://w3id.org/edc/v0.0.1/ns/", + "tx", "https://w3id.org/tractusx/v0.0.1/ns/", + "tx-auth", "https://w3id.org/tractusx/auth/", + "cx-policy", "https://w3id.org/catenax/policy/", + "odrl", "http://www.w3.org/ns/odrl/2/" + ); + String offerId = offer.getOfferId(); ContractNegotiations contractNegotiations = contractMapper.prepareContractNegotiations(providerUrl, offerId, assetId, providerId, action); + contractNegotiations.setContext(contextMap); + log.debug(LogUtil.encode(contractNegotiations.toJsonString())); if (Optional.ofNullable(offer.getHasPolicy()).isPresent()) { JsonNode hasPolicy = offer.getHasPolicy(); ((ObjectNode) hasPolicy).putPOJO("odrl:assigner", Map.of("@id", providerId)); + ((ObjectNode) hasPolicy).putPOJO("odrl:target", Map.of("@id", assetId)); contractNegotiations.setPolicy(offer.getHasPolicy()); } diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/gateways/external/EDCGateway.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/gateways/external/EDCGateway.java index 58307e26e..016bd37ef 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/gateways/external/EDCGateway.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/gateways/external/EDCGateway.java @@ -21,8 +21,12 @@ package org.eclipse.tractusx.sde.edc.gateways.external; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.sde.edc.api.EDCFeignClientApi; import org.eclipse.tractusx.sde.edc.entities.request.asset.AssetEntryRequest; +import org.eclipse.tractusx.sde.edc.entities.request.businesspartnergroup.BusinessPartnerGroupRequest; import org.eclipse.tractusx.sde.edc.entities.request.contractdefinition.ContractDefinitionRequest; import org.eclipse.tractusx.sde.edc.exceptions.EDCGatewayException; import org.springframework.http.HttpStatus; @@ -34,13 +38,15 @@ import feign.FeignException; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Service @RequiredArgsConstructor public class EDCGateway { private final EDCFeignClientApi edcFeignClientApi; - + public boolean assetExistsLookup(String id) { try { edcFeignClientApi.getAsset(id); @@ -100,6 +106,19 @@ public void updateAsset(AssetEntryRequest request) { } } + + public boolean policyExistsLookup(String policyId) { + try { + edcFeignClientApi.getPolicy(policyId); + } catch (FeignException e) { + if (e.status() == HttpStatus.NOT_FOUND.value()) { + return false; + } + throw e; + } + return true; + } + @SneakyThrows public JsonNode createPolicyDefinition(JsonNode request) { try { @@ -118,6 +137,19 @@ public void updatePolicyDefinition(String policyUUId, JsonNode request) { } } + + public boolean contractDefinitionExistsLookup(String contractDefinitionId) { + try { + edcFeignClientApi.getContractDefination(contractDefinitionId); + } catch (FeignException e) { + if (e.status() == HttpStatus.NOT_FOUND.value()) { + return false; + } + throw e; + } + return true; + } + public String createContractDefinition(ContractDefinitionRequest request) { try { return edcFeignClientApi.createContractDefination(request); @@ -133,4 +165,34 @@ public void updateContractDefinition(ContractDefinitionRequest request) { throw new EDCGatewayException(e.getMessage()); } } + + public void addBPNintoPCFBusinessPartnerGroup(String bpnNumber, String groupName) { + + try { + if (StringUtils.isNotBlank(bpnNumber)) { + edcFeignClientApi.getBusinessPartnerGroups(bpnNumber); + }else { + log.info("BPN found empty not adding in business partner group {}", groupName); + } + } catch (FeignException e) { + log.info("BPN not exist in group so adding business partner group {}, {}", groupName, e.getMessage()); + if (e.status() == HttpStatus.NOT_FOUND.value()) { + edcFeignClientApi.createBusinessPartnerGroups( + BusinessPartnerGroupRequest.builder().id(bpnNumber).groups(List.of(groupName)).build()); + + } + } + } + + public void deleteBPNfromPCFBusinessPartnerGroup(String bpnNumber, String groupName) { + try { + if (StringUtils.isNotBlank(bpnNumber)) { + edcFeignClientApi.deleteBusinessPartnerGroups(bpnNumber); + }else { + log.info("BPN found empty not going to delete from business partner group {}", groupName); + } + } catch (FeignException e) { + log.error("Unable to perform delete bpn {} from business partner group {}, {}", bpnNumber, groupName, e.getMessage()); + } + } } \ No newline at end of file diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractMapper.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractMapper.java index 64702cbf2..ea66e771e 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractMapper.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractMapper.java @@ -20,6 +20,7 @@ package org.eclipse.tractusx.sde.edc.mapper; +import java.util.List; import java.util.Map; import org.eclipse.tractusx.sde.edc.entities.request.policies.ActionRequest; @@ -38,7 +39,7 @@ public class ContractMapper { @SneakyThrows public ContractNegotiations prepareContractNegotiations(String providerProtocolUrl, String offerId, String assetId, - String provider, ActionRequest action) { + String provider, List action) { PolicyRequest policy = contractPolicyMapper.preparePolicy(assetId, action); policy.setId(offerId); diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractPolicyMapper.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractPolicyMapper.java index 3764cbdf6..6e8f7c0ef 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractPolicyMapper.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/mapper/ContractPolicyMapper.java @@ -37,7 +37,7 @@ public abstract class ContractPolicyMapper { @Autowired PolicyRequestFactory policyRequestFactory; - public PolicyRequest preparePolicy(String assetId, ActionRequest action) { + public PolicyRequest preparePolicy(String assetId, List action) { Object permissionObj = null; List permissions = policyRequestFactory.getPermissions(assetId, action); @@ -46,7 +46,8 @@ public PolicyRequest preparePolicy(String assetId, ActionRequest action) { if (!permissions.isEmpty()) permissionObj = permissions.get(0); - return PolicyRequest.builder().type("http://www.w3.org/ns/odrl/2/Offer") + return PolicyRequest.builder() + .type("odrl:Offer") .target(Map.of("@id",assetId)) .permissions(permissionObj) .prohibitions(new ArrayList<>()) diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/CatalogResponseBuilder.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/CatalogResponseBuilder.java index 7257b869b..df3e4a1cf 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/CatalogResponseBuilder.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/CatalogResponseBuilder.java @@ -49,7 +49,7 @@ public List queryOnDataOffers(String providerUrl, String co providerUrl = UtilityFunctions.removeLastSlashOfUrl(providerUrl); - if (!providerUrl.endsWith(protocolPath)) + if (!providerUrl.endsWith(protocolPath) && appendProtocolPath) providerUrl = providerUrl + protocolPath; String sproviderUrl = providerUrl; @@ -61,26 +61,24 @@ public List queryOnDataOffers(String providerUrl, String co JsonNode jOffer = contractOfferCatalog.get("dcat:dataset"); if (jOffer.isArray()) { - jOffer.forEach( - offer -> queryOfferResponse.add(buildContractOffer(sproviderUrl, contractOfferCatalog, offer))); - + offer -> handleContractOffer(sproviderUrl, contractOfferCatalog, offer, queryOfferResponse)); } else { - queryOfferResponse.add(buildContractOffer(sproviderUrl, contractOfferCatalog, jOffer)); + handleContractOffer(sproviderUrl, contractOfferCatalog, jOffer, queryOfferResponse); } return queryOfferResponse; } - public QueryDataOfferModel buildContractOffer(String sproviderUrl, JsonNode contractOfferCatalog, JsonNode offer) { - - JsonNode policy = offer.get("odrl:hasPolicy"); + public void handleContractOffer(String sproviderUrl, JsonNode contractOfferCatalog, JsonNode offer, List queryOfferResponse) { + JsonNode contractOffers = offer.get("odrl:hasPolicy"); + String edcstr = EDCAssetConstant.ASSET_PREFIX; - + QueryDataOfferModel build = QueryDataOfferModel.builder() .assetId(getFieldFromJsonNode(offer, edcstr + EDCAssetConstant.ASSET_PROP_ID)) - .connectorOfferUrl(sproviderUrl).offerId(getFieldFromJsonNode(policy, "@id")) + .connectorOfferUrl(sproviderUrl) .title(getFieldFromJsonNode(offer, edcstr + EDCAssetConstant.ASSET_PROP_NAME)) .type(getFieldFromJsonNode(offer, edcstr + EDCAssetConstant.ASSET_PROP_TYPE)) .description(getFieldFromJsonNode(offer, edcstr + EDCAssetConstant.ASSET_PROP_DESCRIPTION)) @@ -91,27 +89,49 @@ public QueryDataOfferModel buildContractOffer(String sproviderUrl, JsonNode cont .fileName(getFieldFromJsonNode(offer, edcstr + EDCAssetConstant.ASSET_PROP_FILENAME)) .fileContentType(getFieldFromJsonNode(offer, edcstr + EDCAssetConstant.ASSET_PROP_CONTENTTYPE)) .connectorId(getFieldFromJsonNode(contractOfferCatalog, edcstr+"participantId")) - .hasPolicy(policy) .build(); + + if (contractOffers.isArray()) { + contractOffers.forEach( + contractOffer -> queryOfferResponse.add(buildContractOffer(build, contractOffer))); + } else { + queryOfferResponse.add(buildContractOffer(build, contractOffers)); + } - checkAndSetPolicyPermission(build, policy); + } + public QueryDataOfferModel buildContractOffer(QueryDataOfferModel build, JsonNode contractOffer) { + + build.setOfferId(getFieldFromJsonNode(contractOffer, "@id")); + build.setHasPolicy(contractOffer); + checkAndSetPolicyPermission(build, contractOffer); return build; } - + private void checkAndSetPolicyPermission(QueryDataOfferModel build, JsonNode policy) { if (policy != null && policy.isArray()) { policy.forEach(pol -> { JsonNode permission = pol.get("odrl:permission"); - checkAndSetPolicyPermissionConstraints(build, permission); + checkAndSetPolicyPermissionsConstraints(build, permission); }); } else if (policy != null) { JsonNode permission = policy.get("odrl:permission"); - checkAndSetPolicyPermissionConstraints(build, permission); + checkAndSetPolicyPermissionsConstraints(build, permission); } } + private void checkAndSetPolicyPermissionsConstraints(QueryDataOfferModel build, JsonNode permissions) { + if (permissions != null && permissions.isArray()) { + permissions.forEach(permission -> { + checkAndSetPolicyPermissionConstraints(build, permission); + }); + } else { + checkAndSetPolicyPermissionConstraints(build, permissions); + } + } + + private void checkAndSetPolicyPermissionConstraints(QueryDataOfferModel build, JsonNode permission) { JsonNode constraints = permission.get("odrl:constraint"); @@ -137,7 +157,14 @@ private void setConstraint(List usagePolicies, JsonNode jsonNode) { // accespoliocy already applied for access control, // in this constrain all are usage policy - String leftOperand = getFieldFromJsonNode(jsonNode, "odrl:leftOperand"); + JsonNode letfOerand = jsonNode.get("odrl:leftOperand"); + String leftOperand = ""; + if(letfOerand.isObject()) { + leftOperand = getFieldFromJsonNode(letfOerand, "@id"); + } else { + leftOperand = getFieldFromJsonNode(jsonNode, "odrl:leftOperand"); + } + String rightOperand = getFieldFromJsonNode(jsonNode, "odrl:rightOperand"); Policies policyResponse = UtilityFunctions.identyAndGetUsagePolicy(leftOperand, rightOperand); if (policyResponse != null) diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ConsumerControlPanelService.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ConsumerControlPanelService.java index 90f23f775..153e227eb 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ConsumerControlPanelService.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ConsumerControlPanelService.java @@ -135,7 +135,7 @@ public void subscribeDataOffers(ConsumerRequest consumerRequest, String processI AtomicReference negotiateContractId = new AtomicReference<>(); AtomicReference checkContractNegotiationStatus = new AtomicReference<>(); - ActionRequest action = policyConstraintBuilderService + List action = policyConstraintBuilderService .getUsagePoliciesConstraints(consumerRequest.getUsagePolicies()); consumerRequest.getOffers().parallelStream().forEach(offer -> { @@ -175,7 +175,7 @@ public void subscribeDataOffers(ConsumerRequest consumerRequest, String processI } - public Map subcribeAndDownloadOffer(Offer offer, ActionRequest action, + public Map subcribeAndDownloadOffer(Offer offer, List action, boolean flagToDownloadImidiate, String downloadAs) { Map resultFields = new ConcurrentHashMap<>(); diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ContractNegotiationService.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ContractNegotiationService.java index f6a4384cc..86c57db25 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ContractNegotiationService.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/ContractNegotiationService.java @@ -57,7 +57,7 @@ public class ContractNegotiationService extends AbstractEDCStepsHelper { @SneakyThrows public EDRCachedResponse verifyOrCreateContractNegotiation(String connectorId, - Map extensibleProperty, String recipientURL, ActionRequest action, Offer offer) { + Map extensibleProperty, String recipientURL, List action, Offer offer) { if (!offer.getConnectorOfferUrl().endsWith(protocolPath)) recipientURL = recipientURL + protocolPath; diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/LookUpDTTwin.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/LookUpDTTwin.java index c36802c54..a0f4ddb8f 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/LookUpDTTwin.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/services/LookUpDTTwin.java @@ -257,13 +257,9 @@ public List getEDCOffer(List assetId } } - List queryOnDataOffers = catalogResponseBuilder.queryOnDataOffers(connectorOfferUrl, + return catalogResponseBuilder.queryOnDataOffers(connectorOfferUrl, queryDataOfferRequestKey.getRight(), 0, 1000, filterExpression); - - return queryOnDataOffers.stream().map(obj-> { - obj.setConnectorOfferUrl(queryDataOfferRequestKey.getLeft()); - return obj; - }).toList(); + } private String getSpecificKeyFromList(ShellDescriptorResponse shellDescriptorResponse, String key) { diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/EDCAssetUrlCacheService.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/EDCAssetUrlCacheService.java index c4f086599..97fa2b044 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/EDCAssetUrlCacheService.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/EDCAssetUrlCacheService.java @@ -63,7 +63,7 @@ public class EDCAssetUrlCacheService { @SneakyThrows public EDRCachedByIdResponse verifyAndGetToken(String bpnNumber, QueryDataOfferModel queryDataOfferModel) { - ActionRequest action = policyConstraintBuilderService + List action = policyConstraintBuilderService .getUsagePoliciesConstraints(queryDataOfferModel.getPolicy().getUsagePolicies()); Offer offer = Offer.builder().assetId(queryDataOfferModel.getAssetId()) @@ -187,5 +187,5 @@ public void clearBpdmUrlCache() { public void removeBpdmCache() { bpdmEdcAssetUtility.removeBpdmCache(edcAssetConfigurableConstant.getBpdmProviderBpnl()); bpdmMap.remove(edcAssetConfigurableConstant.getBpdmProviderBpnl()); - } + } } \ No newline at end of file diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/PCFExchangeAssetUtils.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/PCFExchangeAssetUtils.java index 93dd1eb81..f57200a97 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/PCFExchangeAssetUtils.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/PCFExchangeAssetUtils.java @@ -21,8 +21,8 @@ import java.util.List; +import org.eclipse.tractusx.sde.common.configuration.properties.PCFAssetStaticPropertyHolder; import org.eclipse.tractusx.sde.common.utils.LogUtil; -import org.eclipse.tractusx.sde.edc.constants.EDCAssetConfigurableConstant; import org.eclipse.tractusx.sde.edc.entities.request.contractdefinition.Criterion; import org.eclipse.tractusx.sde.edc.model.response.QueryDataOfferModel; import org.springframework.cache.annotation.CacheEvict; @@ -39,7 +39,7 @@ public class PCFExchangeAssetUtils { private final EDCAssetLookUp edcAssetLookUp; - private final EDCAssetConfigurableConstant edcAssetConfigurableConstant; + private final PCFAssetStaticPropertyHolder pcfAssetStaticPropertyHolder; @Cacheable(value = "bpn-pcfexchange", key = "#bpnNumber") public List getPCFExchangeUrl(String bpnNumber) { @@ -62,7 +62,8 @@ private List getFilterCriteria() { Criterion.builder() .operandLeft("'http://purl.org/dc/terms/type'.'@id'") .operator("=") - .operandRight("https://w3id.org/catenax/taxonomy#"+edcAssetConfigurableConstant.getAssetPropTypePCFExchangeType()) + .operandRight("https://w3id.org/catenax/taxonomy#"+pcfAssetStaticPropertyHolder.getAssetPropTypePCFExchangeType()) .build()); } + } diff --git a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/UtilityFunctions.java b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/UtilityFunctions.java index 947ce4922..08b4b2989 100644 --- a/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/UtilityFunctions.java +++ b/modules/sde-external-services/edc/src/main/java/org/eclipse/tractusx/sde/edc/util/UtilityFunctions.java @@ -53,7 +53,7 @@ public static String removeLastSlashOfUrl(String url) { public static List getUsagePolicies(List usagePolicies, List constraints) { constraints.forEach(constraint -> { - String leftExpVal = constraint.getLeftOperand(); + String leftExpVal = constraint.getLeftOperand().getId(); String rightExpVal = constraint.getRightOperand().toString(); Policies policyResponse = identyAndGetUsagePolicy(leftExpVal, rightExpVal); if (policyResponse != null) diff --git a/modules/sde-external-services/portal/src/main/java/org/eclipse/tractusx/sde/portal/api/IPartnerPoolExternalServiceApi.java b/modules/sde-external-services/portal/src/main/java/org/eclipse/tractusx/sde/portal/api/IPartnerPoolExternalServiceApi.java index 0686db574..4bc3dcda4 100644 --- a/modules/sde-external-services/portal/src/main/java/org/eclipse/tractusx/sde/portal/api/IPartnerPoolExternalServiceApi.java +++ b/modules/sde-external-services/portal/src/main/java/org/eclipse/tractusx/sde/portal/api/IPartnerPoolExternalServiceApi.java @@ -19,6 +19,7 @@ ********************************************************************************/ package org.eclipse.tractusx.sde.portal.api; +import java.net.URI; import java.util.Map; import org.eclipse.tractusx.sde.portal.model.LegalEntityData; @@ -28,10 +29,10 @@ import org.springframework.web.bind.annotation.RequestParam; -@FeignClient(value = "IPartnerPoolExternalServiceApi", url = "${bpdm.provider.edc.public.api}") +@FeignClient(value = "IPartnerPoolExternalServiceApi", url = "placeholder") public interface IPartnerPoolExternalServiceApi { @GetMapping(path = "/legal-entities") - LegalEntityData fetchLegalEntityData(@RequestParam String bpnLs, @RequestParam String legalName, @RequestParam Integer page, @RequestParam Integer size,@RequestHeader Map header); + LegalEntityData fetchLegalEntityData(URI url, @RequestParam String bpnLs, @RequestParam String legalName, @RequestParam Integer page, @RequestParam Integer size,@RequestHeader Map header); } \ No newline at end of file diff --git a/modules/sde-submodules/pcf/src/main/java/org/eclipse/tractusx/sde/submodels/pcf/PCFEDCUsecaseHandler.java b/modules/sde-submodules/pcf/src/main/java/org/eclipse/tractusx/sde/submodels/pcf/PCFEDCUsecaseHandler.java index e32a4fa81..7fbc92e38 100644 --- a/modules/sde-submodules/pcf/src/main/java/org/eclipse/tractusx/sde/submodels/pcf/PCFEDCUsecaseHandler.java +++ b/modules/sde-submodules/pcf/src/main/java/org/eclipse/tractusx/sde/submodels/pcf/PCFEDCUsecaseHandler.java @@ -20,11 +20,24 @@ package org.eclipse.tractusx.sde.submodels.pcf; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.tractusx.sde.common.configuration.properties.PCFAssetStaticPropertyHolder; +import org.eclipse.tractusx.sde.common.constants.SubmoduleCommonColumnsConstant; import org.eclipse.tractusx.sde.common.entities.PolicyModel; import org.eclipse.tractusx.sde.common.submodel.executor.EDCUsecaseStep; import org.eclipse.tractusx.sde.common.submodel.executor.Step; +import org.eclipse.tractusx.sde.common.utils.JsonObjectUtility; +import org.eclipse.tractusx.sde.common.utils.PolicyOperationUtil; +import org.eclipse.tractusx.sde.edc.entities.request.contractdefinition.ContractDefinitionRequest; +import org.eclipse.tractusx.sde.edc.entities.request.contractdefinition.ContractDefinitionRequestFactory; +import org.eclipse.tractusx.sde.edc.entities.request.policies.PolicyConstraintBuilderService; +import org.eclipse.tractusx.sde.edc.gateways.external.EDCGateway; import org.springframework.stereotype.Service; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.gson.JsonObject; @@ -37,13 +50,87 @@ @RequiredArgsConstructor public class PCFEDCUsecaseHandler extends Step implements EDCUsecaseStep { - @SneakyThrows - public ObjectNode run(Integer rowNumber, ObjectNode objectNode, String processId, PolicyModel policy) { - log.warn("No need to create EDC asset for PCF exchange"); - return objectNode; - } + private final PCFAssetStaticPropertyHolder pcfAssetStaticPropertyHolder; + + private final PolicyConstraintBuilderService policyConstraintBuilderService; + + private final ContractDefinitionRequestFactory contractFactory; + + private final EDCGateway edcGateway; + + @SneakyThrows + @Override + public ObjectNode run(Integer rowNumber, ObjectNode objectNode, String processId, PolicyModel policy) { + + Map output = new HashMap<>(); + + String shellId = JsonObjectUtility.getValueFromJsonObjectAsString(objectNode, + SubmoduleCommonColumnsConstant.SHELL_ID); + + String subModelId = JsonObjectUtility.getValueFromJsonObjectAsString(objectNode, + SubmoduleCommonColumnsConstant.SUBMODULE_ID); + + String newOfferId = shellId + "-" + subModelId; + + // Get existing pcf id + String assetId = pcfAssetStaticPropertyHolder.getPcfExchangeAssetId(); + + // API call to added BPN business partner group + List sharedBPNList = PolicyOperationUtil.getAccessBPNList(policy); + + // Create access policy + JsonNode accessPolicyDefinitionRequest = policyConstraintBuilderService.getAccessPolicy(newOfferId, assetId, policy); + String accessPolicyUUId = accessPolicyDefinitionRequest.get("@id").asText(); + if (!edcGateway.policyExistsLookup(accessPolicyUUId)) { + edcGateway.createPolicyDefinition(accessPolicyDefinitionRequest); + } else{ + // Update existing policy + edcGateway.updatePolicyDefinition(accessPolicyUUId, accessPolicyDefinitionRequest); + } + + // Create usage policy + JsonNode usagePolicyDefinitionRequest = policyConstraintBuilderService.getUsagePolicy(newOfferId, assetId, policy); + String usagePolicyUUId = usagePolicyDefinitionRequest.get("@id").asText(); + if (!edcGateway.policyExistsLookup(usagePolicyUUId)) { + edcGateway.createPolicyDefinition(usagePolicyDefinitionRequest); + } else { + // Update existing policy + edcGateway.updatePolicyDefinition(usagePolicyUUId, usagePolicyDefinitionRequest); + } + + // Create contract definition + ContractDefinitionRequest contractDefinitionRequest = contractFactory + .getContractDefinitionRequest(newOfferId, assetId, accessPolicyUUId, usagePolicyUUId); + + String contractDefinitionId = contractDefinitionRequest.getId(); + if (!edcGateway.contractDefinitionExistsLookup(contractDefinitionId)) { + edcGateway.createContractDefinition(contractDefinitionRequest); + } else { + // Update existing contract definition + edcGateway.updateContractDefinition(contractDefinitionRequest); + } + + for (String bpnNumber : sharedBPNList) { + //get call + edcGateway.deleteBPNfromPCFBusinessPartnerGroup(bpnNumber, pcfAssetStaticPropertyHolder.getPcfBusinessPartnerGroup()); + } + + output.put(SubmoduleCommonColumnsConstant.ASSET_ID, assetId); + output.put(SubmoduleCommonColumnsConstant.ACCESS_POLICY_ID, accessPolicyUUId); + output.put(SubmoduleCommonColumnsConstant.USAGE_POLICY_ID, usagePolicyUUId); + output.put(SubmoduleCommonColumnsConstant.CONTRACT_DEFINATION_ID, contractDefinitionId); + + output.entrySet().forEach(entry -> objectNode.put(entry.getKey(), entry.getValue())); + + // existing policy access and usage update + + return objectNode; + + } + + @Override + public void delete(Integer rowIndex, JsonObject jsonObject, String delProcessId, String refProcessId) { + log.warn("No need to delete EDC asset for PCF exchange"); - public void delete(Integer rowIndex, JsonObject jsonObject, String delProcessId, String refProcessId) { - log.warn("No need to delete EDC asset for PCF exchange"); - } + } } \ No newline at end of file diff --git a/modules/sde-submodules/pcf/src/main/resources/pcf-v6.0.0.json b/modules/sde-submodules/pcf/src/main/resources/pcf-v6.0.0.json index a3d5b7b00..0bf4e8579 100644 --- a/modules/sde-submodules/pcf/src/main/resources/pcf-v6.0.0.json +++ b/modules/sde-submodules/pcf/src/main/resources/pcf-v6.0.0.json @@ -6,6 +6,8 @@ "idShort": "PCFExchangeEndpoint", "submodelUriPath":"productIds", "submodelDataPlaneUrl":"https://edc.data.plane", + "sematicIdReference":"Submodel", + "interfaceName":"PCF-1.1", "version": "6.0.0", "semantic_id": "urn:samm:io.catenax.pcf:6.0.0#Pcf", "title": "Product Carbon Footprint (pcf)", @@ -973,6 +975,7 @@ "bpnDiscoverySpecs": { "manufacturerPartId": "${productId}" }, + "usePCFAssetIdAsDTSubprotocolBodyId" :true, "databaseIdentifierSpecs": ["${productId}"], "responseTemplate": { "specVersion": "${specVersion}",