package com.evolveum.midpoint.repo.sql.util;
import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PolicyConstraintsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.cxf.common.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* @author lazyman
*/
public class PrismIdentifierGenerator {
public enum Operation {ADD, ADD_WITH_OVERWRITE, MODIFY}
/**
* Method inserts id for prism container values, which didn't have ids,
* also returns all container values which has generated id
*/
public IdGeneratorResult generate(@NotNull PrismObject object, @NotNull Operation operation) {
IdGeneratorResult result = new IdGeneratorResult();
boolean adding = Operation.ADD.equals(operation);
result.setGeneratedOid(adding);
if (StringUtils.isEmpty(object.getOid())) {
String oid = UUID.randomUUID().toString();
object.setOid(oid);
result.setGeneratedOid(true);
}
generateContainerIds(getContainersToGenerateIdsFor(object), result, operation);
return result;
}
private void generateContainerIds(List<PrismContainer<?>> containers, IdGeneratorResult result, Operation operation) {
Set<Long> usedIds = new HashSet<>();
for (PrismContainer<?> c : containers) {
for (PrismContainerValue<?> val : c.getValues()) {
if (val.getId() != null) {
usedIds.add(val.getId());
}
}
}
Long nextId = 1L;
for (PrismContainer<?> c : containers) {
for (PrismContainerValue<?> val : c.getValues()) {
if (val.getId() != null) {
if (operation == Operation.ADD) {
result.getValues().add(val);
}
} else {
while (usedIds.contains(nextId)) {
nextId++;
}
val.setId(nextId);
usedIds.add(nextId);
if (operation == Operation.ADD) {
result.getValues().add(val);
}
}
}
}
}
// TODO: This seems to be wrong. We want to generate IDs for all multivalue containers
// This is maybe some historic code. It has to be cleaned up.
// MID-3869
private List<PrismContainer<?>> getContainersToGenerateIdsFor(PrismObject parent) {
List<PrismContainer<?>> containers = new ArrayList<>();
if (ObjectType.class.isAssignableFrom(parent.getCompileTimeClass())) {
CollectionUtils.addIgnoreNull(containers, parent.findContainer(ObjectType.F_TRIGGER));
CollectionUtils.addIgnoreNull(containers, parent.findContainer(ObjectType.F_OPERATION_EXECUTION));
}
if (LookupTableType.class.isAssignableFrom(parent.getCompileTimeClass())) {
CollectionUtils.addIgnoreNull(containers, parent.findContainer(LookupTableType.F_ROW));
}
if (AccessCertificationCampaignType.class.isAssignableFrom(parent.getCompileTimeClass())) {
PrismContainer<?> caseContainer = parent.findContainer(AccessCertificationCampaignType.F_CASE);
CollectionUtils.addIgnoreNull(containers, caseContainer);
if (caseContainer != null) {
for (PrismContainerValue<?> casePcv : caseContainer.getValues()) {
CollectionUtils.addIgnoreNull(containers, casePcv.findContainer(AccessCertificationCaseType.F_WORK_ITEM));
}
}
CollectionUtils.addIgnoreNull(containers, parent.findContainer(AccessCertificationCampaignType.F_STAGE));
}
if (FocusType.class.isAssignableFrom(parent.getCompileTimeClass())) {
CollectionUtils.addIgnoreNull(containers, parent.findContainer(FocusType.F_ASSIGNMENT));
}
if (AbstractRoleType.class.isAssignableFrom(parent.getCompileTimeClass())) {
CollectionUtils.addIgnoreNull(containers, parent.findContainer(AbstractRoleType.F_INDUCEMENT));
CollectionUtils.addIgnoreNull(containers, parent.findContainer(AbstractRoleType.F_EXCLUSION));
CollectionUtils.addIgnoreNull(containers, parent.findContainer(AbstractRoleType.F_AUTHORIZATION));
PrismContainer policyConstraints = parent.findContainer(AbstractRoleType.F_POLICY_CONSTRAINTS);
if (policyConstraints != null){
CollectionUtils.addIgnoreNull(containers, policyConstraints.findContainer(PolicyConstraintsType.F_MAX_ASSIGNEES));
CollectionUtils.addIgnoreNull(containers, policyConstraints.findContainer(PolicyConstraintsType.F_MIN_ASSIGNEES));
}
}
if (ShadowType.class.isAssignableFrom(parent.getCompileTimeClass())) {
CollectionUtils.addIgnoreNull(containers, parent.findContainer(ShadowType.F_PENDING_OPERATION));
}
if (ResourceType.class.isAssignableFrom(parent.getCompileTimeClass())) {
CollectionUtils.addIgnoreNull(containers, parent.findContainer(ResourceType.F_ADDITIONAL_CONNECTOR));
}
return containers;
}
public IdGeneratorResult generate(Containerable containerable, Operation operation) {
IdGeneratorResult result = new IdGeneratorResult();
if (!(containerable instanceof AccessCertificationCaseType)) {
return result;
}
AccessCertificationCaseType aCase = (AccessCertificationCaseType) containerable;
List<PrismContainer<?>> containers = new ArrayList<>();
CollectionUtils.addIgnoreNull(containers, aCase.asPrismContainerValue().findContainer(AccessCertificationCaseType.F_WORK_ITEM));
generateContainerIds(containers, result, operation);
return result;
}
}