/******************************************************************************* * (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.compiler.modeller; import io.cloudslang.lang.entities.SensitivityLevel; import io.cloudslang.lang.compiler.SlangTextualKeys; import io.cloudslang.lang.compiler.modeller.model.Action; import io.cloudslang.lang.compiler.modeller.model.Decision; import io.cloudslang.lang.compiler.modeller.model.Flow; import io.cloudslang.lang.compiler.modeller.model.Operation; import io.cloudslang.lang.compiler.modeller.model.Step; import io.cloudslang.lang.compiler.modeller.model.Workflow; import io.cloudslang.lang.compiler.modeller.result.ActionModellingResult; import io.cloudslang.lang.compiler.modeller.result.ExecutableModellingResult; import io.cloudslang.lang.compiler.modeller.result.StepModellingResult; import io.cloudslang.lang.compiler.modeller.result.WorkflowModellingResult; import io.cloudslang.lang.compiler.modeller.transformers.ResultsTransformer; import io.cloudslang.lang.compiler.modeller.transformers.Transformer; import io.cloudslang.lang.compiler.parser.model.ParsedSlang; import io.cloudslang.lang.compiler.validator.ExecutableValidator; import io.cloudslang.lang.compiler.validator.PreCompileValidator; import io.cloudslang.lang.entities.ExecutableType; import io.cloudslang.lang.entities.ScoreLangConstants; import io.cloudslang.lang.entities.bindings.Argument; import io.cloudslang.lang.entities.bindings.Input; import io.cloudslang.lang.entities.bindings.Output; import io.cloudslang.lang.entities.bindings.Result; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.iterators.PeekingIterator; import org.apache.commons.lang3.StringUtils; import static ch.lambdaj.Lambda.filter; import static ch.lambdaj.Lambda.having; import static ch.lambdaj.Lambda.on; import static io.cloudslang.lang.compiler.SlangTextualKeys.FOR_KEY; import static io.cloudslang.lang.compiler.SlangTextualKeys.NAVIGATION_KEY; import static io.cloudslang.lang.compiler.SlangTextualKeys.ON_FAILURE_KEY; import static io.cloudslang.lang.compiler.SlangTextualKeys.PARALLEL_LOOP_KEY; import static io.cloudslang.lang.compiler.SlangTextualKeys.WORKFLOW_KEY; import static io.cloudslang.lang.entities.ScoreLangConstants.LOOP_KEY; import static io.cloudslang.lang.entities.ScoreLangConstants.NAMESPACE_DELIMITER; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; public class ExecutableBuilder { public static final String UNIQUE_STEP_NAME_MESSAGE_SUFFIX = "Each step name in the workflow must be unique"; private List<Transformer> transformers; private TransformersHandler transformersHandler; private DependenciesHelper dependenciesHelper; private PreCompileValidator preCompileValidator; private ResultsTransformer resultsTransformer; private ExecutableValidator executableValidator; private List<Transformer> preExecTransformers; private List<Transformer> postExecTransformers; private List<String> executableAdditionalKeywords = singletonList(SlangTextualKeys.EXECUTABLE_NAME_KEY); private List<String> operationAdditionalKeywords = asList(SlangTextualKeys.JAVA_ACTION_KEY, SlangTextualKeys.PYTHON_ACTION_KEY); private List<String> flowAdditionalKeywords = singletonList(SlangTextualKeys.WORKFLOW_KEY); private List<String> allExecutableAdditionalKeywords; private List<Transformer> actionTransformers; private List<List<String>> executableConstraintGroups; private List<Transformer> preStepTransformers; private List<Transformer> postStepTransformers; private List<String> stepAdditionalKeyWords = asList(ScoreLangConstants.LOOP_KEY, SlangTextualKeys.DO_KEY, SlangTextualKeys.NAVIGATION_KEY); private List<String> parallelLoopValidKeywords = asList(SlangTextualKeys.DO_KEY, SlangTextualKeys.FOR_KEY); // @PostConstruct public void initScopedTransformersAndKeys() { //executable transformers preExecTransformers = filterTransformers(Transformer.Scope.BEFORE_EXECUTABLE); postExecTransformers = filterTransformers(Transformer.Scope.AFTER_EXECUTABLE); //action transformers and keys actionTransformers = filterTransformers(Transformer.Scope.ACTION); allExecutableAdditionalKeywords = new ArrayList<>( executableAdditionalKeywords.size() + operationAdditionalKeywords.size() + flowAdditionalKeywords.size() ); allExecutableAdditionalKeywords.addAll(executableAdditionalKeywords); allExecutableAdditionalKeywords.addAll(operationAdditionalKeywords); allExecutableAdditionalKeywords.addAll(flowAdditionalKeywords); // keys excluding each other executableConstraintGroups = new ArrayList<>(); executableConstraintGroups.add(ListUtils.union(flowAdditionalKeywords, operationAdditionalKeywords)); //step transformers preStepTransformers = filterTransformers(Transformer.Scope.BEFORE_STEP); postStepTransformers = filterTransformers(Transformer.Scope.AFTER_STEP); } private List<Transformer> filterTransformers(Transformer.Scope scope) { return filter(having(on(Transformer.class).getScopes().contains(scope)), transformers); } public ExecutableModellingResult transformToExecutable(ParsedSlang parsedSlang, Map<String, Object> executableRawData, SensitivityLevel sensitivityLevel) { List<RuntimeException> errors = new ArrayList<>(); String execName = preCompileValidator.validateExecutableRawData(parsedSlang, executableRawData, errors); errors.addAll(preCompileValidator.checkKeyWords( execName, "", executableRawData, ListUtils.union(preExecTransformers, postExecTransformers), ParsedSlang.Type.DECISION.equals(parsedSlang.getType()) ? executableAdditionalKeywords : allExecutableAdditionalKeywords, executableConstraintGroups ) ); Map<String, Serializable> preExecutableActionData = new HashMap<>(); Map<String, Serializable> postExecutableActionData = new HashMap<>(); String errorMessagePrefix = "For " + parsedSlang.getType().toString().toLowerCase() + " '" + execName + "' syntax is illegal.\n"; preExecutableActionData.putAll( transformersHandler .runTransformers(executableRawData, preExecTransformers, errors, errorMessagePrefix, sensitivityLevel)); postExecutableActionData.putAll( transformersHandler .runTransformers(executableRawData, postExecTransformers, errors, errorMessagePrefix, SensitivityLevel.ENCRYPTED)); @SuppressWarnings("unchecked") List<Input> inputs = (List<Input>) preExecutableActionData.remove(SlangTextualKeys.INPUTS_KEY); @SuppressWarnings("unchecked") List<Output> outputs = (List<Output>) postExecutableActionData.remove(SlangTextualKeys.OUTPUTS_KEY); @SuppressWarnings("unchecked") List<Result> results = (List<Result>) postExecutableActionData.remove(SlangTextualKeys.RESULTS_KEY); results = results == null ? new ArrayList<Result>() : results; String namespace = parsedSlang.getNamespace(); Set<String> executableDependencies; Set<String> systemPropertyDependencies = null; switch (parsedSlang.getType()) { case FLOW: resultsTransformer.addDefaultResultsIfNeeded((List) executableRawData .get(SlangTextualKeys.RESULTS_KEY), ExecutableType.FLOW, results, errors); Map<String, String> imports = parsedSlang.getImports(); List<Map<String, Map<String, Object>>> workFlowRawData = preCompileValidator.validateWorkflowRawData(parsedSlang, executableRawData.get(WORKFLOW_KEY), execName, errors); Workflow onFailureWorkFlow = getOnFailureWorkflow(workFlowRawData, imports, errors, namespace, execName); WorkflowModellingResult workflowModellingResult = compileWorkFlow(workFlowRawData, imports, onFailureWorkFlow, false, namespace); errors.addAll(workflowModellingResult.getErrors()); Workflow workflow = workflowModellingResult.getWorkflow(); preCompileValidator.validateResultsHaveNoExpression(results, execName, errors); executableDependencies = fetchDirectStepsDependencies(workflow); try { systemPropertyDependencies = dependenciesHelper .getSystemPropertiesForFlow(inputs, outputs, results, workflow.getSteps()); } catch (RuntimeException ex) { errors.add(ex); } Flow flow = new Flow( preExecutableActionData, postExecutableActionData, workflow, namespace, execName, inputs, outputs, results, executableDependencies, systemPropertyDependencies ); return preCompileValidator .validateResult(parsedSlang, execName, new ExecutableModellingResult(flow, errors)); case OPERATION: resultsTransformer.addDefaultResultsIfNeeded((List) executableRawData.get(SlangTextualKeys.RESULTS_KEY), ExecutableType.OPERATION, results, errors); Map<String, Object> actionRawData = getActionRawData(executableRawData, errors, parsedSlang, execName); ActionModellingResult actionModellingResult = compileAction(actionRawData); errors.addAll(actionModellingResult.getErrors()); final Action action = actionModellingResult.getAction(); executableDependencies = new HashSet<>(); preCompileValidator.validateResultTypes(results, execName, errors); preCompileValidator.validateDefaultResult(results, execName, errors); try { systemPropertyDependencies = dependenciesHelper .getSystemPropertiesForOperation(inputs, outputs, results); } catch (RuntimeException ex) { errors.add(ex); } Operation operation = new Operation( preExecutableActionData, postExecutableActionData, action, namespace, execName, inputs, outputs, results, executableDependencies, systemPropertyDependencies ); return preCompileValidator .validateResult(parsedSlang, execName, new ExecutableModellingResult(operation, errors)); case DECISION: resultsTransformer.addDefaultResultsIfNeeded((List) executableRawData.get(SlangTextualKeys.RESULTS_KEY), ExecutableType.DECISION, results, errors); preCompileValidator.validateResultTypes(results, execName, errors); preCompileValidator.validateDecisionResultsSection(executableRawData, execName, errors); preCompileValidator.validateDefaultResult(results, execName, errors); try { systemPropertyDependencies = dependenciesHelper .getSystemPropertiesForDecision(inputs, outputs, results); } catch (RuntimeException ex) { errors.add(ex); } Decision decision = new Decision( preExecutableActionData, postExecutableActionData, namespace, execName, inputs, outputs, results, Collections.<String>emptySet(), systemPropertyDependencies ); return preCompileValidator.validateResult( parsedSlang, execName, new ExecutableModellingResult(decision, errors) ); default: throw new RuntimeException("Error compiling " + parsedSlang.getName() + ". It is not of flow, operations or decision type"); } } private Map<String, Object> getActionRawData( Map<String, Object> executableRawData, List<RuntimeException> errors, ParsedSlang parsedSlang, String execName) { Map<String, Object> actionRawData = new HashMap<>(); Object javaActionRawData = executableRawData.get(SlangTextualKeys.JAVA_ACTION_KEY); Object pythonActionRawData = executableRawData.get(SlangTextualKeys.PYTHON_ACTION_KEY); if (javaActionRawData != null) { actionRawData.put(SlangTextualKeys.JAVA_ACTION_KEY, executableRawData.get(SlangTextualKeys.JAVA_ACTION_KEY)); } if (pythonActionRawData != null) { actionRawData.put(SlangTextualKeys.PYTHON_ACTION_KEY, executableRawData.get(SlangTextualKeys.PYTHON_ACTION_KEY)); } if (MapUtils.isEmpty(actionRawData)) { errors.add(new RuntimeException("Error compiling " + parsedSlang.getName() + ". Operation: " + execName + " has no action data")); } return actionRawData; } private Workflow getOnFailureWorkflow(List<Map<String, Map<String, Object>>> workFlowRawData, Map<String, String> imports, List<RuntimeException> errors, String namespace, String execName) { Map<String, Map<String, Object>> onFailureStepData = preCompileValidator.validateOnFailurePosition( workFlowRawData, execName, errors ); Workflow onFailureWorkFlow = null; if (MapUtils.isNotEmpty(onFailureStepData)) { List<Map<String, Map<String, Object>>> onFailureData; try { //noinspection unchecked onFailureData = (List<Map<String, Map<String, Object>>>) onFailureStepData.values().iterator().next(); } catch (ClassCastException ex) { onFailureData = new ArrayList<>(); errors.add(new RuntimeException("Flow: '" + execName + "' syntax is illegal.\nBelow 'on_failure' property there " + "should be a list of steps and not a map")); } if (CollectionUtils.isNotEmpty(onFailureData)) { if (onFailureData.size() > 1) { errors.add(new RuntimeException("Flow: '" + execName + "' syntax is illegal.\nBelow 'on_failure' property " + "there should be only one step")); } handleOnFailureStepNavigationSection(onFailureData, execName, errors); WorkflowModellingResult workflowModellingResult = compileWorkFlow(onFailureData, imports, null, true, namespace); errors.addAll(workflowModellingResult.getErrors()); onFailureWorkFlow = workflowModellingResult.getWorkflow(); } else if (onFailureData == null) { errors.add(new RuntimeException("Flow: '" + execName + "' syntax is illegal.\nThere is no step below the 'on_failure' property.")); } } return onFailureWorkFlow; } private void handleOnFailureStepNavigationSection(List<Map<String, Map<String, Object>>> onFailureData, String execName, List<RuntimeException> errors) { Map.Entry<String, Map<String, Object>> onFailureStep = getFirstOnFailureStep(onFailureData); if (onFailureStep.getValue().containsKey(NAVIGATION_KEY)) { errors.add(new RuntimeException("Flow: '" + execName + "' syntax is illegal.\nThe step below 'on_failure' property should " + "not contain a \"navigate\" section.")); } } private Map.Entry<String, Map<String, Object>> getFirstOnFailureStep(List<Map<String, Map<String, Object>>> onFailureData) { Map<String, Map<String, Object>> onFailureStepMap = onFailureData.iterator().next(); return onFailureStepMap.entrySet().iterator().next(); } private ActionModellingResult compileAction(Map<String, Object> actionRawData) { Map<String, Serializable> actionData = new HashMap<>(); List<RuntimeException> errors = preCompileValidator .checkKeyWords("action data", "", actionRawData, actionTransformers, null, null); String errorMessagePrefix = "Action syntax is illegal.\n"; actionData.putAll( transformersHandler.runTransformers(actionRawData, actionTransformers, errors, errorMessagePrefix, SensitivityLevel.ENCRYPTED)); Action action = new Action(actionData); return new ActionModellingResult(action, errors); } private WorkflowModellingResult compileWorkFlow(List<Map<String, Map<String, Object>>> workFlowRawData, Map<String, String> imports, Workflow onFailureWorkFlow, boolean onFailureSection, String namespace) { List<RuntimeException> errors = new ArrayList<>(); Deque<Step> steps = new LinkedList<>(); Set<String> stepNames = new HashSet<>(); Deque<Step> onFailureSteps = !(onFailureSection || onFailureWorkFlow == null) ? onFailureWorkFlow.getSteps() : new LinkedList<Step>(); List<String> onFailureStepNames = getStepNames(onFailureSteps); boolean onFailureStepFound = onFailureStepNames.size() > 0; String defaultFailure = onFailureStepFound ? onFailureStepNames.get(0) : ScoreLangConstants.FAILURE_RESULT; PeekingIterator<Map<String, Map<String, Object>>> iterator = new PeekingIterator<>(workFlowRawData.iterator()); while (iterator.hasNext()) { Map<String, Map<String, Object>> stepRawData = iterator.next(); String stepName = getStepName(stepRawData); validateStepName(stepName, errors); if (stepNames.contains(stepName) || onFailureStepNames.contains(stepName)) { errors.add(new RuntimeException("Step name: \'" + stepName + "\' appears more than once in the workflow. " + UNIQUE_STEP_NAME_MESSAGE_SUFFIX)); } stepNames.add(stepName); Map<String, Object> stepRawDataValue; String message = "Step: " + stepName + " syntax is illegal.\nBelow step name, there should " + "be a map of values in the format:\ndo:\n\top_name:"; try { stepRawDataValue = stepRawData.values().iterator().next(); if (MapUtils.isNotEmpty(stepRawDataValue)) { boolean loopKeyFound = stepRawDataValue.containsKey(LOOP_KEY); boolean parallelLoopKeyFound = stepRawDataValue.containsKey(PARALLEL_LOOP_KEY); if (loopKeyFound) { if (parallelLoopKeyFound) { errors.add(new RuntimeException("Step: " + stepName + " syntax is illegal.\nBelow step name, " + "there can be either \'loop\' or \'aync_loop\' key.")); } message = "Step: " + stepName + " syntax is illegal.\nBelow the 'loop' keyword, there " + "should be a map of values in the format:\nfor:\ndo:\n\top_name:"; @SuppressWarnings("unchecked") Map<String, Object> loopRawData = (Map<String, Object>) stepRawDataValue.remove(LOOP_KEY); stepRawDataValue.putAll(loopRawData); } if (parallelLoopKeyFound) { message = "Step: " + stepName + " syntax is illegal.\nBelow the 'parallel_loop' keyword, there " + "should be a map of values in the format:\nfor:\ndo:\n\top_name:"; @SuppressWarnings("unchecked") Map<String, Object> parallelLoopRawData = (Map<String, Object>) stepRawDataValue.remove(PARALLEL_LOOP_KEY); errors.addAll( preCompileValidator.checkKeyWords( stepName, SlangTextualKeys.PARALLEL_LOOP_KEY, parallelLoopRawData, Collections.<Transformer>emptyList(), parallelLoopValidKeywords, null ) ); parallelLoopRawData.put(PARALLEL_LOOP_KEY, parallelLoopRawData.remove(FOR_KEY)); stepRawDataValue.putAll(parallelLoopRawData); } } } catch (ClassCastException ex) { stepRawDataValue = new HashMap<>(); errors.add(new RuntimeException(message)); } String defaultSuccess; Map<String, Map<String, Object>> nextStepData = iterator.peek(); if (nextStepData != null) { defaultSuccess = nextStepData.keySet().iterator().next(); } else { defaultSuccess = onFailureSection ? ScoreLangConstants.FAILURE_RESULT : ScoreLangConstants.SUCCESS_RESULT; } String onFailureStepName = onFailureStepFound ? onFailureStepNames.get(0) : null; StepModellingResult stepModellingResult = compileStep( stepName, stepRawDataValue, defaultSuccess, imports, defaultFailure, namespace, onFailureStepName, onFailureSection ); errors.addAll(stepModellingResult.getErrors()); steps.add(stepModellingResult.getStep()); } if (onFailureStepFound) { steps.addAll(onFailureSteps); } return new WorkflowModellingResult(new Workflow(steps), errors); } private String getStepName(Map<String, Map<String, Object>> stepRawData) { return stepRawData.keySet().iterator().next(); } private String validateStepName(String stepName, List<RuntimeException> errors) { try { executableValidator.validateStepName(stepName); } catch (RuntimeException rex) { errors.add(rex); } return stepName; } private StepModellingResult compileStep( String stepName, Map<String, Object> stepRawData, String defaultSuccess, Map<String, String> imports, String defaultFailure, String namespace, String onFailureStepName, boolean onFailureSection) { List<RuntimeException> errors = new ArrayList<>(); if (MapUtils.isEmpty(stepRawData)) { stepRawData = new HashMap<>(); errors.add(new RuntimeException("Step: " + stepName + " has no data")); } Map<String, Serializable> preStepData = new HashMap<>(); Map<String, Serializable> postStepData = new HashMap<>(); errors.addAll(preCompileValidator .checkKeyWords(stepName, "", stepRawData, ListUtils.union(preStepTransformers, postStepTransformers), stepAdditionalKeyWords, null)); String errorMessagePrefix = "For step '" + stepName + "' syntax is illegal.\n"; preStepData.putAll(transformersHandler .runTransformers(stepRawData, preStepTransformers, errors, errorMessagePrefix, SensitivityLevel.ENCRYPTED)); postStepData.putAll(transformersHandler .runTransformers(stepRawData, postStepTransformers, errors, errorMessagePrefix, SensitivityLevel.ENCRYPTED)); replaceOnFailureReference(postStepData, onFailureStepName); @SuppressWarnings("unchecked") List<Argument> arguments = (List<Argument>) preStepData.get(SlangTextualKeys.DO_KEY); String refId = ""; Map<String, Object> doRawData; try { //noinspection unchecked doRawData = (Map<String, Object>) stepRawData.get(SlangTextualKeys.DO_KEY); } catch (ClassCastException ex) { doRawData = new HashMap<>(); } if (MapUtils.isEmpty(doRawData)) { errors.add(new RuntimeException("Step: \'" + stepName + "\' has no reference information")); } else { try { String refString = doRawData.keySet().iterator().next(); refId = resolveReferenceId(refString, imports, namespace); } catch (RuntimeException rex) { errors.add(rex); } } List<Map<String, String>> navigationStrings = getNavigationStrings(postStepData, defaultSuccess, defaultFailure, errors); Step step = new Step( stepName, preStepData, postStepData, arguments, navigationStrings, refId, preStepData.containsKey(SlangTextualKeys.PARALLEL_LOOP_KEY), onFailureSection); return new StepModellingResult(step, errors); } private void replaceOnFailureReference( Map<String, Serializable> postStepData, String onFailureStepName) { Serializable navigationData = postStepData.get(NAVIGATION_KEY); if (navigationData != null) { @SuppressWarnings("unchecked") // from NavigateTransformer List<Map<String, String>> navigationStrings = (List<Map<String, String>>) navigationData; List<Map<String, String>> transformedNavigationStrings = new ArrayList<>(); for (Map<String, String> navigation : navigationStrings) { Map.Entry<String, String> navigationEntry = navigation.entrySet().iterator().next(); Map<String, String> transformedNavigation = new HashMap<>(navigation); if (navigationEntry.getValue().equals(ON_FAILURE_KEY)) { if (StringUtils.isEmpty(onFailureStepName)) { transformedNavigation.put(navigationEntry.getKey(), ScoreLangConstants.FAILURE_RESULT); } else { transformedNavigation.put(navigationEntry.getKey(), onFailureStepName); } } else { transformedNavigation.put(navigationEntry.getKey(), navigationEntry.getValue()); } transformedNavigationStrings.add(transformedNavigation); } postStepData.put(NAVIGATION_KEY, (Serializable) transformedNavigationStrings); } } private List<Map<String, String>> getNavigationStrings( Map<String, Serializable> postStepData, String defaultSuccess, String defaultFailure, List<RuntimeException> errors) { @SuppressWarnings("unchecked") List<Map<String, String>> navigationStrings = (List<Map<String, String>>) postStepData.get(SlangTextualKeys.NAVIGATION_KEY); //default navigation if (CollectionUtils.isEmpty(navigationStrings)) { navigationStrings = new ArrayList<>(); Map<String, String> successMap = new HashMap<>(); successMap.put(ScoreLangConstants.SUCCESS_RESULT, defaultSuccess); Map<String, String> failureMap = new HashMap<>(); failureMap.put(ScoreLangConstants.FAILURE_RESULT, defaultFailure); navigationStrings.add(successMap); navigationStrings.add(failureMap); return navigationStrings; } else { try { executableValidator.validateNavigationStrings(navigationStrings); return navigationStrings; } catch (RuntimeException rex) { errors.add(rex); return new ArrayList<>(); } } } private String resolveReferenceId(String rawReferenceId, Map<String, String> imports, String namespace) { executableValidator.validateStepReferenceId(rawReferenceId); int numberOfDelimiters = StringUtils.countMatches(rawReferenceId, NAMESPACE_DELIMITER); String resolvedReferenceId; if (numberOfDelimiters == 0) { // implicit namespace resolvedReferenceId = namespace + NAMESPACE_DELIMITER + rawReferenceId; } else { String prefix = StringUtils.substringBefore(rawReferenceId, NAMESPACE_DELIMITER); String suffix = StringUtils.substringAfter(rawReferenceId, NAMESPACE_DELIMITER); if (MapUtils.isNotEmpty(imports) && imports.containsKey(prefix)) { // expand alias resolvedReferenceId = imports.get(prefix) + NAMESPACE_DELIMITER + suffix; } else { // full path without alias expanding resolvedReferenceId = rawReferenceId; } } return resolvedReferenceId; } /** * Fetch the first level of the dependencies of the executable (non recursively) * * @param workflow the workflow of the flow * @return a map of dependencies. Key - dependency full name, value - type */ private Set<String> fetchDirectStepsDependencies(Workflow workflow) { Set<String> dependencies = new HashSet<>(); Deque<Step> steps = workflow.getSteps(); for (Step step : steps) { dependencies.add(step.getRefId()); } return dependencies; } private List<String> getStepNames(Deque<Step> steps) { List<String> stepNames = new ArrayList<>(); for (Step step : steps) { stepNames.add(step.getName()); } return stepNames; } public void setTransformers(List<Transformer> transformers) { this.transformers = transformers; } public void setTransformersHandler(TransformersHandler transformersHandler) { this.transformersHandler = transformersHandler; } public void setDependenciesHelper(DependenciesHelper dependenciesHelper) { this.dependenciesHelper = dependenciesHelper; } public void setPreCompileValidator(PreCompileValidator preCompileValidator) { this.preCompileValidator = preCompileValidator; } public void setResultsTransformer(ResultsTransformer resultsTransformer) { this.resultsTransformer = resultsTransformer; } public void setExecutableValidator(ExecutableValidator executableValidator) { this.executableValidator = executableValidator; } public void setPreExecTransformers(List<Transformer> preExecTransformers) { this.preExecTransformers = preExecTransformers; } public void setPostExecTransformers(List<Transformer> postExecTransformers) { this.postExecTransformers = postExecTransformers; } public void setExecutableAdditionalKeywords(List<String> executableAdditionalKeywords) { this.executableAdditionalKeywords = executableAdditionalKeywords; } public void setOperationAdditionalKeywords(List<String> operationAdditionalKeywords) { this.operationAdditionalKeywords = operationAdditionalKeywords; } public void setFlowAdditionalKeywords(List<String> flowAdditionalKeywords) { this.flowAdditionalKeywords = flowAdditionalKeywords; } public void setAllExecutableAdditionalKeywords(List<String> allExecutableAdditionalKeywords) { this.allExecutableAdditionalKeywords = allExecutableAdditionalKeywords; } public void setActionTransformers(List<Transformer> actionTransformers) { this.actionTransformers = actionTransformers; } public void setExecutableConstraintGroups(List<List<String>> executableConstraintGroups) { this.executableConstraintGroups = executableConstraintGroups; } public void setPreStepTransformers(List<Transformer> preStepTransformers) { this.preStepTransformers = preStepTransformers; } public void setPostStepTransformers(List<Transformer> postStepTransformers) { this.postStepTransformers = postStepTransformers; } public void setStepAdditionalKeyWords(List<String> stepAdditionalKeyWords) { this.stepAdditionalKeyWords = stepAdditionalKeyWords; } public void setParallelLoopValidKeywords(List<String> parallelLoopValidKeywords) { this.parallelLoopValidKeywords = parallelLoopValidKeywords; } }