/*
* Copyright (c) 2010-2017 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.common.expression.*;
import com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyDefinitionImpl;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.QNameUtil;
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.wf.impl.util.MiscDataUtil;
import com.evolveum.midpoint.wf.util.ApprovalUtils;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelOutcomeType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import org.activiti.engine.delegate.DelegateExecution;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.evolveum.midpoint.schema.constants.SchemaConstants.*;
import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getExpressionFactory;
import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getMiscDataUtil;
/**
* @author mederly
*/
@Component
public class WfExpressionEvaluationHelper {
public List<ObjectReferenceType> evaluateRefExpressions(List<ExpressionType> expressions,
ExpressionVariables variables, String contextDescription,
Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
List<ObjectReferenceType> retval = new ArrayList<>();
for (ExpressionType expression : expressions) {
retval.addAll(evaluateRefExpression(expression, variables, contextDescription, task, result));
}
return retval;
}
public List<ObjectReferenceType> evaluateRefExpression(ExpressionType expressionType, ExpressionVariables variables,
String contextDescription, Task task, OperationResult result)
throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException {
return evaluateExpression(expressionType, variables, contextDescription, ObjectReferenceType.class,
ObjectReferenceType.COMPLEX_TYPE, ExpressionUtil.createRefConvertor(UserType.COMPLEX_TYPE), task, result);
}
public <T> T getSingleValue(Collection<T> values, T defaultValue, String contextDescription) {
if (values.size() == 0) {
return defaultValue;
} else if (values.size() > 1) {
throw new IllegalStateException("Expression should return exactly one value; it returned "
+ values.size() + " ones in " + contextDescription);
} else {
T value = values.iterator().next();
return value != null ? value : defaultValue;
}
}
@SuppressWarnings("unchecked")
@NotNull
public <T> List<T> evaluateExpression(ExpressionType expressionType, ExpressionVariables variables,
String contextDescription, Class<T> clazz, QName typeName,
Function<Object, Object> additionalConvertor, Task task,
OperationResult result)
throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException {
ExpressionFactory expressionFactory = getExpressionFactory();
PrismContext prismContext = expressionFactory.getPrismContext();
PrismPropertyDefinition<String> resultDef = new PrismPropertyDefinitionImpl<>(
new QName(SchemaConstants.NS_C, "result"), typeName, prismContext);
Expression<PrismPropertyValue<String>,PrismPropertyDefinition<String>> expression =
expressionFactory.makeExpression(expressionType, resultDef, contextDescription, task, result);
ExpressionEvaluationContext context = new ExpressionEvaluationContext(null, variables, contextDescription, task, result);
context.setAdditionalConvertor(additionalConvertor);
PrismValueDeltaSetTriple<PrismPropertyValue<String>> exprResultTriple = ModelExpressionThreadLocalHolder
.evaluateExpressionInContext(expression, context, task, result);
return exprResultTriple.getZeroSet().stream()
.map(ppv -> (T) ppv.getRealValue())
.collect(Collectors.toList());
}
public boolean evaluateBooleanExpression(ExpressionType expressionType, ExpressionVariables expressionVariables,
String contextDescription, Task task, OperationResult result)
throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException {
Collection<Boolean> values = evaluateExpression(expressionType, expressionVariables, contextDescription,
Boolean.class, DOMUtil.XSD_BOOLEAN, null, task, result);
return getSingleValue(values, false, contextDescription);
}
public ExpressionVariables getDefaultVariables(@Nullable DelegateExecution execution, Task wfTask, OperationResult result)
throws SchemaException, ObjectNotFoundException {
MiscDataUtil miscDataUtil = getMiscDataUtil();
ExpressionVariables variables = new ExpressionVariables();
variables.addVariableDefinition(C_REQUESTER,
miscDataUtil.resolveObjectReference(wfTask.getWorkflowContext().getRequesterRef(), result));
variables.addVariableDefinition(C_OBJECT,
miscDataUtil.resolveObjectReference(wfTask.getWorkflowContext().getObjectRef(), result));
// might be null
variables.addVariableDefinition(C_TARGET,
miscDataUtil.resolveObjectReference(wfTask.getWorkflowContext().getTargetRef(), result));
ObjectDelta objectDelta;
try {
objectDelta = miscDataUtil.getFocusPrimaryDelta(wfTask.getWorkflowContext(), true);
} catch (JAXBException e) {
throw new SchemaException("Couldn't get object delta: " + e.getMessage(), e);
}
variables.addVariableDefinition(SchemaConstants.T_OBJECT_DELTA, objectDelta);
// todo other variables?
// Activiti process instance variables (use with care)
if (execution != null) {
execution.getVariables().entrySet().forEach(e ->
variables.addVariableDefinition(new QName("_" + e.getKey()), e.getValue()));
}
return variables;
}
public static Function<Object, Object> createOutcomeConvertor() {
return (o) -> {
if (o == null || o instanceof String) {
return o;
} else if (o instanceof ApprovalLevelOutcomeType) {
return ApprovalUtils.toUri((ApprovalLevelOutcomeType) o);
} else if (o instanceof QName) {
return QNameUtil.qNameToUri((QName) o);
} else {
//throw new IllegalArgumentException("Couldn't create an URI from " + o);
return o; // let someone else complain about this
}
};
}
}