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

functionalj.promise.DeferActionBuilder Maven / Gradle / Ivy

// ============================================================================
// Copyright (c) 2017-2019 Nawapunth Manusitthipol (NawaMan - http://nawaman.net).
// ----------------------------------------------------------------------------
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ============================================================================
package functionalj.promise;

import static java.util.Objects.requireNonNull;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;

import functionalj.environments.AsyncRunner;
import functionalj.function.Func0;
import functionalj.function.Func1;
import functionalj.function.FuncUnit0;
import functionalj.list.FuncList;
import functionalj.result.Result;
import functionalj.task.Task;
import lombok.val;

public class DeferActionBuilder implements Task {
    
    public static  RetryConfig Retry(int times) {
        return new RetryConfig(times);
    }
    
    public static  Function, DeferActionBuilder> InterruptOnCancel(boolean interruptOnCancel) {
        return builder -> builder.interruptOnCancel(interruptOnCancel);
    }
    
    public static  Function, DeferActionBuilder> OnStart(FuncUnit0 onStart) {
        return builder -> builder.onStart(onStart);
    }
    public static  Function, DeferActionBuilder> Runner(AsyncRunner runner) {
        return builder -> builder.runner(runner);
    }
    
    // TODO - Add other configuration.
    
    private static final FuncUnit0 DO_NOTHING = ()->{};
    
    private final String      toString;
    private final Func0 supplier;
    private boolean           interruptOnCancel = true;
    private FuncUnit0         onStart           = DO_NOTHING;
    private AsyncRunner       runner            = null;
    
    @SuppressWarnings("unchecked")
    private Retry retry = (Retry)Retry.noRetry;
    
    public static final  DeferActionBuilder from(FuncUnit0 runnable) {
        return new DeferActionBuilder<>(runnable);
    }
    public static final  DeferActionBuilder from(Func0 supplier) {
        return new DeferActionBuilder<>(supplier);
    }
    public static final  DeferActionBuilder from(String toString, FuncUnit0 runnable) {
        return new DeferActionBuilder<>(toString, runnable);
    }
    public static final  DeferActionBuilder from(String toString, Func0 supplier) {
        return new DeferActionBuilder<>(toString, supplier);
    }
    
    public DeferActionBuilder(FuncUnit0 runnable) {
        this(null, runnable);
    }
    public DeferActionBuilder(String toString, FuncUnit0 runnable) {
        this(toString, runnable.thenReturnNull());
    }
    
    public DeferActionBuilder(Func0 supplier) {
        this(null, supplier);
    }
    public DeferActionBuilder(String toString, Func0 supplier) {
        this.toString = (toString != null) ? toString : "Task#" + supplier.toString();
        this.supplier = requireNonNull(supplier);
    }
    
    // TODO - Find the way to make this work without resorting to "Object"
    @SafeVarargs
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public final DeferActionBuilder config(Function , DeferActionBuilder> ... configs) {
        if (configs == null)
            return this;
        
        val configList = FuncList.of(configs).filterNonNull();
        val current    = new AtomicReference<>(this);
        configList.forEach(config -> {
            val curBuilder = current.get();
            val newBuilder = config.apply((DeferActionBuilder)curBuilder);
            val nextBuilder
                    = (newBuilder == null)
                    ? curBuilder
                    : (DeferActionBuilder)newBuilder;
            current.set(nextBuilder);
        });
        return current.get();
    }
    
    protected Func0 supplier() {
        return this.supplier;
    }
    
    boolean interruptOnCancel() {
        return this.interruptOnCancel;
    }
    
    public DeferActionBuilder interruptOnCancel(boolean interruptOnCancel) {
        this.interruptOnCancel = interruptOnCancel;
        return this;
    }
    
    FuncUnit0 onStart() {
        return this.onStart;
    }
    
    public DeferActionBuilder onStart(FuncUnit0 onStart) {
        this.onStart = (onStart != null) ? onStart : DO_NOTHING;
        return this;
    }
    
    AsyncRunner runner() {
        return this.runner;
    }
    
    public DeferActionBuilder runner(AsyncRunner runner) {
        this.runner = runner;
        return this;
    }
    
    public DeferActionBuilder loopTimes(int times) {
        this.retry = new Loop(times);
        return this;
    }
    public DeferActionBuilder loopUntil(Func1, Boolean> stopPredicate) {
        this.retry = new Loop(stopPredicate);
        return this;
    }
    
    public DeferActionBuilder retry(int times, long periodMillisecond) {
        this.retry = new Retry(times, periodMillisecond);
        return this;
    }
    public DeferActionBuilder retry(Retry retry) {
        this.retry = (retry != null) ? retry : Retry.defaultRetry();
        return this;
    }
    
    @SuppressWarnings("unchecked")
    public DeferActionBuilder noRetry() {
        this.retry = Retry.noRetry;
        return this;
    }
    
    public WaitRetryBuilder retryForever() {
        return new WaitRetryBuilder(this, Retry.RETRY_FOREVER);
    }
    
    public RetryBuilderTimes retry(int times) {
        return new RetryBuilderTimes(this, times);
    }
    
    public DeferAction build() {
        return retry.create(this);
    }
    
    public DeferAction createAction() {
        return build();
    }
    
    @Override
    public String toString() {
        return toString;
    }
    
    //== Aux classes ==
    
    public static class RetryBuilderTimes {
        private final DeferActionBuilder actionBuilder;
        private final int                      times;
        
        RetryBuilderTimes(DeferActionBuilder actionBuilder, int times) {
            this.actionBuilder = actionBuilder;
            this.times         = times;
        }
        
        public WaitRetryBuilder times() {
            return new WaitRetryBuilder(actionBuilder, times);
        }
        
    }
    
    public static class WaitRetryBuilder {
        private final DeferActionBuilder actionBuilder;
        private final int                      times;
        
        WaitRetryBuilder(DeferActionBuilder actionBuilder, int times) {
            this.actionBuilder = actionBuilder;
            this.times         = times;
        }
        
        public DeferActionBuilder noWaitInBetween() {
            actionBuilder.retry = new Retry(times, Retry.NO_WAIT);
            return actionBuilder;
        }
        
        public WaitRetryBuilderUnit waitFor(long period) {
            return new WaitRetryBuilderUnit(actionBuilder, times, period);
        }
        
    }
    
    public static class WaitRetryBuilderUnit {
        private final DeferActionBuilder actionBuilder;
        private final int                      times;
        private final long                     period;
        
        WaitRetryBuilderUnit(DeferActionBuilder actionBuilder, int times, long period) {
            this.actionBuilder = actionBuilder;
            this.times         = times;
            this.period        = period;
        }
        
        public DeferActionBuilder milliseconds() {
            val retry = new Retry(times, period);
            actionBuilder.retry = retry;
            return actionBuilder;
        }
        
        public DeferActionBuilder seconds() {
            val retry = new Retry(times, period * 1000);
            actionBuilder.retry = retry;
            return actionBuilder;
        }
        
        public DeferActionBuilder minutes() {
            val retry = new Retry(times, period * 1000 * 60);
            actionBuilder.retry = retry;
            return actionBuilder;
        }
        
        public DeferActionBuilder hours() {
            val retry = new Retry(times, period * 1000 * 60 * 60);
            actionBuilder.retry = retry;
            return actionBuilder;
        }
        
        public DeferActionBuilder days() {
            val retry = new Retry(times, period * 1000 * 60 * 60 * 24);
            actionBuilder.retry = retry;
            return actionBuilder;
        }
        
        public DeferActionBuilder weeks() {
            val retry = new Retry(times, period * 1000 * 60 * 60 * 24);
            actionBuilder.retry = retry;
            return actionBuilder;
        }
        
    }
    
}