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

com.github.oxo42.stateless4j.StateRepresentation Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
package com.github.oxo42.stateless4j;

import com.github.oxo42.stateless4j.delegates.Action1;
import com.github.oxo42.stateless4j.delegates.Action2;
import com.github.oxo42.stateless4j.transitions.Transition;
import com.github.oxo42.stateless4j.triggers.TriggerBehaviour;

import java.util.*;

public class StateRepresentation {
    private final TState state;

    private final Map>> triggerBehaviours = new HashMap<>();
    private final List, Object[]>> entryActions = new ArrayList<>();
    private final List>> exitActions = new ArrayList<>();
    private final List> substates = new ArrayList<>();
    private StateRepresentation superstate; // null

    public StateRepresentation(TState state) {
        this.state = state;
    }

    protected Map>> getTriggerBehaviours() {
        return triggerBehaviours;
    }

    public Boolean canHandle(TTrigger trigger) {
        return tryFindHandler(trigger) != null;
    }

    public TriggerBehaviour tryFindHandler(TTrigger trigger) {
        TriggerBehaviour result = tryFindLocalHandler(trigger);
        if (result == null && superstate != null) {
            result = superstate.tryFindHandler(trigger);
        }
        return result;
    }

    TriggerBehaviour tryFindLocalHandler(TTrigger trigger/*, out TriggerBehaviour handler*/) {
        List> possible = triggerBehaviours.get(trigger);
        if (possible == null) {
            return null;
        }

        List> actual = new ArrayList<>();
        for (TriggerBehaviour triggerBehaviour : possible) {
            if (triggerBehaviour.isGuardConditionMet()) {
                actual.add(triggerBehaviour);
            }
        }

        if (actual.size() > 1) {
            throw new IllegalStateException("Multiple permitted exit transitions are configured from state '" + trigger + "' for trigger '" + state + "'. Guard clauses must be mutually exclusive.");
        }

        return actual.get(0);
    }

    public void addEntryAction(final TTrigger trigger, final Action2, Object[]> action) {
        assert action != null : "action is null";

        entryActions.add(new Action2, Object[]>() {
            @Override
            public void doIt(Transition t, Object[] args) {
                if (t.getTrigger().equals(trigger)) {
                    action.doIt(t, args);
                }
            }
        });
    }

    public void addEntryAction(Action2, Object[]> action) {
        assert action != null : "action is null";
        entryActions.add(action);
    }

    public void insertEntryAction(Action2, Object[]> action) {
        assert action != null : "action is null";
        entryActions.add(0, action);
    }

    public void addExitAction(Action1> action) {
        assert action != null : "action is null";
        exitActions.add(action);
    }

    public void enter(Transition transition, Object... entryArgs) {
        assert transition != null : "transition is null";

        if (transition.isReentry()) {
            executeEntryActions(transition, entryArgs);
        } else if (!includes(transition.getSource())) {
            if (superstate != null) {
                superstate.enter(transition, entryArgs);
            }

            executeEntryActions(transition, entryArgs);
        }
    }

    public void exit(Transition transition) {
        assert transition != null : "transition is null";

        if (transition.isReentry()) {
            executeExitActions(transition);
        } else if (!includes(transition.getDestination())) {
            executeExitActions(transition);
            if (superstate != null) {
                superstate.exit(transition);
            }
        }
    }

    void executeEntryActions(Transition transition, Object[] entryArgs) {
        assert transition != null : "transition is null";
        assert entryArgs != null : "entryArgs is null";
        for (Action2, Object[]> action : entryActions) {
            action.doIt(transition, entryArgs);
        }
    }

    void executeExitActions(Transition transition) {
        assert transition != null : "transition is null";
        for (Action1> action : exitActions) {
            action.doIt(transition);
        }
    }

    public void addTriggerBehaviour(TriggerBehaviour triggerBehaviour) {
        List> allowed;
        if (!triggerBehaviours.containsKey(triggerBehaviour.getTrigger())) {
            allowed = new ArrayList<>();
            triggerBehaviours.put(triggerBehaviour.getTrigger(), allowed);
        }
        allowed = triggerBehaviours.get(triggerBehaviour.getTrigger());
        allowed.add(triggerBehaviour);
    }

    public StateRepresentation getSuperstate() {
        return superstate;
    }

    public void setSuperstate(StateRepresentation value) {
        superstate = value;
    }

    public TState getUnderlyingState() {
        return state;
    }

    public void addSubstate(StateRepresentation substate) {
        assert substate != null : "substate is null";
        substates.add(substate);
    }

    public boolean includes(TState stateToCheck) {
        for (StateRepresentation s : substates) {
            if (s.includes(stateToCheck)) {
                return true;
            }
        }
        return this.state.equals(stateToCheck);
    }

    public boolean isIncludedIn(TState stateToCheck) {
        return this.state.equals(stateToCheck) || (superstate != null && superstate.isIncludedIn(stateToCheck));
    }

    @SuppressWarnings("unchecked")
    public List getPermittedTriggers() {
        Set result = new HashSet<>();

        for (TTrigger t : triggerBehaviours.keySet()) {
            for (TriggerBehaviour v : triggerBehaviours.get(t)) {
                if (v.isGuardConditionMet()) {
                    result.add(t);
                    break;
                }
            }
        }

        if (getSuperstate() != null) {
            result.addAll(getSuperstate().getPermittedTriggers());
        }

        return new ArrayList<>(result);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy