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

cn.xnatural.enet.common.task.Step Maven / Gradle / Ivy

package cn.xnatural.enet.common.task;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 执行步骤/执行节点
 * 每个 Step 通过 {@link #next()} 顺序关联
 * 核心方法: {@link #run()}
 * @param   输入参数类型
 * @param   步骤返回值类型
 */
public class Step {
    /**
     * 执行步骤 的名称
     */
    private   String            name;
    /**
     * 执行步骤 的说明
     */
    private   String            description;
    /**
     * 开始执行时间
     */
    private   long              startTime;
    /**
     * 执行时所需的参数
     */
    protected I                 param;
    /**
     * 保存执行结果.
     */
    protected R                 result;
    /**
     * 执行次数
     */
    protected AtomicInteger     count = new AtomicInteger(0);
    /**
     * 执行体(当前Step的主要执行逻辑)
     */
    protected Function    fn;
    /**
     * 下一个 {@link Step} 判断的函数
     * 返回下一个 执行的 {@link Step}
     */
    protected Function nextStepFn;
    /**
     * 如果为true 则 暂停下一个步骤
     */
    private   boolean           suspendNext;
    /**
     * 所属Task
     */
    protected final TaskWrapper       task;
    /**
     * Step 唯一标识
     */
    protected       String            key;

    public Step(TaskWrapper task, Function fn, Function nextStepFn) {
        this.task = task;
        this.fn = fn;
        this.nextStepFn = nextStepFn;
    }

    /**
     * nextStep 默认指向 StopStep
     * @param task
     * @param fn
     */
    public Step(TaskWrapper task, Function fn) {
        this(task, fn, r -> task.stopStep()); // 默认 指向 StopStep
    }
    public Step(TaskWrapper task) {
        this(task, null);
    }

    /**
     * 不用 输入参数的 Step
     * @param 
     */
    public static class NoInputStep extends Step {
        public NoInputStep(TaskWrapper task, Supplier fn, Function nextStepFn) {
            super(task, aVoid -> fn.get(), nextStepFn);
        }
        public NoInputStep(TaskWrapper task, Function fn) {
            super(task, fn);
        }
        public NoInputStep(TaskWrapper task) {
            super(task);
        }

        @Override
        public Step setParam(Void param) {
            throw new UnsupportedOperationException("NoInputStep not should have input param");
        }
    }

    /**
     * 不用 输出参数的 Step
     * @param 
     */
    public static class NoOutStep extends Step {
        public NoOutStep(TaskWrapper task, Consumer fn, Function nextStepFn) {
            super(task, i -> { fn.accept(i); return null; }, nextStepFn);
        }
        public NoOutStep(TaskWrapper task, Consumer fn) {
            super(task, i -> { fn.accept(i); return null; });
        }
        public NoOutStep(TaskWrapper task) {
            super(task);
        }
    }

    /**
     * 任务Task 停止Step,也是最后一个Step
     * @param 
     */
    protected static class StopStep extends NoOutStep {
        public StopStep(TaskWrapper task, Consumer fn) {
            super(task, fn);
        }
        public StopStep(TaskWrapper task) { super(task); }

        @Override
        protected Step next() {
            return null;
        }
        @Override
        public Step setNextStepFn(Function nextStepFn) {
            throw new UnsupportedOperationException("StopStep not need nextStepFn");
        }
    }


    /**
     * 封闭执行的 Task, 没有输入参数, 也没有返回值
     */
    public static class ClosureStep extends Step {
        public ClosureStep(TaskWrapper task) { super(task); }
        public ClosureStep(TaskWrapper task, Consumer fn) {
            super(task, aVoid -> { fn.accept(null); return null; });
        }
        public ClosureStep(TaskWrapper task, Runnable fn, Supplier nextStepSupplier) {
            super(task, aVoid -> { fn.run(); return null; }, aVoid -> nextStepSupplier.get());
        }
    }

    /**
     * 可重复执行的Step
     * @param 
     * @param 
     */
    public static class RetryStep extends Step {
        /**
         * 重试时, 须手动设置为 false
         */
        private boolean complete;
        private Function retryFn;
        private Function paramFn;

        public RetryStep(TaskWrapper task) { super(task); }
        public RetryStep(TaskWrapper task, Function fn, Function retryFn, Function nextStepFn) {
            super(task, fn, nextStepFn);
            this.retryFn = retryFn;
        }

        @Override
        protected void process() {
            count.getAndIncrement();
            if (count.get() > 1) {
                if (retryFn == null) throw new NullPointerException(getKey() + ": retryFn is null");
                if (paramFn != null) param = paramFn.apply(this); //重新计算输入的参数
                result = retryFn.apply(param);
            } else {
                if (fn == null) throw new NullPointerException(getKey() + ": fn is null");
                result = fn.apply(param);
            }
            complete = true;
        }

        public RetryStep setRetryFn(Function retryFn) {
            this.retryFn = retryFn;
            return this;
        }

        public Function getRetryFn() {
            return retryFn;
        }

        @Override
        public boolean isComplete() {
            return complete;
        }

        public RetryStep setComplete(boolean complete) {
            this.complete = complete;
            return this;
        }

        /**
         * 重新执行
         */
        public final void reRun() {
            complete = false;
            //  task.currentStep(): 即被暂停的Step 有可能 不等于 this.
            // 比如: 一个Task 中有 Step1, Step2, 当 Step2调了suspendNext(), 但之后Step1 调了此方法即ReRun().
            // 那么, 当Step1 reRun 执行完后Step2 却是 suspendNext 状态. 所以 这里, 要先把 被暂停的Step 的 suspendNext 设置为false
            if (task.currentStep() != this) task.currentStep().suspendNext = false;
            task.currentStep(this);
            if (isWaitingNext()) continueNext();
            else task.trigger();
        }

        /**
         * 参数获取函数,
         * 因为RetryStep可能每次的参数不一样
         * @param paramFn
         * @return
         */
        public RetryStep paramFn(Function paramFn) {
            this.paramFn = paramFn;
            param = paramFn.apply(this);
            return this;
        }

        @Override
        public Step setParam(I param) {
            throw new UnsupportedOperationException("Please use method paramFn");
        }
    }

    /**
     * Step执行
     * @return 下一个执行Step
     */
    public final Step run() {
        startTime = System.currentTimeMillis();
        process();
        // endTime
        return next();
    }

    /**
     * @return 如果 返回 null , 应该是 任务结束 或 应该是 任务暂停
     */
    protected Step next() {
        if (task.isShouldStop()) return task.stopStep();
        if (suspendNext) return null;
        return (nextStepFn == null ? null : nextStepFn.apply(result));
    }

    /**
     * 调用执行函数
     */
    protected void process() {
        if (fn == null) throw new NullPointerException(getKey() + ": fn is null");
        // 如果已执行过了 则直接返回
        if (count.incrementAndGet() > 1) {
            task.log.error("Step被重复执行, Task被强制Stop!!!");
            task.shouldStop();
            return;
        }
        result = fn.apply(param);
        if (this instanceof StopStep) {
            task.stopped.compareAndSet(false, true);
        }
    }

    /**
     * 挂起/暂停
     * 等待
     */
    public final void suspendNext() {
        suspendNext = true;
    }

    /**
     * 是否被 暂停 中
     * @return
     */
    public final boolean isWaitingNext() {
        return suspendNext;
    }

    /**
     * 恢复执行
     */
    public final void continueNext() {
        suspendNext = false;
        task.trigger();
    }

    public String getKey() {
        if (key == null) {
            key = task.getKey() + " Step: " + name + "";
        }
        return key;
    }

    public boolean isComplete() {
        return count.get() >= 1;
    }

    public Step setParam(I param) {
        this.param = param;
        return this;
    }

    public Step setNextStepFn(Function nextStepFn) {
        this.nextStepFn = nextStepFn;
        return this;
    }

    public Function getNextStepFn() {
        return nextStepFn;
    }

    public Step setFn(Function fn) {
        this.fn = fn;
        return this;
    }


    public Function getFn() {
        return fn;
    }


    public final R getResult() {
        return result;
    }

    public String getName() {
        return name;
    }

    public Step setName(String name) {
        this.name = name;
        return this;
    }

    public String getDescription() {
        return description;
    }

    public Step setDescription(String description) {
        this.description = description;
        return this;
    }

    public TaskWrapper getTask() {
        return task;
    }
}