com.evolveum.midpoint.model.common.expression.functions.CustomFunctions.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.model.common.expression.functions.CustomFunctions.java

Source

/*
 * 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.model.common.expression.functions;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.xml.namespace.QName;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.Validate;

import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismPropertyDefinitionImpl;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.repo.common.expression.Expression;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.repo.common.expression.ExpressionFactory;
import com.evolveum.midpoint.repo.common.expression.ExpressionUtil;
import com.evolveum.midpoint.repo.common.expression.ExpressionVariables;
import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
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.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
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.SecurityViolationException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionParameterType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionReturnMultiplicityType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FunctionLibraryType;

public class CustomFunctions {

    Trace LOGGER = TraceManager.getTrace(CustomFunctions.class);

    private ExpressionFactory expressionFactory;
    private FunctionLibraryType library;
    private OperationResult result;
    private Task task;
    private PrismContext prismContext;

    public CustomFunctions(FunctionLibraryType library, ExpressionFactory expressionFactory, OperationResult result,
            Task task) {
        this.library = library;
        this.expressionFactory = expressionFactory;
        this.prismContext = expressionFactory.getPrismContext();
        this.result = result;
        this.task = task;
    }

    public <V extends PrismValue, D extends ItemDefinition> Object execute(String functionName,
            Map<String, Object> params) throws ExpressionEvaluationException {
        Validate.notNull(functionName, "Function name must be specified");

        List<ExpressionType> functions = library.getFunction().stream()
                .filter(expression -> functionName.equals(expression.getName())).collect(Collectors.toList());

        LOGGER.trace("functions {}", functions);
        ExpressionType expressionType = functions.iterator().next();

        LOGGER.trace("function to execute {}", expressionType);

        try {
            ExpressionVariables variables = new ExpressionVariables();
            if (MapUtils.isNotEmpty(params)) {
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    variables.addVariableDefinition(new QName(entry.getKey()), convertInput(entry, expressionType));
                }
                ;
            }

            QName returnType = expressionType.getReturnType();
            if (returnType == null) {
                returnType = DOMUtil.XSD_STRING;
            }

            D outputDefinition = (D) prismContext.getSchemaRegistry().findItemDefinitionByType(returnType);
            if (outputDefinition == null) {
                outputDefinition = (D) new PrismPropertyDefinitionImpl(SchemaConstantsGenerated.C_VALUE, returnType,
                        prismContext);
            }
            if (expressionType.getReturnMultiplicity() != null
                    && expressionType.getReturnMultiplicity() == ExpressionReturnMultiplicityType.MULTI) {
                outputDefinition.setMaxOccurs(-1);
            } else {
                outputDefinition.setMaxOccurs(1);
            }
            String shortDesc = "custom function execute";
            Expression<V, D> expression = expressionFactory.makeExpression(expressionType, outputDefinition,
                    shortDesc, task, result);

            ExpressionEvaluationContext context = new ExpressionEvaluationContext(null, variables, shortDesc, task,
                    result);
            PrismValueDeltaSetTriple<V> outputTriple = expression.evaluate(context);

            LOGGER.trace("Result of the expression evaluation: {}", outputTriple);

            if (outputTriple == null) {
                return null;
            }

            Collection<V> nonNegativeValues = outputTriple.getNonNegativeValues();

            if (nonNegativeValues == null || nonNegativeValues.isEmpty()) {
                return null;
            }

            if (outputDefinition.isMultiValue()) {
                return PrismValue.getRealValuesOfCollection(nonNegativeValues);
            }

            if (nonNegativeValues.size() > 1) {
                throw new ExpressionEvaluationException("Expression returned more than one value ("
                        + nonNegativeValues.size() + ") in " + shortDesc);
            }

            return nonNegativeValues.iterator().next().getRealValue();

        } catch (SchemaException | ExpressionEvaluationException | ObjectNotFoundException | CommunicationException
                | ConfigurationException | SecurityViolationException e) {
            throw new ExpressionEvaluationException(e.getMessage(), e);
        }

    }

    private Object convertInput(Map.Entry<String, Object> entry, ExpressionType expression) throws SchemaException {

        ExpressionParameterType expressionParam = expression.getParameter().stream()
                .filter(param -> param.getName().equals(entry.getKey())).findAny()
                .orElseThrow(SchemaException::new);

        QName paramType = expressionParam.getType();
        Class<?> expressionParameterClass = prismContext.getSchemaRegistry().determineClassForType(paramType);

        if (expressionParameterClass != null && !DOMUtil.XSD_ANYTYPE.equals(paramType)
                && XmlTypeConverter.canConvert(expressionParameterClass)) {
            return ExpressionUtil.convertValue(expressionParameterClass, null, entry.getValue(),
                    prismContext.getDefaultProtector(), prismContext);
        }

        return entry.getValue();

        // FIXME: awful hack
        //      if (String.class.equals(expressioNParameterClass) && entry.getValue() instanceof PolyString) {
        //         return ((PolyString) entry.getValue()).getOrig();
        //      }

        //if (expressioNParameterClass != null && !expressioNParameterClass.isAssignableFrom(entry.getValue().getClass())) {
        //      if (expressioNParameterClass != null && !expressioNParameterClass.equals(entry.getValue().getClass())){
        //         throw new SchemaException("Unexpected type of value, expecting " + expressioNParameterClass.getSimpleName() + " but the actual value is " + entry.getValue().getClass().getSimpleName());
        //      }

        //      return entry.getValue();

    }

}