/*
* 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.model.impl.expr;
import com.evolveum.midpoint.model.common.expression.Expression;
import com.evolveum.midpoint.model.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.model.common.expression.ExpressionFactory;
import com.evolveum.midpoint.model.common.expression.ExpressionVariables;
import com.evolveum.midpoint.model.common.expression.script.xpath.XPathScriptEvaluator;
import com.evolveum.midpoint.model.impl.ModelObjectResolver;
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.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
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.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.commons.lang.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.Collection;
/**
*
* @author lazyman
*
*/
@Component
public class ExpressionHandler {
@Autowired(required = true)
@Qualifier("cacheRepositoryService")
private RepositoryService repositoryService;
@Autowired(required = true)
private ExpressionFactory expressionFactory;
@Autowired(required = true)
private ModelObjectResolver modelObjectResolver;
@Autowired(required = true)
private PrismContext prismContext;
private XPathScriptEvaluator xpathEvaluator = null;
public String evaluateExpression(ShadowType shadow, ExpressionType expressionType,
String shortDesc, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
Validate.notNull(shadow, "Resource object shadow must not be null.");
Validate.notNull(expressionType, "Expression must not be null.");
Validate.notNull(result, "Operation result must not be null.");
ResourceType resource = resolveResource(shadow, result);
ExpressionVariables variables = getDefaultXPathVariables(null, shadow, resource);
PrismPropertyDefinition<String> outputDefinition = new PrismPropertyDefinitionImpl<>(ExpressionConstants.OUTPUT_ELEMENT_NAME,
DOMUtil.XSD_STRING, prismContext);
Expression<PrismPropertyValue<String>,PrismPropertyDefinition<String>> expression = expressionFactory.makeExpression(expressionType,
outputDefinition, shortDesc, task, result);
ExpressionEvaluationContext params = new ExpressionEvaluationContext(null, variables, shortDesc, task, result);
PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = ModelExpressionThreadLocalHolder.evaluateExpressionInContext(expression, params, task, result);
if (outputTriple == null) {
return null;
}
Collection<PrismPropertyValue<String>> nonNegativeValues = outputTriple.getNonNegativeValues();
if (nonNegativeValues == null || nonNegativeValues.isEmpty()) {
return null;
}
if (nonNegativeValues.size() > 1) {
throw new ExpressionEvaluationException("Expression returned more than one value ("+nonNegativeValues.size()+") in "+shortDesc);
}
return nonNegativeValues.iterator().next().getValue();
}
public boolean evaluateConfirmationExpression(UserType user, ShadowType shadow,
ExpressionType expressionType, Task task, OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
Validate.notNull(user, "User must not be null.");
Validate.notNull(shadow, "Resource object shadow must not be null.");
Validate.notNull(expressionType, "Expression must not be null.");
Validate.notNull(result, "Operation result must not be null.");
ResourceType resource = resolveResource(shadow, result);
ExpressionVariables variables = getDefaultXPathVariables(user, shadow, resource);
String shortDesc = "confirmation expression for "+resource.asPrismObject();
PrismPropertyDefinition<Boolean> outputDefinition = new PrismPropertyDefinitionImpl<>(ExpressionConstants.OUTPUT_ELEMENT_NAME,
DOMUtil.XSD_BOOLEAN, prismContext);
Expression<PrismPropertyValue<Boolean>,PrismPropertyDefinition<Boolean>> expression = expressionFactory.makeExpression(expressionType,
outputDefinition, shortDesc, task, result);
ExpressionEvaluationContext params = new ExpressionEvaluationContext(null, variables, shortDesc, task, result);
PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> outputTriple = ModelExpressionThreadLocalHolder.evaluateExpressionInContext(expression, params, task, result);
Collection<PrismPropertyValue<Boolean>> nonNegativeValues = outputTriple.getNonNegativeValues();
if (nonNegativeValues == null || nonNegativeValues.isEmpty()) {
throw new ExpressionEvaluationException("Expression returned no value ("+nonNegativeValues.size()+") in "+shortDesc);
}
if (nonNegativeValues.size() > 1) {
throw new ExpressionEvaluationException("Expression returned more than one value ("+nonNegativeValues.size()+") in "+shortDesc);
}
PrismPropertyValue<Boolean> resultpval = nonNegativeValues.iterator().next();
if (resultpval == null) {
throw new ExpressionEvaluationException("Expression returned no value ("+nonNegativeValues.size()+") in "+shortDesc);
}
Boolean resultVal = resultpval.getValue();
if (resultVal == null) {
throw new ExpressionEvaluationException("Expression returned no value ("+nonNegativeValues.size()+") in "+shortDesc);
}
return resultVal;
}
// TODO: refactor - this method is also in SchemaHandlerImpl
private ResourceType resolveResource(ShadowType shadow, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException
{
if (shadow.getResource() != null) {
return shadow.getResource();
}
ObjectReferenceType ref = shadow.getResourceRef();
if (ref == null) {
throw new ExpressionEvaluationException("Resource shadow object " + shadow + " doesn't have defined resource.");
}
if (ref.getOid() == null) {
throw new ExpressionEvaluationException("Resource shadow object " + shadow + " defines null resource OID.");
}
return modelObjectResolver.getObjectSimple(ResourceType.class, ref.getOid(), null, null, result);
}
public static ExpressionVariables getDefaultXPathVariables(UserType user,
ShadowType shadow, ResourceType resource) {
ExpressionVariables variables = new ExpressionVariables();
if (user != null) {
variables.addVariableDefinition(ExpressionConstants.VAR_USER, user.asPrismObject());
}
if (shadow != null) {
variables.addVariableDefinition(ExpressionConstants.VAR_ACCOUNT, shadow.asPrismObject());
}
if (resource != null) {
variables.addVariableDefinition(ExpressionConstants.VAR_RESOURCE, resource.asPrismObject());
}
return variables;
}
// Called from the ObjectResolver.resolve
public ObjectType resolveRef(ObjectReferenceType ref, String contextDescription, OperationResult result)
throws ObjectNotFoundException, SchemaException {
Class<? extends ObjectType> type = ObjectType.class;
if (ref.getType() != null) {
ObjectTypes objectTypeType = ObjectTypes.getObjectTypeFromTypeQName(ref.getType());
type = objectTypeType.getClassDefinition();
}
return repositoryService.getObject(type, ref.getOid(), null, result).asObjectable();
}
}