Skip to content

Commit

Permalink
Dynamically-resolvable approvers (except for abstractRole.approverRef…
Browse files Browse the repository at this point in the history
… item). Configurable outcome if no approvers.
  • Loading branch information
mederly committed Jan 13, 2017
1 parent f3f68a2 commit 6585702
Show file tree
Hide file tree
Showing 30 changed files with 421 additions and 162 deletions.
Expand Up @@ -8634,6 +8634,14 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="outcomeIfNoApprovers" type="c:ApprovalLevelOutcomeType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
What is the outcome (of this level) if there are no approvers? E.g. there are no users that have
been assigned a role as an approver; or a user has no managers, etc.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="automaticallyApproved" type="c:ExpressionType" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Expand All @@ -8645,7 +8653,40 @@
</xsd:sequence>
</xsd:complexType>

<xsd:simpleType name="LevelEvaluationStrategyType">
<xsd:simpleType name="ApprovalLevelOutcomeType">
<xsd:annotation>
<xsd:documentation>
Result (outcome) of an approval process level.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumClass/>
</xsd:appinfo>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="approve">
<xsd:annotation>
<xsd:documentation>
Operation was approved at this level. The approval process will continue at the next level.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="APPROVE"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="reject">
<xsd:annotation>
<xsd:documentation>
Operation was rejected at this level. The approval process will stop.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="REJECT"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="LevelEvaluationStrategyType">
<xsd:annotation>
<xsd:documentation>
Enumeration of approval strategies at a particular level.
Expand Down
Expand Up @@ -178,7 +178,8 @@ private static void applyVisitorToValues(Collection<? extends PrismValue> values
private static void resolveRef(PrismReferenceValue refVal, RepositoryService repository,
boolean enforceReferentialIntegrity, boolean forceFilterReevaluation, EvaluationTimeType evaluationTimeType,
PrismContext prismContext, String contextDesc, boolean throwExceptionOnFailure, OperationResult parentResult) {
QName refName = refVal.getParent().getElementName();
String refName = refVal.getParent() != null ?
refVal.getParent().getElementName().toString() : "(unnamed)";

if ((refVal.getResolutionTime() != null && refVal.getResolutionTime() != evaluationTimeType) ||
(refVal.getResolutionTime() == null && evaluationTimeType != EvaluationTimeType.IMPORT)) {
Expand Down
Expand Up @@ -18,6 +18,7 @@

import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRef;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelOutcomeType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LevelEvaluationStrategyType;
Expand All @@ -40,6 +41,8 @@ public interface ApprovalLevel {

ExpressionType getAutomaticallyApproved();

ApprovalLevelOutcomeType getOutcomeIfNoApprovers();

PrismContext getPrismContext();

void setPrismContext(PrismContext prismContext);
Expand Down
Expand Up @@ -17,16 +17,18 @@
package com.evolveum.midpoint.wf.impl.processes.itemApproval;

import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRef;
import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRefImpl;
import com.evolveum.midpoint.wf.impl.util.SerializationSafeContainer;
import com.evolveum.midpoint.wf.impl.util.SingleItemSerializationSafeContainerImpl;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LevelEvaluationStrategyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;

import java.io.Serializable;
import java.util.ArrayList;
Expand All @@ -47,11 +49,12 @@ public class ApprovalLevelImpl implements ApprovalLevel, Serializable {
private List<SerializationSafeContainer<ExpressionType>> approverExpressions = new ArrayList<>();
private LevelEvaluationStrategyType evaluationStrategy;
private SerializationSafeContainer<ExpressionType> automaticallyApproved;
@NotNull private final ApprovalLevelOutcomeType outcomeIfNoApprovers;

private transient PrismContext prismContext;

public ApprovalLevelImpl(ApprovalLevelType levelType, PrismContext prismContext,
RelationResolver relationResolver) {
ApprovalLevelImpl(ApprovalLevelType levelType, PrismContext prismContext,
RelationResolver relationResolver, ReferenceResolver referenceResolver) {

Validate.notNull(prismContext, "prismContext must not be null");

Expand All @@ -61,15 +64,18 @@ public ApprovalLevelImpl(ApprovalLevelType levelType, PrismContext prismContext,

setPrismContext(prismContext);

levelType.getApproverRef().forEach(this::addApproverRef);
relationResolver.getApprovers(levelType.getApproverRelation()).forEach(this::addApproverRef);
levelType.getApproverRef().forEach(ref -> addApproverRef(referenceResolver, ref));
relationResolver.getApprovers(levelType.getApproverRelation()).forEach(this::addResolvedApproverRef);
levelType.getApproverExpression().forEach(this::addApproverExpression);
this.evaluationStrategy = levelType.getEvaluationStrategy();
setAutomaticallyApproved(levelType.getAutomaticallyApproved());
outcomeIfNoApprovers = resolveDefault(levelType.getOutcomeIfNoApprovers());
}

//default: all approvers in one level, evaluation strategy = allMustApprove
public ApprovalLevelImpl(List<ObjectReferenceType> approverRefList, List<ExpressionType> approverExpressionList, ExpressionType automaticallyApproved, PrismContext prismContext) {
ApprovalLevelImpl(List<ObjectReferenceType> approverRefList, List<ExpressionType> approverExpressionList,
ExpressionType automaticallyApproved, @NotNull PrismContext prismContext,
@NotNull ReferenceResolver referenceResolver) {

Validate.notNull(prismContext, "prismContext must not be null");

Expand All @@ -78,16 +84,21 @@ public ApprovalLevelImpl(List<ObjectReferenceType> approverRefList, List<Express
order = 0;

if (approverRefList != null) {
approverRefList.forEach(this::addApproverRef);
approverRefList.forEach(ref -> addApproverRef(referenceResolver, ref));
}
if (approverExpressionList != null) {
approverExpressionList.forEach(this::addApproverExpression);
}
setEvaluationStrategy(LevelEvaluationStrategyType.ALL_MUST_AGREE);
setAutomaticallyApproved(automaticallyApproved);
outcomeIfNoApprovers = resolveDefault(null);
}

@Override
private ApprovalLevelOutcomeType resolveDefault(ApprovalLevelOutcomeType value) {
return value != null ? value : ApprovalLevelOutcomeType.REJECT;
}

@Override
public String getName() {
return name;
}
Expand Down Expand Up @@ -146,6 +157,12 @@ public void setAutomaticallyApproved(ExpressionType automaticallyApproved) {
this.automaticallyApproved = new SingleItemSerializationSafeContainerImpl<>(automaticallyApproved, prismContext);
}

@NotNull
@Override
public ApprovalLevelOutcomeType getOutcomeIfNoApprovers() {
return outcomeIfNoApprovers;
}

public int getOrder() {
return order;
}
Expand All @@ -156,7 +173,7 @@ public PrismContext getPrismContext() {
}

@Override
public void setPrismContext(PrismContext prismContext) {
public void setPrismContext(@NotNull PrismContext prismContext) {
this.prismContext = prismContext;
}

Expand All @@ -178,12 +195,20 @@ public ApprovalLevelType toApprovalLevelType(PrismContext prismContext) {
return levelType;
}

public void addApproverRef(ObjectReferenceType approverRef) {
approverRefs.add(new LightweightObjectRefImpl(approverRef));
private void addApproverRef(ReferenceResolver referenceResolver, ObjectReferenceType approverRef) {
try {
referenceResolver.resolveReference(approverRef, toString()).forEach(this::addResolvedApproverRef);
} catch (SchemaException|ObjectNotFoundException|ExpressionEvaluationException e) {
throw new SystemException("Couldn't resolve approverRef in " + this, e);
}
}

private void addResolvedApproverRef(ObjectReferenceType resolvedApproverRef) {
approverRefs.add(new LightweightObjectRefImpl(resolvedApproverRef));
}

public void addApproverExpression(ExpressionType expressionType) {
approverExpressions.add(new SingleItemSerializationSafeContainerImpl<ExpressionType>(expressionType, prismContext));
private void addApproverExpression(ExpressionType expressionType) {
approverExpressions.add(new SingleItemSerializationSafeContainerImpl<>(expressionType, prismContext));
}

@Override
Expand Down
Expand Up @@ -23,6 +23,7 @@
import com.evolveum.midpoint.wf.impl.util.SerializationSafeContainer;
import com.evolveum.midpoint.wf.impl.util.SingleItemSerializationSafeContainerImpl;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.jetbrains.annotations.NotNull;

import java.io.Serializable;
import java.util.List;
Expand All @@ -41,12 +42,12 @@ public class ApprovalRequestImpl<I extends Serializable> implements ApprovalRequ

private ApprovalSchema approvalSchema;

private ApprovalRequestImpl(I itemToApprove, PrismContext prismContext) {
private ApprovalRequestImpl(I itemToApprove, @NotNull PrismContext prismContext) {
setPrismContext(prismContext);
setItemToApprove(itemToApprove);
}

private ApprovalRequestImpl(SerializationSafeContainer wrappedValue, PrismContext prismContext) {
private ApprovalRequestImpl(SerializationSafeContainer wrappedValue, @NotNull PrismContext prismContext) {
setPrismContext(prismContext);
setItemToApprove(wrappedValue);
}
Expand All @@ -56,58 +57,60 @@ private ApprovalRequestImpl(SerializationSafeContainer wrappedValue, PrismContex
// setSchemaFromConfig(config, prismContext);
// }

public ApprovalRequestImpl(I itemToApprove, PcpAspectConfigurationType config, PrismContext prismContext,
RelationResolver relationResolver) {
public ApprovalRequestImpl(I itemToApprove, PcpAspectConfigurationType config, @NotNull PrismContext prismContext,
RelationResolver relationResolver, ReferenceResolver referenceResolver) {
this(itemToApprove, prismContext);
setSchemaFromConfig(config, prismContext, relationResolver);
setSchemaFromConfig(config, prismContext, relationResolver, referenceResolver);
}

protected void setSchemaFromConfig(PcpAspectConfigurationType config, PrismContext prismContext,
RelationResolver relationResolver) {
private void setSchemaFromConfig(PcpAspectConfigurationType config, @NotNull PrismContext prismContext,
RelationResolver relationResolver, ReferenceResolver referenceResolver) {
if (config != null) {
setApprovalSchema(new ApprovalSchemaImpl(config.getApprovalSchema(), config.getApproverRef(),
config.getApproverExpression(), config.getAutomaticallyApproved(), prismContext, relationResolver));
config.getApproverExpression(), config.getAutomaticallyApproved(), prismContext, relationResolver,
referenceResolver));
}
}

public ApprovalRequestImpl(I itemToApprove, ApprovalSchemaType approvalSchema, PrismContext prismContext,
RelationResolver relationResolver) {
public ApprovalRequestImpl(I itemToApprove, ApprovalSchemaType approvalSchema, @NotNull PrismContext prismContext,
RelationResolver relationResolver, ReferenceResolver referenceResolver) {
this(itemToApprove, prismContext);
setApprovalSchema(new ApprovalSchemaImpl(approvalSchema, prismContext, relationResolver));
setApprovalSchema(new ApprovalSchemaImpl(approvalSchema, prismContext, relationResolver, referenceResolver));
}


public ApprovalRequestImpl(SerializationSafeContainer itemToApproveWrapped, PcpAspectConfigurationType config,
ApprovalSchemaType approvalSchema, List<ObjectReferenceType> approverRef,
List<ExpressionType> approverExpression, ExpressionType automaticallyApproved,
PrismContext prismContext, RelationResolver relationResolver) {
ApprovalSchemaType approvalSchema, List<ObjectReferenceType> approverRef,
List<ExpressionType> approverExpression, ExpressionType automaticallyApproved,
@NotNull PrismContext prismContext, RelationResolver relationResolver, ReferenceResolver referenceResolver) {
this(itemToApproveWrapped, prismContext);
setSchemaFromConfigAndParameters(config, approvalSchema, approverRef, approverExpression, automaticallyApproved,
prismContext, relationResolver);
prismContext, relationResolver, referenceResolver);
}

public ApprovalRequestImpl(I itemToApprove, PcpAspectConfigurationType config, ApprovalSchemaType approvalSchema,
List<ObjectReferenceType> approverRef, List<ExpressionType> approverExpression,
ExpressionType automaticallyApproved, PrismContext prismContext,
RelationResolver relationResolver) {
List<ObjectReferenceType> approverRef, List<ExpressionType> approverExpression,
ExpressionType automaticallyApproved, @NotNull PrismContext prismContext,
RelationResolver relationResolver, ReferenceResolver referenceResolver) {
this(itemToApprove, prismContext);
setSchemaFromConfigAndParameters(config, approvalSchema, approverRef, approverExpression, automaticallyApproved,
prismContext, relationResolver);
prismContext, relationResolver, referenceResolver);
}

private void setSchemaFromConfigAndParameters(PcpAspectConfigurationType config, ApprovalSchemaType approvalSchema,
List<ObjectReferenceType> approverRef, List<ExpressionType> approverExpression, ExpressionType automaticallyApproved,
PrismContext prismContext, RelationResolver relationResolver) {
@NotNull PrismContext prismContext, RelationResolver relationResolver, ReferenceResolver referenceResolver) {
if (config != null &&
(!config.getApproverRef().isEmpty() ||
config.getApprovalSchema() != null ||
!config.getApproverExpression().isEmpty() ||
config.getAutomaticallyApproved() != null)) {
setApprovalSchema(new ApprovalSchemaImpl(config.getApprovalSchema(), config.getApproverRef(),
config.getApproverExpression(), config.getAutomaticallyApproved(), prismContext, relationResolver));
config.getApproverExpression(), config.getAutomaticallyApproved(), prismContext,
relationResolver, referenceResolver));
} else {
setApprovalSchema(new ApprovalSchemaImpl(approvalSchema, approverRef,
approverExpression, automaticallyApproved, prismContext, relationResolver));
approverExpression, automaticallyApproved, prismContext, relationResolver, referenceResolver));
}
}

Expand Down
Expand Up @@ -39,32 +39,33 @@ public class ApprovalSchemaImpl implements ApprovalSchema, Serializable {

private transient PrismContext prismContext;

public ApprovalSchemaImpl(ApprovalSchemaType approvalSchemaType, PrismContext prismContext,
RelationResolver relationResolver) {
ApprovalSchemaImpl(ApprovalSchemaType approvalSchemaType, @NotNull PrismContext prismContext,
RelationResolver relationResolver, ReferenceResolver referenceResolver) {
setPrismContext(prismContext);
initFromApprovalSchemaType(approvalSchemaType, relationResolver);
initFromApprovalSchemaType(approvalSchemaType, relationResolver, referenceResolver);
}

public ApprovalSchemaImpl(ApprovalSchemaType approvalSchema, List<ObjectReferenceType> approverRefList,
List<ExpressionType> approverExpressionList, ExpressionType automaticallyApproved,
PrismContext prismContext, RelationResolver relationResolver) {
ApprovalSchemaImpl(ApprovalSchemaType approvalSchema, List<ObjectReferenceType> approverRefList,
List<ExpressionType> approverExpressionList, ExpressionType automaticallyApproved,
@NotNull PrismContext prismContext, RelationResolver relationResolver, ReferenceResolver referenceResolver) {
setPrismContext(prismContext);
if (approvalSchema != null) {
initFromApprovalSchemaType(approvalSchema, relationResolver);
initFromApprovalSchemaType(approvalSchema, relationResolver, referenceResolver);
} else if ((approverRefList != null && !approverRefList.isEmpty()) || (approverExpressionList != null && !approverExpressionList.isEmpty())) {
ApprovalLevelImpl level = new ApprovalLevelImpl(approverRefList, approverExpressionList, automaticallyApproved, prismContext);
ApprovalLevelImpl level = new ApprovalLevelImpl(approverRefList, approverExpressionList,
automaticallyApproved, prismContext, referenceResolver);
addLevel(level);
} else {
throw new IllegalArgumentException("Neither approvalSchema nor approverRef/approverExpression is filled-in");
}
}

private void initFromApprovalSchemaType(ApprovalSchemaType approvalSchemaType,
RelationResolver relationResolver) {
RelationResolver relationResolver, ReferenceResolver referenceResolver) {
this.name = approvalSchemaType.getName();
this.description = approvalSchemaType.getDescription();
for (ApprovalLevelType levelType : approvalSchemaType.getLevel()) {
addLevel(levelType, relationResolver);
addLevel(levelType, relationResolver, referenceResolver);
}
}

Expand Down Expand Up @@ -99,7 +100,7 @@ public PrismContext getPrismContext() {
}

@Override
public void setPrismContext(PrismContext prismContext) {
public void setPrismContext(@NotNull PrismContext prismContext) {
this.prismContext = prismContext;
for (ApprovalLevel approvalLevel : levels) {
approvalLevel.setPrismContext(prismContext);
Expand All @@ -121,12 +122,12 @@ public void toApprovalSchemaType(ApprovalSchemaType approvalSchemaType) {
return ast;
}

public void addLevel(ApprovalLevelImpl level) {
private void addLevel(ApprovalLevelImpl level) {
levels.add(level);
}

public void addLevel(ApprovalLevelType levelType, RelationResolver relationResolver) {
addLevel(new ApprovalLevelImpl(levelType, prismContext, relationResolver));
private void addLevel(ApprovalLevelType levelType, RelationResolver relationResolver, ReferenceResolver referenceResolver) {
addLevel(new ApprovalLevelImpl(levelType, prismContext, relationResolver, referenceResolver));
}

@Override
Expand Down

0 comments on commit 6585702

Please sign in to comment.