/******************************************************************************* * (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 io.cloudslang.lang.entities.ExecutableType; import io.cloudslang.lang.entities.ScoreLangConstants; import io.cloudslang.lang.entities.bindings.Input; import io.cloudslang.lang.entities.bindings.Output; import io.cloudslang.lang.entities.bindings.Result; import io.cloudslang.lang.entities.bindings.values.Value; import io.cloudslang.lang.runtime.bindings.InputsBinding; import io.cloudslang.lang.runtime.bindings.OutputsBinding; import io.cloudslang.lang.runtime.bindings.ResultsBinding; import io.cloudslang.lang.runtime.env.Context; import io.cloudslang.lang.runtime.env.ParentFlowData; import io.cloudslang.lang.runtime.env.ReturnValues; import io.cloudslang.lang.runtime.env.RunEnvironment; import io.cloudslang.lang.runtime.events.LanguageEventData; import io.cloudslang.score.lang.ExecutionRuntimeServices; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.tuple.Pair; import org.apache.log4j.Logger; 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:24 */ @Component public class ExecutableExecutionData extends AbstractExecutionData { public static final String ACTION_RETURN_VALUES_KEY = "actionReturnValues"; @Autowired private ResultsBinding resultsBinding; @Autowired private InputsBinding inputsBinding; @Autowired private OutputsBinding outputsBinding; private static final Logger logger = Logger.getLogger(ExecutableExecutionData.class); public void startExecutable(@Param(ScoreLangConstants.EXECUTABLE_INPUTS_KEY) List<Input> executableInputs, @Param(ScoreLangConstants.RUN_ENV) RunEnvironment runEnv, @Param(ScoreLangConstants.USER_INPUTS_KEY) Map<String, ? extends Value> userInputs, @Param(EXECUTION_RUNTIME_SERVICES) ExecutionRuntimeServices executionRuntimeServices, @Param(ScoreLangConstants.NODE_NAME_KEY) String nodeName, @Param(ScoreLangConstants.NEXT_STEP_ID_KEY) Long nextStepId, @Param(ScoreLangConstants.EXECUTABLE_TYPE) ExecutableType executableType) { try { Map<String, Value> callArguments = runEnv.removeCallArguments(); if (userInputs != null) { callArguments.putAll(userInputs); } LanguageEventData.StepType stepType = LanguageEventData.convertExecutableType(executableType); sendStartBindingInputsEvent(executableInputs, runEnv, executionRuntimeServices, "Pre Input binding for " + stepType, stepType, nodeName); Map<String, Value> executableContext = inputsBinding .bindInputs(executableInputs, callArguments, runEnv.getSystemProperties()); Map<String, Value> actionArguments = new HashMap<>(); actionArguments.putAll(executableContext); //done with the user inputs, don't want it to be available in next startExecutable steps.. if (userInputs != null) { userInputs.clear(); } updateCallArgumentsAndPushContextToStack(runEnv, new Context(executableContext), actionArguments); sendEndBindingInputsEvent(executableInputs, executableContext, runEnv, executionRuntimeServices, "Post Input binding for " + stepType, stepType, nodeName); // put the next step position for the navigation runEnv.putNextStepPosition(nextStepId); runEnv.getExecutionPath().down(); } catch (RuntimeException e) { logger.error("There was an error running the start executable execution step of: \'" + nodeName + "\'.\n\tError is: " + e.getMessage()); throw new RuntimeException("Error running: \'" + nodeName + "\'.\n\t " + e.getMessage(), e); } } /** * This method is executed by the finishExecutable execution step of an operation or flow * * @param runEnv the run environment object * @param executableOutputs the operation outputs data * @param executableResults the operation results data * @param executionRuntimeServices services supplied by score engine for handling the execution */ public void finishExecutable(@Param(ScoreLangConstants.RUN_ENV) RunEnvironment runEnv, @Param(ScoreLangConstants.EXECUTABLE_OUTPUTS_KEY) List<Output> executableOutputs, @Param(ScoreLangConstants.EXECUTABLE_RESULTS_KEY) List<Result> executableResults, @Param(EXECUTION_RUNTIME_SERVICES) ExecutionRuntimeServices executionRuntimeServices, @Param(ScoreLangConstants.NODE_NAME_KEY) String nodeName, @Param(ScoreLangConstants.EXECUTABLE_TYPE) ExecutableType executableType) { try { runEnv.getExecutionPath().up(); Context operationContext = runEnv.getStack().popContext(); Map<String, Value> operationVariables = operationContext == null ? null : operationContext.getImmutableViewOfVariables(); ReturnValues actionReturnValues = buildReturnValues(runEnv, executableType); LanguageEventData.StepType stepType = LanguageEventData.convertExecutableType(executableType); fireEvent(executionRuntimeServices, runEnv, ScoreLangConstants.EVENT_OUTPUT_START, "Output binding started", stepType, nodeName, Pair.of(ScoreLangConstants.EXECUTABLE_OUTPUTS_KEY, (Serializable) executableOutputs), Pair.of(ScoreLangConstants.EXECUTABLE_RESULTS_KEY, (Serializable) executableResults), Pair.of(ACTION_RETURN_VALUES_KEY, executableType == ExecutableType.OPERATION ? new ReturnValues(new HashMap<String, Value>(), actionReturnValues.getResult()) : actionReturnValues) ); // Resolving the result of the operation/flow String result = resultsBinding.resolveResult( operationVariables, actionReturnValues.getOutputs(), runEnv.getSystemProperties(), executableResults, actionReturnValues.getResult() ); Map<String, Value> operationReturnOutputs = outputsBinding.bindOutputs( operationVariables, actionReturnValues.getOutputs(), runEnv.getSystemProperties(), executableOutputs ); ReturnValues returnValues = new ReturnValues(operationReturnOutputs, result); runEnv.putReturnValues(returnValues); fireEvent(executionRuntimeServices, runEnv, ScoreLangConstants.EVENT_OUTPUT_END, "Output binding finished", stepType, nodeName, Pair.of(LanguageEventData.OUTPUTS, (Serializable) operationReturnOutputs), Pair.of(LanguageEventData.RESULT, returnValues.getResult()) ); // If we have parent flow data on the stack, we pop it and request the score engine to switch // to the parent execution plan id once it can, and we set the next position that was stored there // for the use of the navigation if (!runEnv.getParentFlowStack().isEmpty()) { handleNavigationToParent(runEnv, executionRuntimeServices); } else { fireEvent(executionRuntimeServices, runEnv, ScoreLangConstants.EVENT_EXECUTION_FINISHED, "Execution finished running", stepType, nodeName, Pair.of(LanguageEventData.RESULT, returnValues.getResult()), Pair.of(LanguageEventData.OUTPUTS, (Serializable) operationReturnOutputs) ); } } catch (RuntimeException e) { logger.error("There was an error running the finish executable execution step of: \'" + nodeName + "\'.\n\tError is: " + e.getMessage()); throw new RuntimeException("Error running: \'" + nodeName + "\'.\n\t" + e.getMessage(), e); } } private void handleNavigationToParent(RunEnvironment runEnv, ExecutionRuntimeServices executionRuntimeServices) { ParentFlowData parentFlowData = runEnv.getParentFlowStack().popParentFlowData(); executionRuntimeServices.requestToChangeExecutionPlan(parentFlowData.getRunningExecutionPlanId()); runEnv.putNextStepPosition(parentFlowData.getPosition()); } private ReturnValues buildReturnValues(RunEnvironment runEnvironment, ExecutableType executableType) { ReturnValues returnValues = runEnvironment.removeReturnValues(); switch (executableType) { case DECISION: returnValues = new ReturnValues(Collections.<String, Value>emptyMap(), null); break; case FLOW: break; case OPERATION: break; default: throw new RuntimeException("Unrecognized type: " + executableType); } return returnValues; } }