Provisioning context is used to optimize provisioning by allowing you to prepare data earlier than in individual attributes. The purpose is to avoid load the same data in multiple attributes.
An example might be the need to compute a value of an attribute based on identity contracts. In such a case, it is possible to load this contracts through the relevant service as part of the transformation into the system. However, a problem can arise if we need these same contracts in the other five attributes. At such a moment, it would mean 4 times unnecessary loading of the same contracts.
The solution to this situation is to use provisioning context, which allows you to load a contracts only once and distribute them to each attribute.
Provisioning context can be defined in two ways. The first is to check the predefined options on detail of mapping, that will fill the predefined context items. It is also possible to insert into the context any other object that we need to propagate. For this purpose, a map is included in the context, where the key is a String item and the value is Object.
The predefined context structure:
The map in the context:
For easy access to the context object, suggestions have been implemented that describe context methods (name, description, return type of the method). These suggestions are used in context scripts, in transformation to the system, and in all scripts that have a 'mapping context' category.
Using the context is very simple. Suppose we want to solve the problem described in the example above. Ie. we need to create a context that will contain all the identity contracts for which provisioning is performed.
.addParameter('context', context)
inside the generated code after you selected the transformation script (this won't be needed after https://redmine.czechidm.com/issues/2564 is resolved)Example of using context. We use all identity contracts from context to check the contract state. If the user has at least one contract valid, the script returns "Valid". If not, then "NotValid".
Script in attribute mapping details:
contracts = context.getContracts() for (def contract : contracts ){ if (contract.isValid()){ return "Valid" } } return "NotValid"
Example of using context. We want one of the attributes to return a list of objects containing the value eav "JobNameEAV" from all user contracts, including contract status information. For example {"JobName": "job1", "State": "true"}, {"JobName": "job2", "State": "false"}
First of all, we must define provisioning context in the mapping of the system:
We will use the following transformation script for the context, which collects all eav values from all user contract:
import eu.bcvsolutions.idm.core.eav.api.dto.IdmFormDefinitionDto; import eu.bcvsolutions.idm.core.api.service.IdmIdentityContractService; import eu.bcvsolutions.idm.core.eav.api.dto.IdmFormInstanceDto; import eu.bcvsolutions.idm.core.api.dto.IdmIdentityContractDto; IdmFormDefinitionDto definition = formService.getDefinition(IdmIdentityContractDto.class, "EAV contract"); //get form definition "EAV contract" def contracts = identityContractService.findAllByIdentity(entity.getId()) // get all intetity contract by identity id def map = new HashMap(); for (contract in contracts) { def form = formService.getFormInstance(contract, definition) // collect all eav values map.put(form.getOwnerId(),form) } context.put("contractFormInstances", map) return context
We use this script in attribute mapping details:
import eu.bcvsolutions.idm.core.eav.api.dto.IdmFormInstanceDto; import eu.bcvsolutions.idm.core.api.dto.IdmIdentityContractDto contracts = context.get("contractFormInstances") def result = new ArrayList(); for( Serializable contractId : contracts.keySet()) { //loop through contracts IdmFormInstanceDto contractFormInstance = contracts.get(contractId); String JobNameEav = (String) contractFormInstance.toSinglePersistentValue("JobNameEAV"); //get eav value def contract = context.getContracts().find{contractId.equals(it.getId())}; //finds the current contract if (JobNameEav){ Map<String,String> map = new HashMap<String,String>(); map.put("JobName", JobNameEav); map.put("State", contract.isValid()); //return true if the current contract is valid result.add(map); } } return result; // return list all objects
Another example of using context. We go through the user's roles in the current system. If the user has at least one of the roles, we will create an email from eav contract value and domain. For example login1@email1.CZ for role wit code "Role1".
Provisioning context in the mapping of the system:
We will use the same transformation script for the context as in the previous example, which collects all eav values from all user contract:
import eu.bcvsolutions.idm.core.eav.api.dto.IdmFormDefinitionDto; import eu.bcvsolutions.idm.core.api.service.IdmIdentityContractService; import eu.bcvsolutions.idm.core.eav.api.dto.IdmFormInstanceDto; import eu.bcvsolutions.idm.core.api.dto.IdmIdentityContractDto; IdmFormDefinitionDto definition = formService.getDefinition(IdmIdentityContractDto.class, "EAV contract"); //get form definition "EAV contract" def contracts = identityContractService.findAllByIdentity(entity.getId()) // get all intetity contract by identity id def map = new HashMap(); for (contract in contracts) { def form = formService.getFormInstance(contract, definition) // collect all eav values map.put(form.getOwnerId(),form) } context.put("contractFormInstances", map) return context
We use this script in attribute mapping details:
import eu.bcvsolutions.idm.core.api.utils.DtoUtils import eu.bcvsolutions.idm.core.api.dto.IdmRoleDto; import eu.bcvsolutions.idm.core.model.entity.IdmIdentityRole_ import eu.bcvsolutions.idm.core.api.dto.IdmIdentityRoleDto import eu.bcvsolutions.idm.core.eav.api.dto.IdmFormInstanceDto; import org.apache.commons.lang3.StringUtils; def contracts = context.get("contractFormInstances") def result = new ArrayList(); def values = new HashSet(); def roles = context.getIdentityRolesForSystem(); /get all identity roles for system def getLogin(contracts, entity, domain, context) { def validContracts = context.getContracts(). findAll {contract -> contract.isValid()} .findAll {contract -> IdmFormInstanceDto contractFormInstance = contracts.get(contract.id) //list of all valid identity contract } for (def validContract : validContracts) { //loop through valid contracts IdmFormInstanceDto contractFormInstance = contracts.get(validContract.id) String login = (String) contractFormInstance.toSinglePersistentValue("EAVlogin");//get eav value if(login){ StringBuilder sb = new StringBuilder(); sb.append(login); sb.append(domain); domainLogin = sb.toString() //merges a string values login and domain } } if(domainLogin){ return domainLogin; } } for (def identityRoleDto : roles ){ //goes through all the roles on the system IdmRoleDto roleDto = DtoUtils.getEmbedded(identityRoleDto, IdmIdentityRole_.role); def roleCode = roleDto.getCode(); //get role code if(roleCode == "Role1"){ values.add(getLoginForCompany(contracts, entity,"@email1.CZ", context)); //adds EAVlogin value with domain "@email1.CZ" to the list, if the user has a role with code "Role1" } else if(roleCode == "Role2"){ values.add(getLoginForCompany(contracts, entity,"@email2.CZ", context)); //adds EAVlogin value with domain "@email2.CZ" to the list, if the user has a role with code "Role2" } else if(roleCode == "Role3"){ values.add(getLoginForCompany(contracts, entity, "@email3.CZ", context));//adds EAVlogin value with domain "@email3.CZ" to the list, if the user has a role with code "Role3" } } if (values) { return values }