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

com.ocadotechnology.scenario.StepManager Maven / Gradle / Ivy

There is a newer version: 16.6.21
Show newest version
/*
 * Copyright © 2017-2023 Ocado (Ocava)
 *
 * 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.ocadotechnology.scenario;

import static com.ocadotechnology.scenario.StepManager.ExecuteStepExecutionType.Type.PERIODIC;

import java.util.Optional;
import java.util.OptionalDouble;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import com.ocadotechnology.event.scheduling.EventScheduler;
import com.ocadotechnology.id.StringIdGenerator;
import com.ocadotechnology.simulation.Simulation;
import com.ocadotechnology.validation.Failer;

public class StepManager {
    private final StepCache stepsCache;
    protected final ScenarioSimulationApi simulation;
    protected final NotificationCache notificationCache;
    protected final ScenarioNotificationListener listener;

    public StepManager(StepCache stepsCache, ScenarioSimulationApi simulation, NotificationCache notificationCache, ScenarioNotificationListener listener) {
        this.stepsCache = stepsCache;
        this.simulation = simulation;
        this.notificationCache = notificationCache;
        this.listener = listener;
    }

    public StepCache getStepsCache() {
        return stepsCache;
    }

    public S getSimulation() {
        return simulation.getSimulation();
    }

    public TimeUnit getTimeUnit() {
        return simulation.getSchedulerTimeUnit();
    }

    public void add(CheckStep checkStep, CheckStepExecutionType checkStepExecutionType) {
        if (checkStepExecutionType.isOrdered()) {
            addOrderedCheckStep(checkStepExecutionType, checkStep);
        } else {
            addUnorderedStepOnExecutionOfStep(checkStepExecutionType, checkStep);
        }
    }

    private void addOrderedCheckStep(CheckStepExecutionType checkStepExecutionType, CheckStep baseStep) {
        CheckStep checkStep = checkStepExecutionType.createOrderedStep(baseStep);
        checkStep.setStepName(LoggerUtil.getStepName());
        checkStep.setStepOrder(stepsCache.getNextStepCounter());
        notificationCache.addKnownNotification(checkStep.getType());
        stepsCache.addOrdered(checkStep);

        if (checkStepExecutionType.isFailingStep()) {
            stepsCache.addFailingStep(checkStep);
        }
    }

    public void add(String name, ValidationStep step) {
        step.setStepName(LoggerUtil.getStepName());
        step.setStepOrder(stepsCache.getNextStepCounter());
        step.setName(name);
        notificationCache.addKnownNotification(step.getType());
        stepsCache.addUnordered(name, step);
    }

    public void add(BroadcastStep broadcastStep) {
        broadcastStep.setStepOrder(stepsCache.getNextStepCounter());
        broadcastStep.setStepName(LoggerUtil.getStepName());
        stepsCache.addOrdered(broadcastStep);
    }

    public void add(ExceptionCheckStep exceptionCheckStep) {
        exceptionCheckStep.setStepOrder(stepsCache.getNextStepCounter());
        exceptionCheckStep.setStepName(LoggerUtil.getStepName());
        stepsCache.addCheckStep(exceptionCheckStep);
    }

    public void add(ExecuteStep executeStep) {
        add(executeStep, false);
    }

    public void add(ExecuteStep executeStep, boolean isFailingStep) {
        executeStep.setStepOrder(stepsCache.getNextStepCounter());
        executeStep.setStepName(LoggerUtil.getStepName());
        stepsCache.addOrdered(executeStep);
        if (isFailingStep) {
            stepsCache.addFailingStep(executeStep);
        }
    }

    public void addExecuteStep(Runnable r) {
        add(new SimpleExecuteStep(r));
    }

    public void add(PeriodicExecuteStep periodicExecuteStep) {
        periodicExecuteStep.setStepOrder(stepsCache.getNextStepCounter());
        periodicExecuteStep.setStepName(LoggerUtil.getStepName());
        stepsCache.addOrdered(periodicExecuteStep);
    }

    public void add(ExecuteStep executeStep, ExecuteStepExecutionType executeStepExecutionType) {
        if (executeStepExecutionType.type == ExecuteStepExecutionType.Type.ORDERED) {
            add(executeStep);
        } else if (executeStepExecutionType.type == PERIODIC) {
            add(new PeriodicExecuteStep(executeStep, executeStepExecutionType.getScheduler(), executeStepExecutionType.getPeriod()));
        } else {
            throw Failer.fail("Unhandled Execute step type");
        }
    }

    public void addFinal(ExecuteStep executeStep) {
        executeStep.setStepOrder(stepsCache.getNextStepCounter());
        executeStep.setStepName(LoggerUtil.getStepName());
        stepsCache.addFinalStep(executeStep);
    }

    public void add(String name, ExecuteStep executeStep) {
        executeStep.setStepOrder(stepsCache.getNextStepCounter());
        executeStep.setStepName(LoggerUtil.getStepName());
        executeStep.setName(name);
        stepsCache.addUnordered(name, executeStep);
    }

    public void add(WaitStep scheduledStep) {
        scheduledStep.setStepOrder(stepsCache.getNextStepCounter());
        scheduledStep.setStepName(LoggerUtil.getStepName());
        stepsCache.addOrdered(scheduledStep);
    }

    public void add(ScheduledStep scheduledStep) {
        scheduledStep.setStepOrder(stepsCache.getNextStepCounter());
        scheduledStep.setStepName(LoggerUtil.getStepName());
        stepsCache.addOrdered(scheduledStep);
    }

    private void addUnorderedStepOnExecutionOfStep(CheckStepExecutionType checkStepExecutionType, CheckStep testStep) {
        notificationCache.addKnownNotification(testStep.getType());

        add(new ExecuteStep() {
            @Override
            protected void executeStep() {
                UnorderedCheckStep step = checkStepExecutionType.createUnorderedStep(testStep);
                if (checkStepExecutionType.isFailingStep()) {
                    // Remove the original step added and replace with the new wrapped step
                    stepsCache.removeFailingStep(testStep);
                    stepsCache.addFailingStep(step);
                }

                notificationCache.resetUnorderedNotification();
                addUnordered(checkStepExecutionType.getName(), step, getStepName(), getStepOrder());
            }
        });
    }

    private void addUnordered(String name, UnorderedCheckStep testStep, String stepName, int stepOrder) {
        testStep.setStepOrder(stepOrder);
        testStep.setStepName(stepName);
        testStep.setName(name);
        notificationCache.addKnownNotification(testStep.getType());
        stepsCache.addUnordered(name, testStep);
    }

    public static class ExecuteStepExecutionType {
        enum Type {ORDERED, PERIODIC}

        private final Optional> schedulerSupplier;
        private final OptionalDouble period;
        private final String name;
        private final Type type;

        private ExecuteStepExecutionType(String name, Type type) {
            this.name = name;
            this.type = type;
            this.schedulerSupplier = Optional.empty();
            this.period = OptionalDouble.empty();
        }

        private ExecuteStepExecutionType(String name, Type type, Optional> schedulerSupplier, OptionalDouble period) {
            this.name = name;
            this.type = type;
            this.schedulerSupplier = schedulerSupplier;
            this.period = period;
        }

        public EventScheduler getScheduler() {
            return schedulerSupplier.orElseThrow(() -> Failer.fail("Scheduler was not set")).get();
        }

        public double getPeriod() {
            return period.orElseThrow(() -> Failer.fail("Period not provided"));
        }

        public static ExecuteStepExecutionType ordered() {
            return new ExecuteStepExecutionType(nextId(), Type.ORDERED);
        }

        public static ExecuteStepExecutionType periodic(String name, Supplier schedulerSupplier, double period) {
            return new ExecuteStepExecutionType(name, PERIODIC, Optional.of(schedulerSupplier), OptionalDouble.of(period));
        }

        public static ExecuteStepExecutionType periodic(Supplier schedulerSupplier, double period) {
            return periodic(nextId(), schedulerSupplier, period);
        }

        private static String nextId() {
            return StringIdGenerator.getId(ExecuteStepExecutionType.class).id;
        }
    }
}