Skip to content

Commit

Permalink
Fix execution constraints for approval tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Jun 10, 2019
1 parent 18f43ed commit 2e29471
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 1 deletion.
Expand Up @@ -92,6 +92,8 @@ public interface PrismContainer<C extends Containerable>

<T> void setPropertyRealValue(QName propertyName, T realValue) throws SchemaException;

<C extends Containerable> void setContainerRealValue(QName containerName, C realValue) throws SchemaException;

<T> void setPropertyRealValues(QName propertyName, T... realValues) throws SchemaException;

<T> T getPropertyRealValue(ItemPath propertyPath, Class<T> type);
Expand Down
Expand Up @@ -250,6 +250,17 @@ public <T> void setPropertyRealValue(QName propertyName, T realValue) throws Sch
property.setRealValue(realValue);
}

public <X extends Containerable> void setContainerRealValue(QName itemName, X realValue) throws SchemaException {
checkMutability();
if (realValue != null) {
PrismContainer<Containerable> container = findOrCreateContainer(ItemName.fromQName(itemName));
//noinspection unchecked
container.setValue(realValue.asPrismContainerValue());
} else {
removeContainer(ItemName.fromQName(itemName));
}
}

public <T> void setPropertyRealValues(QName propertyName, T... realValues) throws SchemaException {
checkMutability();
PrismProperty<T> property = findOrCreateProperty(ItemName.fromQName(propertyName));
Expand Down
Expand Up @@ -17,16 +17,19 @@
package com.evolveum.midpoint.wf.impl.execution;

import com.evolveum.midpoint.common.Clock;
import com.evolveum.midpoint.model.common.SystemObjectCache;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.repo.api.PreconditionViolationException;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.SearchResultList;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.CaseTypeUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
Expand All @@ -48,6 +51,8 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.xml.datatype.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -75,6 +80,10 @@ public class ExecutionHelper {
@Autowired public ExpressionEvaluationHelper expressionEvaluationHelper;
@Autowired public WorkItemHelper workItemHelper;
@Autowired public AuthorizationHelper authorizationHelper;
@Autowired private SystemObjectCache systemObjectCache;

private static final String DEFAULT_EXECUTION_GROUP_PREFIX_FOR_SERIALIZATION = "$approval-task-group$:";
private static final long DEFAULT_SERIALIZATION_RETRY_TIME = 10000L;

public void closeCaseInRepository(CaseType aCase, OperationResult result)
throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException {
Expand Down Expand Up @@ -146,4 +155,83 @@ public void checkDependentCases(String rootOid, OperationResult result)
}
}
}

public void setExecutionConstraints(Task task, CaseType aCase, OperationResult result) throws SchemaException {
PrismObject<SystemConfigurationType> systemConfiguration = systemObjectCache.getSystemConfiguration(result);
WfConfigurationType wfConfiguration = systemConfiguration != null ? systemConfiguration.asObjectable().getWorkflowConfiguration() : null;
WfExecutionTasksConfigurationType tasksConfig = wfConfiguration != null ? wfConfiguration.getExecutionTasks() : null;
if (tasksConfig != null) {
// execution constraints
TaskExecutionConstraintsType constraints = tasksConfig.getExecutionConstraints();
if (constraints != null) {
task.setExecutionConstraints(constraints.clone());
}
// serialization
WfExecutionTasksSerializationType serialization = tasksConfig.getSerialization();
if (serialization != null && !Boolean.FALSE.equals(serialization.isEnabled())) {
List<WfExecutionTasksSerializationScopeType> scopes = new ArrayList<>(serialization.getScope());
if (scopes.isEmpty()) {
scopes.add(WfExecutionTasksSerializationScopeType.OBJECT);
}
List<String> groups = new ArrayList<>(scopes.size());
for (WfExecutionTasksSerializationScopeType scope : scopes) {
String groupPrefix = serialization.getGroupPrefix() != null
? serialization.getGroupPrefix() : DEFAULT_EXECUTION_GROUP_PREFIX_FOR_SERIALIZATION;
String groupSuffix = getGroupSuffix(scope, aCase, task);
if (groupSuffix == null) {
continue;
}
groups.add(groupPrefix + scope.value() + ":" + groupSuffix);
}
if (!groups.isEmpty()) {
Duration retryAfter;
if (serialization.getRetryAfter() != null) {
if (constraints != null && constraints.getRetryAfter() != null && !constraints.getRetryAfter()
.equals(serialization.getRetryAfter())) {
LOGGER.warn(
"Workflow configuration: task constraints retryAfter ({}) is different from serialization retryAfter ({}) -- using the latter",
constraints.getRetryAfter(), serialization.getRetryAfter());
}
retryAfter = serialization.getRetryAfter();
} else if (constraints != null && constraints.getRetryAfter() != null) {
retryAfter = constraints.getRetryAfter();
} else {
retryAfter = XmlTypeConverter.createDuration(DEFAULT_SERIALIZATION_RETRY_TIME);
}
TaskExecutionConstraintsType executionConstraints = task.getExecutionConstraints();
if (executionConstraints == null) {
executionConstraints = new TaskExecutionConstraintsType();
task.setExecutionConstraints(executionConstraints);
}
for (String group : groups) {
executionConstraints
.beginSecondaryGroup()
.group(group)
.groupTaskLimit(1);
}
executionConstraints.setRetryAfter(retryAfter);
LOGGER.trace("Setting groups {} with a limit of 1 for task {}", groups, task);
}
}
}
}

private String getGroupSuffix(WfExecutionTasksSerializationScopeType scope, CaseType aCase, Task task) {
switch (scope) {
case GLOBAL: return "";
case OBJECT:
String oid = aCase.getObjectRef() != null ? aCase.getObjectRef().getOid() : null;
if (oid == null) {
LOGGER.warn("No object OID present, synchronization with the scope of {} couldn't be set up for task {}", scope, task);
return null;
}
return oid;
case TARGET:
return aCase.getTargetRef() != null ? aCase.getTargetRef().getOid() : null; // null can occur so let's be silent then
case OPERATION:
return aCase.getParentRef() != null ? aCase.getParentRef().getOid() : aCase.getOid();
default:
throw new AssertionError("Unknown scope: " + scope);
}
}
}
Expand Up @@ -479,6 +479,7 @@ private void submitExecutionTask(CaseType aCase, boolean waiting, OperationResul
if (waiting) {
task.setInitialExecutionStatus(TaskExecutionStatus.WAITING);
}
executionHelper.setExecutionConstraints(task, aCase, result);
taskManager.switchToBackground(task, result);
}

Expand Down
Expand Up @@ -841,4 +841,8 @@ public ObjectReferenceType getOwnerRef() {
public Collection<String> getCachingProfiles() {
return emptySet();
}

@Override
public void setExecutionConstraints(TaskExecutionConstraintsType value) {
}
}
Expand Up @@ -308,6 +308,8 @@ void setNameImmediate(PolyStringType value, OperationResult parentResult)

TaskExecutionConstraintsType getExecutionConstraints();

void setExecutionConstraints(TaskExecutionConstraintsType value);

String getGroup();

@NotNull
Expand Down
Expand Up @@ -419,7 +419,14 @@ <X> PropertyDelta<X> createPropertyDeltaIfPersistent(ItemName name, X value) {
}

@Nullable
ReferenceDelta createReferenceDeltaIfPersistent(ItemName name, ObjectReferenceType value) {
private <X extends Containerable> ContainerDelta<X> createContainerDeltaIfPersistent(ItemName name, X value)
throws SchemaException {
return isPersistent() ?
deltaFactory().container().createModificationReplace(name, TaskType.class, value) : null;
}

@Nullable
private ReferenceDelta createReferenceDeltaIfPersistent(ItemName name, ObjectReferenceType value) {
return isPersistent() ? deltaFactory().reference().createModificationReplace(name,
taskManager.getTaskObjectDefinition(), value != null ? value.clone().asReferenceValue() : null) : null;
}
Expand All @@ -442,6 +449,14 @@ private <X> void setProperty(ItemName name, X value) {
addPendingModification(setPropertyAndCreateDeltaIfPersistent(name, value));
}

private <X extends Containerable> void setContainer(ItemName name, X value) {
try {
addPendingModification(setContainerAndCreateDeltaIfPersistent(name, value));
} catch (SchemaException e) {
throw new SystemException("Couldn't set the task container '" + name + "': " + e.getMessage(), e);
}
}

private <X> void setPropertyTransient(ItemName name, X value) {
synchronized (PRISM_ACCESS) {
try {
Expand All @@ -452,6 +467,16 @@ private <X> void setPropertyTransient(ItemName name, X value) {
}
}

private <X extends Containerable> void setContainerTransient(ItemName name, X value) {
synchronized (PRISM_ACCESS) {
try {
taskPrism.setContainerRealValue(name, value);
} catch (SchemaException e) {
throw new SystemException("Couldn't set the task property '" + name + "': " + e.getMessage(), e);
}
}
}

private <X> void setPropertyImmediate(ItemName name, X value, OperationResult result)
throws SchemaException, ObjectNotFoundException {
try {
Expand All @@ -467,6 +492,12 @@ private <X> PropertyDelta<X> setPropertyAndCreateDeltaIfPersistent(ItemName name
return createPropertyDeltaIfPersistent(name, value);
}

private <X extends Containerable> ContainerDelta<X> setContainerAndCreateDeltaIfPersistent(ItemName name, X value)
throws SchemaException {
setContainerTransient(name, value);
return createContainerDeltaIfPersistent(name, value);
}

private PrismReferenceValue getReferenceValue(ItemName name) {
synchronized (PRISM_ACCESS) {
PrismReference reference = taskPrism.findReference(name);
Expand Down Expand Up @@ -1141,6 +1172,11 @@ public TaskExecutionConstraintsType getExecutionConstraints() {
}
}

@Override
public void setExecutionConstraints(TaskExecutionConstraintsType value) {
setContainer(TaskType.F_EXECUTION_CONSTRAINTS, value);
}

@Override
public String getGroup() {
synchronized (PRISM_ACCESS) {
Expand Down

0 comments on commit 2e29471

Please sign in to comment.