/* * Copyright (c) 2010-2016 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.scripting.actions; import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.common.expression.ExpressionSyntaxException; import com.evolveum.midpoint.model.common.expression.ExpressionUtil; import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.model.common.expression.script.ScriptExpression; import com.evolveum.midpoint.model.common.expression.script.ScriptExpressionFactory; import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; import com.evolveum.midpoint.model.impl.util.Utils; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.schema.constants.ExpressionConstants; import com.evolveum.midpoint.schema.result.OperationResult; 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.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ScriptExpressionEvaluatorType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.xml.namespace.QName; import java.util.Collection; import java.util.List; /** * @author mederly */ @Component public class ScriptExecutor extends BaseActionExecutor { //private static final Trace LOGGER = TraceManager.getTrace(ScriptExecutor.class); @Autowired private ScriptExpressionFactory scriptExpressionFactory; private static final String NAME = "execute-script"; private static final String PARAM_SCRIPT = "script"; private static final String PARAM_OUTPUT_ITEM = "outputItem"; // item name or type (as URI!) -- EXPERIMENTAL @PostConstruct public void init() { scriptingExpressionEvaluator.registerActionExecutor(NAME, this); } @Override public Data execute(ActionExpressionType expression, Data input, ExecutionContext context, OperationResult result) throws ScriptExecutionException { ScriptExpressionEvaluatorType script = expressionHelper.getSingleArgumentValue(expression.getParameter(), PARAM_SCRIPT, true, true, NAME, input, context, ScriptExpressionEvaluatorType.class, result); String outputItem = expressionHelper.getSingleArgumentValue(expression.getParameter(), PARAM_OUTPUT_ITEM, false, false, NAME, input, context, String.class, result); ItemDefinition<?> outputDefinition = getItemDefinition(outputItem); ScriptExpression scriptExpression; try { scriptExpression = scriptExpressionFactory.createScriptExpression(script, outputDefinition, "script"); } catch (ExpressionSyntaxException e) { throw new ScriptExecutionException("Couldn't parse script expression: " + e.getMessage(), e); } Data output = Data.createEmpty(); for (PrismValue value: input.getData()) { context.checkTaskStop(); String valueDescription; long started; if (value instanceof PrismObjectValue) { started = operationsHelper.recordStart(context, asObjectType(value)); valueDescription = asObjectType(value).asPrismObject().toString(); } else { started = 0; valueDescription = value.toHumanReadableString(); } Throwable exception = null; try { Object outObject = executeScript(scriptExpression, value, context, result); if (outObject != null) { addToData(outObject, output); } if (value instanceof PrismObjectValue) { operationsHelper.recordEnd(context, asObjectType(value), started, null); } } catch (Throwable ex) { if (value instanceof PrismObjectValue) { operationsHelper.recordEnd(context, asObjectType(value), started, ex); } exception = processActionException(ex, NAME, value, context); } context.println((exception != null ? "Attempted to execute " : "Executed ") + "script on " + valueDescription + exceptionSuffix(exception)); } return output; } private void addToData(Object outObject, Data output) throws SchemaException { if (outObject == null) { // nothing to do } else if (outObject instanceof Collection) { for (Object o : (Collection) outObject) { addToData(o, output); } } else { PrismValue value; if (outObject instanceof PrismValue) { value = (PrismValue) outObject; } else if (outObject instanceof Objectable) { value = new PrismObjectValue<>((Objectable) outObject, prismContext); } else if (outObject instanceof Containerable) { value = new PrismContainerValue<>((Containerable) outObject, prismContext); } else { value = new PrismPropertyValue<>(outObject, prismContext); } output.addValue(value); } } private ItemDefinition<?> getItemDefinition(String itemUri) throws ScriptExecutionException { if (StringUtils.isBlank(itemUri)) { return null; } QName itemName = QNameUtil.uriToQName(itemUri, true); ItemDefinition def = prismContext.getSchemaRegistry().findItemDefinitionByElementName(itemName); if (def != null) { return def; } def = prismContext.getSchemaRegistry().findItemDefinitionByType(itemName); if (def != null) { return def; } throw new ScriptExecutionException("Supplied item identification " + itemUri + " corresponds neither to item name nor type name"); } private Object executeScript(ScriptExpression scriptExpression, PrismValue prismValue, ExecutionContext context, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { ExpressionVariables variables = new ExpressionVariables(); variables.addVariableDefinition(ExpressionConstants.VAR_INPUT, prismValue); variables.addVariableDefinition(ExpressionConstants.VAR_PRISM_CONTEXT, prismContext); ExpressionUtil.addActorVariable(variables, securityEnforcer); List<?> rv = Utils.evaluateScript(scriptExpression, null, variables, true, "in '"+NAME+"' action", context.getTask(), result); if (rv == null || rv.size() == 0) { return null; } else if (rv.size() == 1) { return rv.get(0); } else { return rv; // shouldn't occur; would cause problems } } private ObjectType asObjectType(PrismValue value) { return (ObjectType) ((PrismObjectValue) value).asObjectable(); } }