/*
* Copyright (c) 2010-2015 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.wf.impl.processes.itemApproval;
import com.evolveum.midpoint.model.common.expression.ExpressionVariables;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.WfContextUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.DOMUtil;
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.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.wf.impl.processes.common.*;
import com.evolveum.midpoint.wf.util.ApprovalUtils;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import java.util.*;
import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.*;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelOutcomeType.APPROVE;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelOutcomeType.REJECT;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelOutcomeType.SKIP;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.AutomatedCompletionReasonType.AUTO_COMPLETION_CONDITION;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.AutomatedCompletionReasonType.NO_ASSIGNEES_FOUND;
/**
* @author mederly
*/
public class InitializeLoopThroughApproversInStage implements JavaDelegate {
private static final Trace LOGGER = TraceManager.getTrace(InitializeLoopThroughApproversInStage.class);
public void execute(DelegateExecution execution) {
PrismContext prismContext = getPrismContext();
WfExpressionEvaluationHelper evaluationHelper = SpringApplicationContextHolder.getExpressionEvaluationHelper();
LOGGER.trace("Executing the delegate; execution = {}", execution);
OperationResult opResult = new OperationResult(InitializeLoopThroughApproversInStage.class.getName() + ".execute");
Task opTask = getTaskManager().createTaskInstance();
Task wfTask = ActivitiUtil.getTask(execution, opResult);
ApprovalStageDefinitionType stageDef = ActivitiUtil.getAndVerifyCurrentStage(execution, wfTask, false, prismContext);
int stageNumber = stageDef.getNumber();
opTask.setChannel(wfTask.getChannel());
ExpressionVariables expressionVariables = null;
ApprovalLevelOutcomeType predeterminedOutcome = null;
if (stageDef.getAutomaticallyApproved() != null) {
try {
expressionVariables = evaluationHelper.getDefaultVariables(execution, wfTask, opResult);
boolean preApproved = evaluationHelper.evaluateBooleanExpression(stageDef.getAutomaticallyApproved(), expressionVariables,
"automatic approval expression", opTask, opResult);
LOGGER.trace("Pre-approved = {} for stage {}", preApproved, stageDef);
if (preApproved) {
predeterminedOutcome = APPROVE;
recordAutoCompletionDecision(wfTask.getOid(), APPROVE, AUTO_COMPLETION_CONDITION, stageNumber, opResult);
}
} catch (Exception e) { // todo
throw new SystemException("Couldn't evaluate auto-approval expression", e);
}
}
if (predeterminedOutcome == null && stageDef.getAutomaticallyCompleted() != null) {
try {
if (expressionVariables == null) {
expressionVariables = evaluationHelper.getDefaultVariables(execution, wfTask, opResult);
}
List<String> outcomes = evaluationHelper.evaluateExpression(stageDef.getAutomaticallyCompleted(), expressionVariables,
"automatic completion expression", String.class,
DOMUtil.XSD_STRING, WfExpressionEvaluationHelper.createOutcomeConvertor(), opTask, opResult);
LOGGER.trace("Pre-completed = {} for stage {}", outcomes, stageDef);
Set<String> distinctOutcomes = new HashSet<>(outcomes);
if (distinctOutcomes.size() > 1) {
throw new IllegalStateException("Ambiguous result from 'automatically completed' expression: " + distinctOutcomes);
} else if (!distinctOutcomes.isEmpty()) {
predeterminedOutcome = ApprovalUtils.approvalLevelOutcomeFromUri(distinctOutcomes.iterator().next());
if (predeterminedOutcome != null && predeterminedOutcome != SKIP) {
recordAutoCompletionDecision(wfTask.getOid(), predeterminedOutcome, AUTO_COMPLETION_CONDITION,
stageNumber, opResult);
}
}
} catch (Exception e) { // todo
throw new SystemException("Couldn't evaluate auto-approval expression", e);
}
}
Set<ObjectReferenceType> approverRefs = new HashSet<>();
if (predeterminedOutcome == null) {
approverRefs.addAll(CloneUtil.cloneCollectionMembers(stageDef.getApproverRef()));
if (!stageDef.getApproverExpression().isEmpty()) {
try {
if (expressionVariables == null) {
expressionVariables = evaluationHelper.getDefaultVariables(execution, wfTask, opResult);
}
approverRefs.addAll(evaluationHelper.evaluateRefExpressions(stageDef.getApproverExpression(), expressionVariables,
"resolving approver expression", opTask, opResult));
} catch (ExpressionEvaluationException|ObjectNotFoundException|SchemaException|RuntimeException e) {
throw new SystemException("Couldn't evaluate approvers expressions", e);
}
}
LOGGER.trace("Approvers at the stage {} (before potential group expansion) are: {}", stageDef, approverRefs);
if (stageDef.getGroupExpansion() == GroupExpansionType.ON_WORK_ITEM_CREATION) {
approverRefs = MidpointUtil.expandGroups(approverRefs);
LOGGER.trace("Approvers at the stage {} (after group expansion) are: {}", stageDef, approverRefs);
}
if (approverRefs.isEmpty()) {
LOGGER.debug("No approvers at the stage '{}' for process {} (id {}) - response is {}", stageDef.getName(),
execution.getVariable(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME),
execution.getProcessInstanceId(), stageDef.getOutcomeIfNoApprovers());
predeterminedOutcome = stageDef.getOutcomeIfNoApprovers();
switch (predeterminedOutcome) {
case APPROVE:
recordAutoCompletionDecision(wfTask.getOid(), APPROVE, NO_ASSIGNEES_FOUND, stageNumber, opResult);
break;
case REJECT:
recordAutoCompletionDecision(wfTask.getOid(), REJECT, NO_ASSIGNEES_FOUND, stageNumber, opResult);
break;
case SKIP:
// do nothing, just silently skip the stage
break;
default:
throw new IllegalStateException("Unexpected outcome: " + stageDef.getOutcomeIfNoApprovers() + " in " + stageDef);
}
}
}
Boolean stop;
if (predeterminedOutcome != null) {
stop = Boolean.TRUE;
} else {
stop = Boolean.FALSE;
}
execution.setVariable(CommonProcessVariableNames.VARIABLE_STAGE_NUMBER, stageNumber);
execution.setVariable(CommonProcessVariableNames.VARIABLE_STAGE_NAME, stageDef.getName());
execution.setVariable(CommonProcessVariableNames.VARIABLE_STAGE_DISPLAY_NAME, stageDef.getDisplayName());
execution.setVariableLocal(ProcessVariableNames.APPROVERS_IN_STAGE, ActivitiUtil.toLightweightReferences(approverRefs));
execution.setVariableLocal(ProcessVariableNames.LOOP_APPROVERS_IN_STAGE_STOP, stop);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Approval process instance {} (id {}), stage {}: predetermined outcome: {}, approvers: {}",
execution.getVariable(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME),
execution.getProcessInstanceId(),
WfContextUtil.getStageDiagName(stageDef), predeterminedOutcome, approverRefs);
}
getActivitiInterface().notifyMidpointAboutProcessEvent(execution); // store stage information in midPoint task
}
private void recordAutoCompletionDecision(String taskOid, ApprovalLevelOutcomeType outcome,
AutomatedCompletionReasonType reason, int stageNumber, OperationResult opResult) {
StageCompletionEventType event = new StageCompletionEventType();
event.setTimestamp(XmlTypeConverter.createXMLGregorianCalendar(new Date()));
event.setStageNumber(stageNumber);
//event.setStageName(level.getName());
//event.setStageDisplayName(level.getDisplayName());
event.setAutomatedDecisionReason(reason);
event.setOutcome(ApprovalUtils.toUri(outcome));
MidpointUtil.recordEventInTask(event, null, taskOid, opResult);
}
}