Skip to content

Commit

Permalink
Merge pull request #296 from FraunhoferISST/feat/register_parttype_at…
Browse files Browse the repository at this point in the history
…_edc

Feat/register parttype at edc
  • Loading branch information
tom-rm-meyer-ISST authored Mar 22, 2024
2 parents 503a440 + 1570946 commit ed2cbda
Show file tree
Hide file tree
Showing 16 changed files with 422 additions and 68 deletions.
2 changes: 1 addition & 1 deletion DEPENDENCIES_FRONTEND
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ npm/npmjs/@babel/highlight/7.23.4, MIT AND (BSD-2-Clause AND ISC AND MIT) AND BS
npm/npmjs/@babel/parser/7.23.6, MIT AND (BSD-2-Clause AND ISC AND MIT) AND BSD-2-Clause AND BSD-3-Clause, approved, #10663
npm/npmjs/@babel/plugin-transform-react-jsx-self/7.23.3, MIT, approved, clearlydefined
npm/npmjs/@babel/plugin-transform-react-jsx-source/7.23.3, MIT, approved, clearlydefined
npm/npmjs/@babel/runtime/7.24.0, MIT, approved, clearlydefined
npm/npmjs/@babel/runtime/7.24.0, MIT AND (BSD-2-Clause AND ISC AND MIT) AND BSD-2-Clause AND BSD-3-Clause, approved, #13900
npm/npmjs/@babel/template/7.22.15, MIT, approved, #9017
npm/npmjs/@babel/traverse/7.23.7, MIT AND (BSD-2-Clause AND ISC AND MIT) AND BSD-2-Clause AND BSD-3-Clause, approved, #11520
npm/npmjs/@babel/types/7.23.6, MIT AND (BSD-2-Clause AND ISC AND MIT) AND BSD-2-Clause AND BSD-3-Clause, approved, #11521
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private void setupCustomerRole() throws JsonProcessingException {

MaterialPartnerRelation semiconductorPartnerRelation = new MaterialPartnerRelation(semiconductorMaterial,
supplierPartner, semiconductorMatNbrSupplier, true, false);
semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX);
// semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX);
mprService.create(semiconductorPartnerRelation);
semiconductorPartnerRelation = mprService.find(semiconductorMaterial, supplierPartner);
log.info("Found Relation: " + semiconductorPartnerRelation);
Expand Down Expand Up @@ -248,7 +248,7 @@ private void setupSupplierRole() {

MaterialPartnerRelation semiconductorPartnerRelation = new MaterialPartnerRelation(semiconductorMaterial,
customerPartner, semiconductorMatNbrCustomer, false, true);
semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX);
// semiconductorPartnerRelation.setPartnerCXNumber(semiconductorMatNbrCatenaX);
semiconductorPartnerRelation = mprService.create(semiconductorPartnerRelation);

log.info("Created Relation " + semiconductorPartnerRelation);
Expand Down Expand Up @@ -411,7 +411,7 @@ private Material getNewSemiconductorMaterialForSupplier() {
private Material getNewSemiconductorMaterialForCustomer() {
Material material = new Material();
material.setOwnMaterialNumber(semiconductorMatNbrCustomer);
material.setMaterialNumberCx(semiconductorMatNbrCatenaX);
// material.setMaterialNumberCx(semiconductorMatNbrCatenaX);
material.setMaterialFlag(true);
material.setName("Semiconductor");
return material;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ public boolean registerAssetsInitially() {
public boolean createPolicyAndContractDefForPartner(Partner partner) {
boolean result = createPolicyDefinitionForPartner(partner);
result &= createDtrContractDefinitionForPartner(partner);
result &= registerPartTypeAssetForPartner(partner);
result &= createPartTypeInfoContractDefForPartner(partner);
result &= createContractDefinitionForPartner(partner, DT_ApiMethodEnum.REQUEST);
result &= createContractDefinitionForPartner(partner, DT_ApiMethodEnum.STATUS_REQUEST);
return result & createContractDefinitionForPartner(partner, DT_ApiMethodEnum.RESPONSE);
Expand Down Expand Up @@ -186,6 +188,21 @@ private boolean createDtrContractDefinitionForPartner(Partner partner) {
}
}

private boolean createPartTypeInfoContractDefForPartner(Partner partner) {
var body = edcRequestBodyBuilder.buildPartTypeInfoContractDefinitionForPartner(partner);
try (var response = sendPostRequest(body, List.of("v2", "contractdefinitions"))) {
if (!response.isSuccessful()) {
log.warn("Contract definition registration failed for partner " + partner.getBpnl() + " and PartTypeInfo asset");
return false;
}
log.info("Contract definition successful for PartTypeAsset and partner " + partner.getBpnl());
return true;
} catch (Exception e) {
log.error("Contract definition registration failed for partner " + partner.getBpnl() + " and PartTypeInfo asset", e);
return false;
}
}


/**
* Registers a policy definition that allows only the given partner's
Expand Down Expand Up @@ -242,6 +259,7 @@ private boolean registerDtrAsset() {
if (response.body() != null) {
log.warn("Response: \n" + response.body().string());
}
return false;
}
return true;
} catch (Exception e) {
Expand All @@ -250,6 +268,24 @@ private boolean registerDtrAsset() {
}
}

private boolean registerPartTypeAssetForPartner(Partner partner) {
var body = edcRequestBodyBuilder.buildPartTypeInfoRegistrationBody(partner);
try (var response = sendPostRequest(body, List.of("v3", "assets"))) {
if (!response.isSuccessful()) {
log.warn("Asset registration failed for PartTypeAsset and partner " + partner.getBpnl());
if (response.body() != null) {
log.warn("Response: \n" + response.body().string());
}
return false;
}
log.info("Asset registration successful for PartTypeAsset and partner " + partner.getBpnl());
return true;
} catch (Exception e) {
log.error("Failed to register PartTypeAsset for partner " + partner.getBpnl());
return false;
}
}

/**
* Util method to register an API asset to your control plane.
*
Expand Down Expand Up @@ -277,11 +313,12 @@ private boolean registerApiAsset(DT_ApiMethodEnum apiMethod) {
/**
* Retrieve the response to an unfiltered catalog request from the partner
* with the given dspUrl
* @param dspUrl The dspUrl of your partner
* @return The response containing the full catalog, if successful
*
* @param dspUrl The dspUrl of your partner
* @return The response containing the full catalog, if successful
*/
public Response getCatalogResponse(String dspUrl) throws IOException {
return sendPostRequest(edcRequestBodyBuilder.buildBasicCatalogRequestBody(dspUrl, null), List.of("v2", "catalog", "request"));
return sendPostRequest(edcRequestBodyBuilder.buildBasicCatalogRequestBody(dspUrl, null), List.of("v2", "catalog", "request"));
}

/**
Expand Down Expand Up @@ -432,6 +469,129 @@ public Response postProxyPullRequest(String url, String authKey, String authCode
}
}

public Response getProxyPullRequest(String url, String authKey, String authCode, String[] pathParams) {
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
for (var pathSegment : pathParams) {
urlBuilder.addPathSegment(pathSegment);
}
try {
var request = new Request.Builder()
.get()
.url(urlBuilder.build())
.header(authKey, authCode)
.build();
return CLIENT.newCall(request).execute();
} catch (Exception e) {
log.error("ProxyPull GET Request failed ", e);
return null;
}
}

/**
* Tries to negotiate for the PartTypeInfo-Submodel asset with the given partner
* and also tries to initiate the transfer of the edr token to the given endpoint.
* <p>
* It will return a String array of length 4. The authKey is stored under index 0, the
* authCode under index 1, the endpoint under index 2 and the contractId under index 3.
*
* @param partner the partner
* @return A String array or null, if negotiation failed or the authCode did not arrive
*/
public String[] getContractForPartTypeInfoSubmodel(Partner partner) {
try {
var responseNode = getCatalog(partner.getEdcUrl());
var catalogArray = responseNode.get("dcat:dataset");
// If there is exactly one asset, the catalogContent will be a JSON object.
// In all other cases catalogContent will be a JSON array.
// For the sake of uniformity we will embed a single object in an array.
if (catalogArray.isObject()) {
catalogArray = objectMapper.createArrayNode().add(catalogArray);
}
JsonNode targetCatalogEntry = null;
for (var entry : catalogArray) {
var dctTypeObject = entry.get("dct:type");
if (dctTypeObject != null) {
if (("https://w3id.org/catenax/taxonomy#Submodel").equals(dctTypeObject.get("@id").asText())) {
if ("3.0".equals(entry.get("https://w3id.org/catenax/ontology/common#version").asText())) {
var semanticId = entry.get("aas-semantics:semanticId");
String idString = semanticId.get("@id").asText();
if ("urn:samm:io.catenax.part_type_information:1.0.0#PartTypeInformation".equals(idString)) {
if (targetCatalogEntry == null) {
if (variablesService.isUseFrameworkPolicy()) {
if (testFrameworkAgreementConstraint(entry)) {
targetCatalogEntry = entry;
} else {
log.error("Contract Negotiation for PartTypeInformation Submodel asset with partner " + partner.getBpnl() + " has " +
"been aborted. This partner's contract policy does not match the policy " +
"supported by this application. \n Supported Policy: " + variablesService.getPurisFrameworkAgreement() +
"\n Received offer from Partner: \n" + entry.toPrettyString());
break;
}
} else {
targetCatalogEntry = entry;
}
} else {
log.warn("Ambiguous catalog entries found! \n" + catalogArray.toPrettyString());
}
}
}
}
}
}
if (targetCatalogEntry == null) {
log.error("Could not find submodel asset for PartTypeInformation at partner " + partner.getBpnl() + " 's catalog");
return null;
}
String assetId = targetCatalogEntry.get("@id").asText();
JsonNode negotiationResponse = initiateNegotiation(partner, targetCatalogEntry);
String negotiationId = negotiationResponse.get("@id").asText();
// Await confirmation of contract and contractId
String contractId = null;
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
var responseObject = getNegotiationState(negotiationId);
if ("FINALIZED".equals(responseObject.get("edc:state").asText())) {
contractId = responseObject.get("edc:contractAgreementId").asText();
break;
}
}
if (contractId == null) {
var negotiationState = getNegotiationState(negotiationId);
log.warn("no contract id, last negotiation state: \n" + negotiationState.toPrettyString());
log.error("Failed to obtain " + assetId + " from " + partner.getEdcUrl());
return null;
}

// Initiate transfer of edr
var transferResp = initiateProxyPullTransfer(partner, contractId, assetId);
String transferId = transferResp.get("@id").asText();
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
transferResp = getTransferState(transferId);
if ("STARTED".equals(transferResp.get("edc:state").asText())) {
break;
}
}

// Await arrival of edr
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
EDR_Dto edr_Dto = edrService.findByTransferId(transferId);
if (edr_Dto != null) {
log.info("Successfully negotiated for " + assetId + " with " + partner.getEdcUrl());
return new String[]{edr_Dto.authKey(), edr_Dto.authCode(), edr_Dto.endpoint(), contractId};
}
}
log.warn("did not receive authCode");
log.error("Failed to obtain " + assetId + " from " + partner.getEdcUrl());
return null;

} catch (Exception e) {
log.error("Failed to get contract for PartTypeInfo submodel asset from " + partner.getBpnl(), e);
return null;
}
}

/**
* Tries to negotiate for the given api Method with the given partner
* and also tries to initiate the transfer of the edr token to the given endpoint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,24 @@ public JsonNode buildDtrContractDefinitionForPartner(Partner partner) {
return body;
}

public JsonNode buildPartTypeInfoContractDefinitionForPartner(Partner partner) {
var body = getEdcContextObject();
body.put("@id", partner.getBpnl() +"_contractdefinition_for_PartTypeInfoAsset");
body.put("accessPolicyId", getBpnPolicyId(partner));
if(variablesService.isUseFrameworkPolicy()) {
body.put("contractPolicyId", FRAMEWORK_POLICY_ID);
} else {
body.put("contractPolicyId", getBpnPolicyId(partner));
}
var assetsSelector = MAPPER.createObjectNode();
body.set("assetsSelector", assetsSelector);
assetsSelector.put("@type", "CriterionDto");
assetsSelector.put("operandLeft", EDC_NAMESPACE + "id");
assetsSelector.put("operator", "=");
assetsSelector.put("operandRight", getPartTypeInfoAssetId(partner));
return body;
}

/**
* This method helps to ensure that the buildContractDefinitionWithBpnRestrictedPolicy uses the
* same policy-id as the one that is created with the buildContractDefinitionWithBpnRestrictedPolicy
Expand Down Expand Up @@ -338,10 +356,44 @@ public JsonNode buildDtrRegistrationBody() {
return body;
}

public JsonNode buildPartTypeInfoRegistrationBody(Partner partner) {
var body = getAssetRegistrationContext();
body.put("@id", getPartTypeInfoAssetId(partner));
var propertiesObject = MAPPER.createObjectNode();
body.set("properties", propertiesObject);
var dctTypeObject = MAPPER.createObjectNode();
propertiesObject.set("dct:type", dctTypeObject);
dctTypeObject.put("@id", CX_TAXO_NAMESPACE + "Submodel");
propertiesObject.put("cx-common:version", "3.0");
var semanticIdObject = MAPPER.createObjectNode();
propertiesObject.set("aas-semantics:semanticId", semanticIdObject);
semanticIdObject.put("@id", "urn:samm:io.catenax.part_type_information:1.0.0#PartTypeInformation");
var dataAddress = MAPPER.createObjectNode();
String url = variablesService.getParttypeInformationServerendpoint();
if (!url.endsWith("/")) {
url += "/";
}
url += partner.getBpnl();
dataAddress.put("@type", "DataAddress");
dataAddress.put("proxyPath", "true");
dataAddress.put("proxyQueryParams", "false");
dataAddress.put("proxyMethod", "false");
dataAddress.put("type", "HttpData");
dataAddress.put("baseUrl", url);
dataAddress.put("authKey", "x-api-key");
dataAddress.put("authCode", variablesService.getApiKey());
body.set("dataAddress", dataAddress);
return body;
}

private String getDtrAssetId() {
return "DigitalTwinRegistryId@" + variablesService.getOwnBpnl();
}

private String getPartTypeInfoAssetId(Partner partner) {
return "PartTypeInformationApi_" + partner.getBpnl();
}

private ObjectNode getAssetRegistrationContext() {
var body = MAPPER.createObjectNode();
var context = MAPPER.createObjectNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.authorizeHttpRequests(
// any request in spring context
(authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers("/stockView/**", "/partners/**", "/materials/**", "/materialpartnerrelations/**", "/item-stock/**", "/edrendpoint/**", "/edc/**").authenticated()
.requestMatchers("/stockView/**", "/partners/**", "/materials/**", "/materialpartnerrelations/**", "/item-stock/**", "/edrendpoint/**", "/edc/**", "/parttypeinformation/**").authenticated()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/health/**").permitAll()
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ public class VariablesService {
* The port used by this apps server application.
*/
private String serverPort;
@Value("${puris.baseurl}")
private String purisBaseUrl;
@Value("${puris.demonstrator.role}")
/**
* Must be set to "CUSTOMER" or "SUPPLIER" if
* you want to start with some initial settings
* defined in the DataInjectionCommandLineRunner
*/
private String demoRole;
@Value("${puris.edr.endpoint}")

@Value("${puris.baseurl}" + "catena/edrendpoint")
/**
* The edrEndpoint to be used during consumer pull asset transfers.
*/
Expand All @@ -57,7 +60,7 @@ public class VariablesService {
* in the context of a consumer pull is removed from memory
*/
private long edrTokenDeletionTimer;
@Value("${puris.request.serverendpoint}")
@Value("${puris.baseurl}" + "catena/item-stock/request")
/**
* The url under which this application's request endpoint can
* be reached by external machines.
Expand All @@ -69,7 +72,7 @@ public class VariablesService {
* during asset creation.
*/
private String requestApiAssetId;
@Value("${puris.response.serverendpoint}")
@Value("${puris.baseurl}" + "catena/item-stock/response")
/**
* The url under which this application's response endpoint can
* be reached by external machines.
Expand All @@ -87,7 +90,7 @@ public class VariablesService {
* during asset creation.
*/
private String statusRequestApiAssetId;
@Value("${puris.statusrequest.serverendpoint}")
@Value("${puris.baseurl}" + "catena/item-stock/status")
/**
* The url under which this application's status-request endpoint
* can be reached by external machines.
Expand Down Expand Up @@ -116,6 +119,9 @@ public class VariablesService {
*/
private String dtrUrl;

@Value("${puris.baseurl}" + "catena/parttypeinformation")
private String parttypeInformationServerendpoint;

@Value("${puris.generatematerialcatenaxid}")
/**
* A flag that signals whether the MaterialService
Expand Down
Loading

0 comments on commit ed2cbda

Please sign in to comment.