Package au.com.ds.ef

Source Code of au.com.ds.ef.EasyFlow

package au.com.ds.ef;

import au.com.ds.ef.call.*;
import au.com.ds.ef.err.ExecutionError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Executor;


public class EasyFlow<C extends StatefulContext> {
    static Logger log = LoggerFactory.getLogger(EasyFlow.class);
    protected State<C> startState;
    private C context;
    private Executor executor;
    private boolean validated;
    private boolean skipValidation = false;

    private StateHandler<C> onStateEnterHandler;
    private StateHandler<C> onStateLeaveHandler;
    private StateHandler<C> onFinalStateHandler;
    private EventHandler<C> onEventTriggeredHandler;
    private ContextHandler<C> onTerminateHandler;
    private ExecutionErrorHandler onError;
    private boolean trace = false;

    protected EasyFlow(State<C> startState, TransitionBuilder<C>... transitions) {
        this.startState = startState;
        this.validated = false;
        for (TransitionBuilder<C> transition : transitions) {
            startState.addEvent(transition.getEvent(), transition.getStateTo());
        }
    }

    private void prepare() {
        startState.setFlowRunner(this);
        if (executor == null) {
            executor = new AsyncExecutor();
        }

        if (onError == null) {
            onError = new DefaultErrorHandler();
        }
    }

    public EasyFlow<C> validate() {
        if (!validated) {
            prepare();

            if (!skipValidation) {
                LogicValidator<C> validator = new LogicValidator<C>(startState);
                validator.validate();
            }
            validated = true;
        }

        return this;
    }

    public void start(final C context) {
        validate();
        this.context = context;

        if (context.getState() == null) {
            setCurrentState(startState, context);
        }
    }

    protected void setCurrentState(final State<C> state, final C context) {
        execute(new Runnable() {
            @Override
            public void run() {
                if (isTrace())
                    log.debug("setting current state to {} for {} <<<", state, context);

                State<C> prevState = context.getState();
                if (prevState != null) {
                    prevState.leave(context);
                }

                context.setState(state);
                context.getState().enter(context);

                if (isTrace())
                    log.debug("setting current state to {} for {} >>>", state, context);
            }
        });
    }

    protected void execute(Runnable task) {
        executor.execute(task);
    }

    public C getContext() {
        return context;
    }

    public EasyFlow<C> whenEventTriggered(EventHandler<C> onEventTriggered) {
        this.onEventTriggeredHandler = onEventTriggered;
        return this;
    }

    protected void callOnEventTriggered(Event<C> event, State<C> from, State<C> to, C context) throws Exception {
        if (onEventTriggeredHandler != null) {
            try {
                if (isTrace())
                    log.debug("when triggered {} in {} for {} <<<", event, from, context);

                onEventTriggeredHandler.call(event, from, to, context);

                if (isTrace())
                    log.debug("when triggered {} in {} for {} >>>", event, from, context);
            } catch (Exception e) {
                callOnError(new ExecutionError(from, event, e,
                    "Execution Error in [EasyFlow.whenEventTriggered] handler", context));
            }
        }
    }

    public EasyFlow<C> whenStateEnter(StateHandler<C> onStateEnter) {
        this.onStateEnterHandler = onStateEnter;
        return this;
    }

    protected void callOnStateEnter(final State<C> state, final C context) {
        if (onStateEnterHandler != null) {
            try {
                if (isTrace())
                    log.debug("when enter state {} for {} <<<", state, context);

                onStateEnterHandler.call(state, context);

                if (isTrace())
                    log.debug("when enter state {} for {} >>>", state, context);
            } catch (Exception e) {
                callOnError(new ExecutionError(state, null, e,
                    "Execution Error in [EasyFlow.whenStateEnter] handler", context));
            }
        }
    }

    public EasyFlow<C> whenStateLeave(StateHandler<C> onStateLeave) {
        this.onStateLeaveHandler = onStateLeave;
        return this;
    }

    protected void callOnStateLeave(final State<C> state, final C context) {
        if (onStateLeaveHandler != null) {
            try {
                if (isTrace())
                    log.debug("when leave state {} for {} <<<", state, context);

                onStateLeaveHandler.call(state, context);

                if (isTrace())
                    log.debug("when leave state {} for {} >>>", state, context);
            } catch (Exception e) {
                callOnError(new ExecutionError(state, null, e,
                    "Execution Error in [EasyFlow.whenStateLeave] handler", context));
            }
        }
    }

    public EasyFlow<C> whenFinalState(StateHandler<C> onFinalState) {
        this.onFinalStateHandler = onFinalState;
        return this;
    }

    protected void callOnFinalState(final State<C> state, final C context) {
        try {
            if (onFinalStateHandler != null) {
                if (isTrace())
                    log.debug("when final state {} for {} <<<", state, context);

                onFinalStateHandler.call(state, context);

                if (isTrace())
                    log.debug("when final state {} for {} >>>", state, context);
            }

            callOnTerminate(context);
        } catch (Exception e) {
            callOnError(new ExecutionError(state, null, e,
                "Execution Error in [EasyFlow.whenFinalState] handler", context));
        }
    }

    public EasyFlow<C> whenError(ExecutionErrorHandler onError) {
        this.onError = onError;
        return this;
    }

    public EasyFlow<C> whenTerminate(ContextHandler onTerminateHandler) {
        this.onTerminateHandler = onTerminateHandler;
        return this;
    }

    public void waitForCompletion() {
        waitForCompletion(context);
    }

    public void waitForCompletion(C context) {
      context.awaitTermination();
    }

    public EasyFlow<C> executor(Executor executor) {
        this.executor = executor;
        return this;
    }

    public EasyFlow<C> trace() {
        trace = true;
        return this;
    }

    public EasyFlow<C> skipValidation() {
        skipValidation = true;
        return this;
    }

    protected boolean isTrace() {
        return trace;
    }

    protected void callOnError(final ExecutionError error) {
        if (onError != null) {
            onError.call(error);
        }
        callOnTerminate((C) error.getContext());
    }

    protected void callOnTerminate(final C context) {
        if (!context.isTerminated()) {
            try {
                if (isTrace())
                    log.debug("terminating context {}", context);

                context.setTerminated();
                if (onTerminateHandler != null){
                    if (isTrace())
                        log.debug("when terminate for {} <<<", context);

                    onTerminateHandler.call(context);

                    if (isTrace())
                        log.debug("when terminate for {} >>>", context);
                }
            } catch (Exception e) {
                log.error("Execution Error in [EasyFlow.whenTerminate] handler", e);
            }
        }
    }
}
TOP

Related Classes of au.com.ds.ef.EasyFlow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.