Skip to content

Commit

Permalink
fix(bug): fixed bug related to auto-negotiation and adding logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Mathias Brunkow Moser committed May 13, 2024
1 parent 8d28ae9 commit 5cce456
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.eclipse.tractusx.digitalproductpass.config.PassportConfig;
import org.eclipse.tractusx.digitalproductpass.config.SingleApiConfig;
import org.eclipse.tractusx.digitalproductpass.managers.ProcessManager;
import org.eclipse.tractusx.digitalproductpass.models.general.Selection;
import org.eclipse.tractusx.digitalproductpass.models.http.Response;
import org.eclipse.tractusx.digitalproductpass.models.http.requests.DiscoverySearch;
import org.eclipse.tractusx.digitalproductpass.models.http.requests.Search;
Expand All @@ -47,6 +48,7 @@
import org.eclipse.tractusx.digitalproductpass.models.manager.Process;
import org.eclipse.tractusx.digitalproductpass.models.manager.Status;
import org.eclipse.tractusx.digitalproductpass.models.negotiation.catalog.Dataset;
import org.eclipse.tractusx.digitalproductpass.models.negotiation.policy.Set;
import org.eclipse.tractusx.digitalproductpass.models.passports.PassportResponse;
import org.eclipse.tractusx.digitalproductpass.services.AasService;
import org.eclipse.tractusx.digitalproductpass.services.AuthenticationService;
Expand All @@ -58,10 +60,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import utils.HttpUtil;
import utils.JsonUtil;
import utils.LogUtil;
import utils.ThreadUtil;
import utils.*;
import utils.exceptions.UtilException;

import java.util.List;
Expand Down Expand Up @@ -89,6 +88,8 @@ public class ApiController {
private @Autowired AuthenticationService authService;
private @Autowired PassportConfig passportConfig;
private @Autowired HttpUtil httpUtil;
private @Autowired EdcUtil edcUtil;
private @Autowired PolicyUtil policyUtil;
private @Autowired JsonUtil jsonUtil;
private @Autowired ProcessManager processManager;
private @Autowired SingleApiConfig singleApiConfig;
Expand Down Expand Up @@ -176,7 +177,7 @@ public Response singleApi(@Valid @RequestBody SingleApiRequest singleApiRequestB
try {
createResponseData = (Map<String, String>) jsonUtil.toMap(createResponse.getData());
} catch (UtilException e) {
response = httpUtil.getBadRequest("Create Call:\n" + e.getMessage());
response = httpUtil.getInternalError("Failed in creating process: " + e.getMessage());
return httpUtil.buildResponse(response, httpResponse);
}
String processId= createResponseData.get("processId");
Expand All @@ -199,16 +200,28 @@ public Response singleApi(@Valid @RequestBody SingleApiRequest singleApiRequestB
searchResponseData = (Map<String, Object>) jsonUtil.toMap(searchResponse.getData());
contracts = (Map<String, Dataset>) jsonUtil.toMap(searchResponseData.get("contracts"));
} catch (UtilException e) {
response = httpUtil.getBadRequest("Search Call:\n" + e.getMessage());
response = httpUtil.getInternalError("Failed to search for digital twin in dtrs: " + e.getMessage());
return httpUtil.buildResponse(response, httpResponse);
}
LogUtil.printMessage("[SINGLE API] [PROCESS "+processId + "] Search for contracts done! Digital Twin and Contracts available!");
//Call sign function
TokenRequest tokenRequest = new TokenRequest();
tokenRequest.setToken(searchResponseData.get("token").toString());
tokenRequest.setProcessId(searchResponseData.get("id").toString());
String contractId = contracts.entrySet().stream().findFirst().get().getKey();
tokenRequest.setContractId(contractId);
// Get valid contract and policy
Selection<Dataset, Set> selection = edcUtil.selectValidContractAndPolicy(contracts, passportConfig.getPolicyCheck());

if(selection == null){
LogUtil.printError("[SINGLE API] [PROCESS "+processId + "] No valid contracts and policies found!");
response = httpUtil.getNotFound("No valid contracts and policies were found in the asset negotiation!");
return httpUtil.buildResponse(response, httpResponse);
}
LogUtil.printMessage("[SINGLE API] [PROCESS "+processId + "] Selected [CONTRACT "+selection.d().getId()+"]:["+this.jsonUtil.toJson(selection.d(), false)+"]!");
LogUtil.printMessage("[SINGLE API] [PROCESS "+processId + "] Selected [POLICY "+selection.s().getId()+"]:["+this.jsonUtil.toJson(selection.s(), false)+"]!");
// Set contract
tokenRequest.setContractId(selection.d().getId());
// Set policy id
tokenRequest.setPolicyId(selection.s().getId());
Response agreeResponse = contractService.doContractAgreement(httpRequest, httpResponse, tokenRequest);
LogUtil.printMessage("[SINGLE API] [PROCESS "+processId + "] Agreed with a contract and started the contract negotiation!");
//The Status from the response must 200 to proceed
Expand All @@ -220,7 +233,7 @@ public Response singleApi(@Valid @RequestBody SingleApiRequest singleApiRequestB
try {
status = (Status) jsonUtil.bindObject(agreeResponse.getData(), Status.class);
} catch (UtilException e) {
response = httpUtil.getBadRequest("Agree Call:\n" + e.getMessage());
response = httpUtil.getInternalError("Failed to agree in the contract policy: " + e.getMessage());
return httpUtil.buildResponse(response, httpResponse);
}
int retry = 1;
Expand All @@ -239,7 +252,7 @@ public Response singleApi(@Valid @RequestBody SingleApiRequest singleApiRequestB
++retry;
ThreadUtil.sleep(singleApiConfig.getDelay());
} catch (Exception e) {
response = httpUtil.getBadRequest("Status Call:\n" + e.getMessage());
response = httpUtil.getBadRequest("Failed to look for process status: " + e.getMessage());
return httpUtil.buildResponse(response, httpResponse);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ public void searchEndpoint(String processId, String bpn, String endpoint) {
throw new ManagerException("DtrSearchManager.searchEndpoint", "There was no valid policy available for the digital twin registry found!");
}

LogUtil.printMessage("[DTR-AUTO-NEGOTIATION] [PROCESS "+processId + "] Selected [CONTRACT "+contractAndPolicy.d().getId()+"]:["+this.jsonUtil.toJson(contractAndPolicy.d(), false)+"]!");
LogUtil.printMessage("[DTR-AUTO-NEGOTIATION] [PROCESS "+processId + "] Selected [POLICY "+contractAndPolicy.s().getId()+"]:["+this.jsonUtil.toJson(contractAndPolicy.s(), false)+"]!");

Thread singleOfferThread = ThreadUtil.runThread(createAndSaveDtr(contractAndPolicy, datasets, bpn, providerBpn, endpoint, processId), "CreateAndSaveDtr-" + processId + "-" + bpn + "-" + endpoint);
try {
if (!singleOfferThread.join(Duration.ofSeconds(this.dtrRequestProcessTimeout))) {
Expand All @@ -284,6 +287,8 @@ public void searchEndpoint(String processId, String bpn, String endpoint) {
if (contractAndPolicy == null) {
throw new ManagerException("DtrSearchManager.searchEndpoint", "There was no valid policy available for the digital twin registry found!");
}
LogUtil.printMessage("[DTR-AUTO-NEGOTIATION] [PROCESS "+processId + "] Selected [CONTRACT "+contractAndPolicy.d().getId()+"]:["+this.jsonUtil.toJson(contractAndPolicy.d(), false)+"]!");
LogUtil.printMessage("[DTR-AUTO-NEGOTIATION] [PROCESS "+processId + "] Selected [POLICY "+contractAndPolicy.s().getId()+"]:["+this.jsonUtil.toJson(contractAndPolicy.s(), false)+"]!");
// Store datasets in the digital twin logs
contractOfferList.parallelStream().forEach(dataset -> {
Thread multipleOffersThread = ThreadUtil.runThread(createAndSaveDtr(contractAndPolicy, datasets, bpn, providerBpn, endpoint, processId), "CreateAndSaveDtr-" + processId + "-" + bpn + "-" + endpoint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class SingleApiRequest {
@JsonProperty(value="discoveryIdType", defaultValue = "manufacturerPartId")
String discoveryIdType;

@JsonProperty("children")
@JsonProperty(value="children", defaultValue = "false")
Boolean children;

@JsonProperty("semanticId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,11 +520,16 @@ public Response doContractAgreement(HttpServletRequest httpRequest, HttpServletR
String policyId = tokenRequestBody.getPolicyId();
Set policy = null;
DataTransferService.NegotiateContract contractNegotiation = null;
policy = policyUtil.getPolicyById(dataset, policyId);
// This function will always get a complaint policy from the allowed ones
policy = policyUtil.getCompliantPolicyById(dataset, policyId, passportConfig.getPolicyCheck());
if (policy == null) {
response = httpUtil.getBadRequest("The policy selected does not exists!");
response = httpUtil.getBadRequest("The policy selected is not allowed per configuration or does not exists!");
return httpUtil.buildResponse(response, httpResponse);
}

LogUtil.printMessage("[ASSET"+(policyId == null?"-":"-AUTO-")+"NEGOTIATION] [PROCESS "+processId + "] Selected [POLICY "+policy.getId()+"]:["+this.jsonUtil.toJson(policy, false)+"]!");
LogUtil.printMessage("[ASSET-NEGOTIATION] [PROCESS "+processId + "] Selected [POLICY "+policy.getId()+"]:["+this.jsonUtil.toJson(policy, false)+"]!");

contractNegotiation = dataService
.new NegotiateContract(
processManager.loadDataModel(httpRequest),
Expand Down
90 changes: 86 additions & 4 deletions dpp-backend/digitalproductpass/src/main/java/utils/PolicyUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@
import org.springframework.stereotype.Component;
import utils.exceptions.UtilException;

import java.util.ArrayList;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
Expand Down Expand Up @@ -86,6 +85,7 @@ public Set getPolicyById(Dataset dataset, String policyId) {
if (rawPolicy == null) {
return null;
}

Set policy = null;
// If the policy is an object
if (rawPolicy instanceof LinkedHashMap) {
Expand All @@ -110,6 +110,88 @@ public Set getPolicyById(Dataset dataset, String policyId) {

return policy;
}
/**
* Gets a specific policy from a dataset by id
* <p>
*
* @param dataset the {@code Dataset} object of data set contained in the catalog
* @param policyId {@code String} the id of the policy to get
* @param policyConfig {@code PolicyCheckConfig} the policy configuration
* @return Set of policy if found or null otherwise.
*/
public Set getCompliantPolicyById(Dataset dataset, String policyId, PolicyCheckConfig policyConfig) {
// If the policy check is disabled get the policy from all the contract available policies
if(!policyConfig.getEnabled()){
return this.getPolicyById(dataset,policyId);
}

Object rawPolicies = dataset.getPolicy();
// If the policy is not available
if (rawPolicies == null) {
return null;
}

// Get all the valid policies for this contract
Map<String, Set> policies = this.getValidPolicyMapByConstraints(rawPolicies, policyConfig);

java.util.Set<String> keys = policies.keySet();

if(keys.size() == 0){
return null; // No valid policies available for this contract
}

// If policy id is not specified find any compliant policy in the contract
if(policyId == null){
policyId = keys.stream().findAny().orElse(null);
}

if(!policies.containsKey(policyId)){
return null; // Policy does not exists;
}
return policies.get(policyId);
}

/**
* Gets a specific policy from a dataset by constraint
* <p>
*
* @param policies the {@code Object} object of with one or more policies
* @param policyCheckConfigs {@code List<PolicyConfig>} list of constraints for the permissions
* @return Map of of valid policies for constraints by id or null if the policy or policies are not valid.
*/
public Map<String, Set> getValidPolicyMapByConstraints(Object policies, PolicyCheckConfig policyCheckConfigs) {
// Find if policy is array or object and call the evaluate functions
try {
// If the policy is not available
if (policies == null || policyCheckConfigs == null) {
return null;
}
// Generate configuration policies
List<PolicyConfig> policyConfigs = policyCheckConfigs.getPolicies();
List<Set> validPolicies = this.buildPolicies(policyConfigs);

Boolean strictMode = policyCheckConfigs.getStrictMode();
// There is no valid policy available
if (validPolicies == null || validPolicies.size() == 0) {
return null;
}
if (policies instanceof LinkedHashMap) {
// Check if policy is valid or not
Set policy = Set.build(policies);
// In case the policy is valid return the policy
if(this.isPolicyValid(policy, validPolicies, strictMode)){
return new HashMap<>(){{put(policy.getId(), policy);}}; // Add policy to a list of valid policies
}
// If the policy is not valid return an empty list
return new HashMap<>();
}
List<Set> policyList = this.parsePolicies(policies);
//Search for policies that are valid and get one of the valid ones
return policyList.stream().parallel().filter(p -> this.isPolicyValid(p, validPolicies, strictMode)).collect(Collectors.toMap(Set::getId, Function.identity()));
}catch (Exception e) {
throw new UtilException(PolicyUtil.class, "It was not possible to get policy by constraints!");
}
}

/**
* Gets a specific policy from a dataset by constraint
Expand Down

0 comments on commit 5cce456

Please sign in to comment.