/******************************************************************************* * (c) Copyright 2016 Hewlett-Packard Development Company, L.P. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Apache License v2.0 which accompany this distribution. * * The Apache License is available at * http://www.apache.org/licenses/LICENSE-2.0 * *******************************************************************************/ package io.cloudslang.lang.runtime.steps; import com.hp.oo.sdk.content.annotations.Param; import com.hp.oo.sdk.content.plugin.SerializableSessionObject; import io.cloudslang.lang.entities.ActionType; import io.cloudslang.lang.entities.ScoreLangConstants; import io.cloudslang.lang.entities.bindings.values.Value; import io.cloudslang.lang.entities.bindings.values.ValueFactory; import io.cloudslang.lang.runtime.bindings.scripts.ScriptExecutor; import io.cloudslang.lang.runtime.env.ReturnValues; import io.cloudslang.lang.runtime.env.RunEnvironment; import io.cloudslang.lang.runtime.events.LanguageEventData; import io.cloudslang.runtime.api.java.JavaRuntimeService; import io.cloudslang.score.api.execution.ExecutionParametersConsts; import io.cloudslang.score.lang.ExecutionRuntimeServices; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.log4j.Logger; import org.python.google.common.collect.Sets; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import static io.cloudslang.score.api.execution.ExecutionParametersConsts.EXECUTION_RUNTIME_SERVICES; /** * User: stoneo * Date: 02/11/2014 * Time: 10:25 */ @Component public class ActionExecutionData extends AbstractExecutionData { private static final Logger logger = Logger.getLogger(ActionExecutionData.class); public static final String PACKAGING_TYPE_JAR = "jar"; public static final String PACKAGING_TYPE_ZIP = "zip"; public static final int GAV_PARTS = 3; @Autowired private ScriptExecutor scriptExecutor; @Autowired private JavaRuntimeService javaExecutionService; public void doAction(@Param(EXECUTION_RUNTIME_SERVICES) ExecutionRuntimeServices executionRuntimeServices, @Param(ScoreLangConstants.RUN_ENV) RunEnvironment runEnv, @Param(ExecutionParametersConsts.NON_SERIALIZABLE_EXECUTION_DATA) Map<String, Object> nonSerializableExecutionData, @Param(ScoreLangConstants.NEXT_STEP_ID_KEY) Long nextStepId, @Param(ScoreLangConstants.ACTION_TYPE) ActionType actionType, @Param(ScoreLangConstants.JAVA_ACTION_CLASS_KEY) String className, @Param(ScoreLangConstants.JAVA_ACTION_METHOD_KEY) String methodName, @Param(ScoreLangConstants.JAVA_ACTION_GAV_KEY) String gav, @Param(ScoreLangConstants.PYTHON_ACTION_SCRIPT_KEY) String script, @Param(ScoreLangConstants.PYTHON_ACTION_DEPENDENCIES_KEY) Collection<String> dependencies) { Map<String, Value> returnValue = new HashMap<>(); Map<String, Value> callArguments = runEnv.removeCallArguments(); Map<String, Value> callArgumentsDeepCopy = new HashMap<>(); for (Map.Entry<String, Value> entry : callArguments.entrySet()) { callArgumentsDeepCopy.put(entry.getKey(), ValueFactory.create(entry.getValue())); } Map<String, SerializableSessionObject> serializableSessionData = runEnv.getSerializableDataMap(); fireEvent(executionRuntimeServices, ScoreLangConstants.EVENT_ACTION_START, "Preparing to run action " + actionType, runEnv.getExecutionPath().getParentPath(), LanguageEventData.StepType.ACTION, null, Pair.of(LanguageEventData.CALL_ARGUMENTS, (Serializable) callArgumentsDeepCopy)); try { switch (actionType) { case JAVA: returnValue = runJavaAction(serializableSessionData, callArguments, nonSerializableExecutionData, gav, className, methodName); break; case PYTHON: returnValue = prepareAndRunPythonAction(dependencies, script, callArguments); break; default: break; } } catch (RuntimeException ex) { fireEvent(executionRuntimeServices, ScoreLangConstants.EVENT_ACTION_ERROR, ex.getMessage(), runEnv.getExecutionPath().getParentPath(), LanguageEventData.StepType.ACTION, null, Pair.of(LanguageEventData.EXCEPTION, ex.getMessage())); logger.error(ex); throw (ex); } ReturnValues returnValues = new ReturnValues(returnValue, null); runEnv.putReturnValues(returnValues); fireEvent(executionRuntimeServices, ScoreLangConstants.EVENT_ACTION_END, "Action performed", runEnv.getExecutionPath().getParentPath(), LanguageEventData.StepType.ACTION, null); runEnv.putNextStepPosition(nextStepId); } @SuppressWarnings("unchecked") private Map<String, Value> runJavaAction(Map<String, SerializableSessionObject> serializableSessionData, Map<String, Value> currentContext, Map<String, Object> nonSerializableExecutionData, String gav, String className, String methodName) { Map<String, Serializable> returnMap = (Map<String, Serializable>) javaExecutionService .execute(normalizeJavaGav(gav), className, methodName, new CloudSlangJavaExecutionParameterProvider(serializableSessionData, createActionContext(currentContext), nonSerializableExecutionData)); if (returnMap == null) { throw new RuntimeException("Action method did not return Map<String,String>"); } return createActionResult(returnMap, currentContext); } protected Map<String, Serializable> createActionContext(Map<String, Value> context) { Map<String, Serializable> result = new HashMap<>(); for (Map.Entry<String, Value> entry : context.entrySet()) { result.put(entry.getKey(), entry.getValue() == null ? null : entry.getValue().get()); } return result; } protected Map<String, Value> createActionResult(Map<String, Serializable> executionResult, Map<String, Value> context) { Map<String, Value> result = new HashMap<>(); for (Map.Entry<String, Serializable> entry : executionResult.entrySet()) { Value callArgumenet = context.get(entry.getKey()); Value value = ValueFactory.create(entry.getValue(), callArgumenet != null && callArgumenet.isSensitive()); result.put(entry.getKey(), value); } return result; } /** * Checks whether need to append packaging type to the gav * * @param gav * @param packagingType * @return */ private String normalizeGav(String gav, String packagingType) { //this is temporary solution until we add mandatory for java //after this we will not check the empty assuming it is always not empty and we have 3 parts return (StringUtils.isEmpty(gav) || (gav.split(":").length > GAV_PARTS)) ? gav : gav + ":" + packagingType; } private String normalizeJavaGav(String gav) { return normalizeGav(gav, PACKAGING_TYPE_JAR); } private Set<String> normalizePythonDependencies(Collection<String> dependencies) { Set<String> pythonDependencies = dependencies == null || dependencies.isEmpty() ? Sets.<String>newHashSet() : new HashSet<>(dependencies); Set<String> normalizedDependencies = new HashSet<>(pythonDependencies.size()); for (String dependency : pythonDependencies) { normalizedDependencies.add(normalizeGav(dependency, PACKAGING_TYPE_ZIP)); } return normalizedDependencies; } private Map<String, Value> prepareAndRunPythonAction(Collection<String> dependencies, String pythonScript, Map<String, Value> callArguments) { if (StringUtils.isNotBlank(pythonScript)) { return scriptExecutor.executeScript( normalizePythonDependencies(dependencies), pythonScript, callArguments); } throw new RuntimeException("Python script not found in action data"); } }