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

org.squirrelframework.foundation.fsm.impl.StateMachineDataImpl Maven / Gradle / Ivy

package org.squirrelframework.foundation.fsm.impl;

import static com.google.common.base.Preconditions.checkState;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.squirrelframework.foundation.fsm.*;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Maps;

public class StateMachineDataImpl, S, E, C>
        implements StateMachineData,
        StateMachineData.Reader,
        StateMachineData.Writer {

    private static final long serialVersionUID = 4102325896046410596L;

    private static final Logger logger = LoggerFactory
            .getLogger(StateMachineDataImpl.class);

    private S currentState;

    private S lastState;

    private S initialState;

    private final Map lastActiveChildStateStore = Maps.newHashMap();

    private final ListMultimap parallelStatesStore = ArrayListMultimap.create();

    private Class stateMachineType;

    private Class stateType;

    private Class eventType;

    private Class contextType;
    
    private String identifier;

    private Object startContext;

    private final transient Map> states;

    private Map, S, E, C>> linkStateDataStore;

    public StateMachineDataImpl(Map> states) {
        this.states = Collections.unmodifiableMap(states);
    }

    public StateMachineDataImpl() {
        this.states = null;
    }

    @Override
    public Map> originalStates() {
        if (states == null) {
            return Collections.emptyMap();
        }
        return states;
    }
    
    private void clear() {
        currentState = null;
        lastState = null;
        initialState = null;
        stateMachineType = null;
        stateType = null;
        eventType = null;
        contextType = null;
        identifier = null;
        startContext = null;
        if(lastActiveChildStateStore!=null) {
            lastActiveChildStateStore.clear();
        }
        if(parallelStatesStore!=null) {
            parallelStatesStore.clear();
        }
        if(linkStateDataStore!=null) {
            linkStateDataStore.clear();
        }
    }

    @Override
    public void dump(StateMachineData.Reader src) {
        clear();
        
        this.write().typeOfStateMachine(src.typeOfStateMachine());
        this.write().typeOfState(src.typeOfState());
        this.write().typeOfEvent(src.typeOfEvent());
        this.write().typeOfContext(src.typeOfContext());

        this.write().identifier(src.identifier());
        this.write().currentState(src.currentState());
        this.write().lastState(src.lastState());
        this.write().initialState(src.initialState());
        // write start context of state machine
        this.write().startContext(src.startContext());

        for (S state : src.activeParentStates()) {
            S lastActiveChildState = src.lastActiveChildStateOf(state);
            if (lastActiveChildState != null) {
                this.write().lastActiveChildStateFor(state, lastActiveChildState);
            }
        }

        for (S state : src.parallelStates()) {
            List subStates = src.subStatesOn(state);
            if (subStates != null && !subStates.isEmpty()) {
                for (S subState : subStates) {
                    // ignore parallel state check in subStateFor as no states
                    // for reference
                    // this.write().subStateFor(state, subState);
                    parallelStatesStore.put(state, subState);
                }
            }
        }
    }

    private Map, S, E, C>> getLinkedStateData() {
        if (linkStateDataStore == null) {
            linkStateDataStore = Maps.newHashMap();
        }
        return linkStateDataStore;
    }

    @Override
    public StateMachineData.Reader read() {
        return this;
    }

    @Override
    public StateMachineData.Writer write() {
        return this;
    }

    @Override
    public void currentState(S currentStateId) {
        this.currentState = currentStateId;
    }

    @Override
    public void lastState(S lastStateId) {
        this.lastState = lastStateId;
    }

    @Override
    public void initialState(S initialStateId) {
        this.initialState = initialStateId;
    }

    @Override
    public void startContext(C context) {
        if(context!=null && context instanceof Serializable)
            startContext = context;
    }

    @Override
    public void lastActiveChildStateFor(S parentStateId, S childStateId) {
        lastActiveChildStateStore.put(parentStateId, childStateId);
    }

    @Override
    public void subStateFor(S parentStateId, S subStateId) {
        if (rawStateFrom(parentStateId) != null
                && rawStateFrom(parentStateId).isParallelState()
                && !parallelStatesStore.containsEntry(parentStateId, subStateId)) {
            parallelStatesStore.put(parentStateId, subStateId);
        } else {
            logger.warn("Cannot set sub states on none parallel state {}.",
                    parentStateId);
        }
    }

    @Override
    public void removeSubState(S parentStateId, S subStateId) {
        if (rawStateFrom(parentStateId) != null
                && rawStateFrom(parentStateId).isParallelState()) {
            parallelStatesStore.remove(parentStateId, subStateId);
        } else {
            logger.warn("Cannot remove sub states on none parallel state {}.",
                    parentStateId);
        }
    }

    @Override
    public void removeSubStatesOn(S parentStateId) {
        if (rawStateFrom(parentStateId).isParallelState()) {
            parallelStatesStore.removeAll(parentStateId);
        }
    }
    
    @Override
    public void identifier(String id) {
        this.identifier = id;
    }

    @Override
    public String identifier() {
        return identifier;
    }

    @Override
    public S currentState() {
        return currentState;
    }

    @Override
    public S lastState() {
        return lastState;
    }

    @Override
    public S initialState() {
        return initialState;
    }

    @Override
    public S lastActiveChildStateOf(S parentStateId) {
        return lastActiveChildStateStore.get(parentStateId);
    }

    @Override
    public C startContext() {
        return (C)startContext;
    }

    @Override
    public Collection activeParentStates() {
        return Collections.unmodifiableCollection(lastActiveChildStateStore.keySet());
    }

    @Override
    public List subStatesOn(S parentStateId) {
        List subStates = parallelStatesStore.get(parentStateId);
        return subStates != null ? Collections.unmodifiableList(subStates)
                : Collections. emptyList();
    }

    @Override
    public ImmutableState currentRawState() {
        return currentState!=null ? rawStateFrom(currentState) : null;
    }

    @Override
    public ImmutableState lastRawState() {
        return rawStateFrom(lastState);
    }

    @Override
    public ImmutableState rawStateFrom(S stateId) {
        if(stateId==null) return null;
        ImmutableState rawState = originalStates().get(stateId);
        return rawState!=null ? rawState.getThis() : null;
    }

    @Override
    public ImmutableState initialRawState() {
        return rawStateFrom(initialState());
    }

    @Override
    public Class typeOfStateMachine() {
        return stateMachineType;
    }

    @Override
    public Class typeOfState() {
        return stateType;
    }

    @Override
    public Class typeOfEvent() {
        return eventType;
    }

    @Override
    public Class typeOfContext() {
        return contextType;
    }

    @Override
    public void typeOfStateMachine(Class stateMachineType) {
        checkState(this.stateMachineType==null);
        this.stateMachineType = stateMachineType;
    }

    @Override
    public void typeOfState(Class stateClass) {
        checkState(this.stateType==null);
        this.stateType = stateClass;
    }

    @Override
    public void typeOfEvent(Class eventClass) {
        checkState(this.eventType==null);
        this.eventType = eventClass;
    }

    @Override
    public void typeOfContext(Class contextClass) {
        checkState(this.contextType==null);
        this.contextType = contextClass;
    }

    @Override
    public Collection> rawStates() {
        return Collections.unmodifiableCollection(originalStates().values());
    }

    @Override
    public Collection states() {
        return Collections.unmodifiableCollection(originalStates().keySet());
    }

    @Override
    public Collection parallelStates() {
        return Collections.unmodifiableCollection(parallelStatesStore.keySet());
    }

    @Override
    public Collection linkedStates() {
        if (linkStateDataStore == null || linkStateDataStore.isEmpty()) {
            return Collections.emptySet();
        }
        return Collections.unmodifiableCollection(linkStateDataStore.keySet());
    }

    @Override
    public StateMachineData.Reader, S, E, C> linkedStateDataOf(
            S linkedState) {
        if (linkStateDataStore != null && !linkStateDataStore.isEmpty())
            return linkStateDataStore.get(linkedState);
        return null;
    }

    @Override
    public void linkedStateDataOn(S linkedState,
            StateMachineData.Reader, S, E, C> linkStateData) {
        getLinkedStateData().put(linkedState, linkStateData);
    }
}