/*
* Copyright (c) 2010-2013 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.common;
import com.evolveum.midpoint.model.api.expr.MidpointFunctions;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.schema.util.WfContextUtil;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.task.api.Task;
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.itemApproval.ProcessVariableNames;
import com.evolveum.midpoint.wf.impl.util.MiscDataUtil;
import com.evolveum.midpoint.wf.impl.util.SerializationSafeContainer;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames.*;
import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getMidpointFunctions;
import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getTaskManager;
/**
* General utilities that can be used from within processes.
*
* @author mederly
*/
public class ActivitiUtil implements Serializable {
private static final long serialVersionUID = 5183098710717369392L;
private static final Trace LOGGER = TraceManager.getTrace(ActivitiUtil.class);
@NotNull
public static ApprovalStageDefinitionType getAndVerifyCurrentStage(DelegateExecution execution, Task wfTask, boolean stageInContextSet,
PrismContext prismContext) {
int stageNumber = getRequiredVariable(execution, ProcessVariableNames.STAGE_NUMBER_LOCAL, Integer.class, prismContext);
ApprovalStageDefinitionType stageDefinition;
if (stageInContextSet) {
stageDefinition = WfContextUtil.getCurrentStageDefinition(wfTask.getWorkflowContext());
if (stageDefinition == null) {
throw new IllegalStateException("No current stage information in " + wfTask);
}
} else {
stageDefinition = WfContextUtil.getStageDefinition(wfTask.getWorkflowContext(), stageNumber);
if (stageDefinition == null) {
throw new IllegalStateException("No stage #" + stageNumber + " in " + wfTask);
}
}
return stageDefinition;
}
public PrismContext getPrismContext() {
return SpringApplicationContextHolder.getPrismContext();
}
public void revive(SerializationSafeContainer<?> container) {
container.setPrismContext(SpringApplicationContextHolder.getPrismContext());
}
// todo - better name?
public MidpointFunctions midpoint() {
return getMidpointFunctions();
}
@Override
public String toString() {
return this.getClass().getName() + " object.";
}
@NotNull
public static String getTaskOid(Map<String, Object> variables) {
return ActivitiUtil.getRequiredVariable(variables, CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID, String.class, null);
}
@NotNull
public static Task getTask(DelegateExecution execution, OperationResult result) {
String oid = getTaskOid(execution.getVariables());
try {
return getTaskManager().getTask(oid, result);
} catch (ObjectNotFoundException|SchemaException|RuntimeException e) {
throw new SystemException("Couldn't get task " + oid + " corresponding to process " + execution.getProcessInstanceId(), e);
}
}
@SuppressWarnings("unchecked")
public static <T> T getRequiredVariable(DelegateExecution execution, String name, Class<T> clazz, PrismContext prismContext) {
Object value = getVariable(execution.getVariables(), name, clazz, prismContext);
if (value == null) {
throw new IllegalStateException("Required process variable " + name + " is missing in " + execution);
} else {
return (T) value;
}
}
public static <T> T getRequiredVariable(Map<String, Object> variables, String name, Class<T> clazz, PrismContext prismContext) {
Object value = getVariable(variables, name, clazz, prismContext);
if (value == null) {
throw new IllegalStateException("Required process variable " + name + " is missing");
} else {
return (T) value;
}
}
public static <T> T getVariable(DelegateExecution execution, String name, Class<T> clazz, PrismContext prismContext) {
return getVariable(execution.getVariables(), name, clazz, prismContext);
}
@SuppressWarnings("unchecked")
public static <T> T getVariable(Map<String, Object> variables, String name, Class<T> clazz, PrismContext prismContext) {
Object value = variables.get(name);
if (value instanceof SerializationSafeContainer && !SerializationSafeContainer.class.isAssignableFrom(clazz)) {
SerializationSafeContainer container = (SerializationSafeContainer) value;
if (container.getPrismContext() == null && prismContext != null) {
container.setPrismContext(prismContext);
}
value = container.getValue();
}
if (value != null && !(clazz.isAssignableFrom(value.getClass()))) {
throw new IllegalStateException("Process variable " + name + " should be of " + clazz + " but is of "
+ value.getClass() + " instead.");
} else {
return (T) value;
}
}
public static <T> T getVariable(Map<String, Object> variables, String name, Class<T> clazz) {
return getVariable(variables, name, clazz, null);
}
@NotNull
public static WfContextType getWorkflowContext(Task wfTask) {
if (wfTask == null) {
throw new IllegalArgumentException("No task");
} else if (wfTask.getWorkflowContext() == null) {
throw new IllegalArgumentException("No workflow context in task " + wfTask);
} else {
return wfTask.getWorkflowContext();
}
}
public static List<LightweightObjectRef> toLightweightReferences(Collection<ObjectReferenceType> refs) {
return refs.stream().map(ort -> new LightweightObjectRefImpl(ort)).collect(Collectors.toList());
}
// TODO move to better place (it is called also from WorkItemManager)
// Make sure this does not refer to variables modified in activity db but not in the Java task object
// TODO CLEAN THIS UP!!! (maybe by reading WorkItemType?)
public static void fillInWorkItemEvent(WorkItemEventType event, MidPointPrincipal currentUser, String workItemId,
Map<String, Object> variables, PrismContext prismContext) {
if (currentUser != null) {
event.setInitiatorRef(ObjectTypeUtil.createObjectRef(currentUser.getUser()));
}
event.setTimestamp(XmlTypeConverter.createXMLGregorianCalendar(new Date()));
event.setExternalWorkItemId(workItemId);
String originalAssigneeString = ActivitiUtil.getVariable(variables, VARIABLE_ORIGINAL_ASSIGNEE, String.class, prismContext);
if (originalAssigneeString != null) {
event.setOriginalAssigneeRef(MiscDataUtil.stringToRef(originalAssigneeString));
}
event.setStageNumber(ActivitiUtil.getRequiredVariable(variables, VARIABLE_STAGE_NUMBER, Integer.class, prismContext));
event.setEscalationLevel(WfContextUtil.createEscalationLevel(ActivitiUtil.getEscalationLevelNumber(variables),
ActivitiUtil.getVariable(variables, VARIABLE_ESCALATION_LEVEL_NAME, String.class, prismContext),
ActivitiUtil.getVariable(variables, VARIABLE_ESCALATION_LEVEL_DISPLAY_NAME, String.class, prismContext)));
}
public static int getEscalationLevelNumber(Map<String, Object> variables) {
Integer e = ActivitiUtil.getVariable(variables, VARIABLE_ESCALATION_LEVEL_NUMBER, Integer.class, null);
return e != null ? e : 0;
}
}