All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.chutneytesting.design.domain.scenario.compose.ComposableStep Maven / Gradle / Ivy

package com.chutneytesting.design.domain.scenario.compose;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toMap;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;

public class ComposableStep {

    public final String id;
    public final String name;
    public final List steps;
    public final Map defaultParameters; // default parameters defined when editing the component alone
    public final Optional implementation;
    public final Strategy strategy;
    public final Map executionParameters; // override default parameters values when the component is used inside another component
    public final List tags;

    private ComposableStep(String id,
                           String name,
                           List steps,
                           Map defaultParameters,
                           Optional implementation,
                           Strategy strategy,
                           Map executionParameters,
                           List tags) {
        this.id = id;
        this.name = name;
        this.steps = steps;
        this.defaultParameters = defaultParameters;
        this.implementation = implementation;
        this.strategy = strategy;
        this.executionParameters = executionParameters;
        this.tags = tags;
    }

    public boolean hasCyclicDependencies() {
        return checkCyclicDependency(this, new ArrayList<>());
    }

    private boolean checkCyclicDependency(ComposableStep composableStep, List parentsAcc) {
        if (composableStep.steps.isEmpty()) {
            return false;
        }

        parentsAcc.add(composableStep.id);
        List childrenIds = composableStep.steps.stream()
            .map(cs -> cs.id)
            .collect(Collectors.toList());

        if (!Collections.disjoint(childrenIds, parentsAcc)) {
            return true;
        }

        return composableStep.steps.stream()
            .anyMatch(cs -> checkCyclicDependency(cs, new ArrayList<>(parentsAcc)));
    }

    public Map getEmptyExecutionParameters() {
        return executionParameters.entrySet().stream()
            .filter(e -> StringUtils.isBlank(e.getValue()))
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> "", LinkedHashMap::new));
    }

    public Map getChildrenEmptyParam() {
        return steps.stream()
            .flatMap(s -> s.getEmptyExecutionParameters().entrySet().stream())
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> ""));
    }

    public ComposableStep usingExecutionParameters(Map executionParameters) {
        return builder().from(this).withExecutionParameters(executionParameters).build();
    }

    @Override
    public String toString() {
        return "ComposableStep{" +
            "id='" + id + '\'' +
            ", name='" + name + '\'' +
            ", steps=" + steps +
            ", defaultParameters=" + defaultParameters +
            ", implementation=" + implementation +
            ", strategy=" + strategy.toString() +
            ", executionParameters=" + executionParameters +
            '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ComposableStep that = (ComposableStep) o;
        return Objects.equals(id, that.id) &&
            Objects.equals(name, that.name) &&
            Objects.equals(steps, that.steps) &&
            Objects.equals(defaultParameters, that.defaultParameters) &&
            Objects.equals(implementation, that.implementation) &&
            Objects.equals(strategy, that.strategy) &&
            Objects.equals(executionParameters, that.executionParameters)
            ;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, steps, defaultParameters, implementation, strategy, executionParameters);
    }

    public static ComposableStepBuilder builder() {
        return new ComposableStepBuilder();
    }

    public static class ComposableStepBuilder {

        private String id;
        private String name;
        private List steps;
        private Map defaultParameters;
        private Optional implementation = empty();
        private Strategy strategy;
        private List tags = new ArrayList<>();
        private Map overrideExecutionParameters;

        private ComposableStepBuilder() {}

        public ComposableStep build() {
            defaultParameters = unmodifiableMap(ofNullable(defaultParameters).orElse(emptyMap()));
            steps = unmodifiableList(ofNullable(steps).orElse(emptyList()));

            ComposableStep composableStep = new ComposableStep(
                ofNullable(id).orElse(""),
                ofNullable(name).orElse(""),
                steps,
                defaultParameters,
                implementation,
                ofNullable(strategy).orElse(Strategy.DEFAULT),
                resolveExecutionParameters(),
                unmodifiableList(ofNullable(tags).orElse(emptyList()))
            );

            if (composableStep.hasCyclicDependencies()) {
                throw new ComposableStepCyclicDependencyException(composableStep.id, composableStep.name);
            }

            return composableStep;
        }

        private Map resolveExecutionParameters() {
            Map emptyChildrenParameters = steps.stream()
                .flatMap(s -> s.getEmptyExecutionParameters().entrySet().stream())
                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> "", LinkedHashMap::new));

            Map executionParameters = new LinkedHashMap<>();
            executionParameters.putAll(emptyChildrenParameters);
            executionParameters.putAll(defaultParameters);
            executionParameters.putAll(ofNullable(this.overrideExecutionParameters).orElse(emptyMap()));
            return executionParameters;
        }

        public ComposableStepBuilder withId(String id) {
            this.id = id;
            return this;
        }

        public ComposableStepBuilder withName(String name) {
            this.name = name;
            return this;
        }

        public ComposableStepBuilder withSteps(List steps) {
            this.steps = steps;
            return this;
        }

        public ComposableStepBuilder withDefaultParameters(Map defaultParameters) {
            this.defaultParameters = defaultParameters;
            return this;
        }

        public ComposableStepBuilder withExecutionParameters(Map executionParameters) {
            this.overrideExecutionParameters = executionParameters;
            return this;
        }

        public ComposableStepBuilder withImplementation(String implementation) {
            this.implementation = ofNullable(implementation);
            return this;
        }

        public ComposableStepBuilder withStrategy(Strategy strategy) {
            this.strategy = strategy;
            return this;
        }

        public ComposableStepBuilder withTags(List tags) {
            this.tags = tags;
            return this;
        }

        public final ComposableStepBuilder from(ComposableStep instance) {
            this.id = instance.id;
            this.name = instance.name;
            this.steps = instance.steps;
            this.defaultParameters = instance.defaultParameters;
            this.implementation = instance.implementation;
            this.strategy = instance.strategy;
            return this;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy