.NET: C#: Stateless library: Commit a transaction at the end

Viewed 200

Using Stateless library for .NET I wrote a state machine that does a few things:

  1. Read a barcode ticket
  2. do some validation
  3. check for some more validation
  4. do some digital I/O(turn a light green and open a gate)
  5. frame a transaction and commit it

My StateMachine code is as follows:

public class MainStateMachine
{
    public delegate void tvOnTransitioned(StateMachine<State, Trigger>.Transition otransition);
    public delegate void tvUnhandledTrigger(State estate, Trigger etrigger);
    public delegate void tvEntryExit();
    public delegate bool bnGuardClause();
    public delegate void vLogMsg(string sstring);

    public delegate void tvOnTransition_Barcode(sbarcodeserial);
    StateMachine<State, Trigger>.TriggerWithParameters<string> oBarcode_Trigger_With_Parameters;

    public tvOnTransitioned OnTransitioned = null;
    public tvUnhandledTrigger OnUnhandledTrigger = null;

    #region SuperState
    public tvEntryExit OnEntry_Input = null;
    public tvEntryExit OnExit_Input = null;
    #endregion

    #region Substates_Entry_Exit
    public tvEntryExit OnEntry_CSC_BarcodeValidation = null;
    public tvEntryExit OnEntry_PaymentSatisfied = null;
    public tvEntryExit OnEntry_FrameTransaction = null;
    #endregion

    #region Transitions
    public tvEntryExit OnTransition_BarcodeValid = null;
    public tvEntryExit OnTransition_OCR_Validation_OK = null;
    public tvEntryExit OnTransition_LD_RisingEdge = null;
    public tvEntryExit OnTransition_BarcodeError = null;
    public tvEntryExit OnTransition_BarcodeInvalid = null;
    public tvEntryExit OnTransition_OCR_ValidationNot_OK = null;        
    #endregion
    public tvOnTransition_Barcode OnTransition_DO_CSCBarcodeValidation = null;
    
    public enum State
    {
        //Super states
        Input,                       
        //sub states
        CSC_Barcode_Validation, OCR_BarcodeValidation, PaymentSatisfied, Transaction
    }

    public enum Trigger
    {
        OpenLane,
        Trg_CloseLane,
        Trg_BC,            
        Trg_BarCodeRead,
        Trg_BarcodeError,
        Trg_BarcodeInvalid,
        Trg_BarcodeValid,
        Trg_OCR_ValidationNot_OK,
        Trg_OCR_Validation_OK,
        Trg_LDRisingEdge,
        Trg_LDFallingEdge            
    }

    State _state = State.Input;

    StateMachine<State, Trigger> _sMachine;
    object oLock;

    public MainStateMachine()
    {
        this.oLock = new object();
        _sMachine = new StateMachine<State, Trigger>(() => _state, s => _state = s);
        this._sMachine.OnTransitioned((otransition) => { if (this.OnTransitioned != null) this.OnTransitioned(otransition); });
        this._sMachine.OnUnhandledTrigger((estate, etrigger) => { if (this.OnUnhandledTrigger != null) this.OnUnhandledTrigger(estate, etrigger); });

        this.oBarcode_Trigger_With_Parameters = this._sMachine.SetTriggerParameters<string>(Trigger.Trg_BC);

        //Tag/Barcode Input state
        _sMachine.Configure(State.Input)
            .Permit(Trigger.Trg_BC, State.CSC_Barcode_Validation)
            .OnEntry(() => { if (this.OnEntry_Input != null) this.OnEntry_Input(); })
            .OnExit(() => { if (this.OnExit_Input != null) this.OnExit_Input(); });

        _sMachine.Configure(State.CSC_Barcode_Validation)
            .SubstateOf(State.Input)
            .OnEntryFrom(this.oBarcode_Trigger_With_Parameters, (sbarcodeserial) => { if (this.OnTransition_DO_CSCBarcodeValidation != null) this.OnTransition_DO_CSCBarcodeValidation( sbarcodeserial); })
            .Permit(Trigger.Trg_BarcodeError, State.Transaction)
            .Permit(Trigger.Trg_BarcodeValid, State.OCR_BarcodeValidation)
            .OnEntry(() => { if (OnEntry_CSC_BarcodeValidation != null) OnEntry_CSC_BarcodeValidation(); }); 

        _sMachine.Configure(State.OCR_BarcodeValidation)
            .SubstateOf(State.Input)
            .OnEntryFrom(Trigger.Trg_BarcodeValid, () =>
            {
                if(this.OnTransition_BarcodeValid != null) this.OnTransition_BarcodeValid();
            })
            .Permit(Trigger.Trg_OCR_ValidationNot_OK, State.Transaction)
            .Permit(Trigger.Trg_OCR_Validation_OK, State.PaymentSatisfied);

        _sMachine.Configure(State.PaymentSatisfied)
            .Permit(Trigger.Trg_LDRisingEdge, State.Transaction)
            .OnEntryFrom(Trigger.Trg_OCR_Validation_OK, () =>
            {
                if (this.OnTransition_OCR_Validation_OK != null) this.OnTransition_OCR_Validation_OK();
            })                
            .OnEntry(() => { if (this.OnEntry_PaymentSatisfied != null) OnEntry_PaymentSatisfied(); });                                                                                                             //.OnExit(() => { if (this.OnExit_PaymentSatisfied != null) OnExit_PaymentSatisfied(); });

        _sMachine.Configure(State.Transaction)
            .OnEntryFrom(Trigger.Trg_LDRisingEdge, () =>
            {
                if (this.OnTransition_LD_RisingEdge != null) this.OnTransition_LD_RisingEdge();
            })
            .OnEntryFrom(Trigger.Trg_BarcodeError, () => { if (this.OnTransition_BarcodeError != null) this.OnTransition_BarcodeError(); })
            .OnEntryFrom(Trigger.Trg_BarcodeInvalid, () => { if (this.OnTransition_BarcodeInvalid != null) this.OnTransition_BarcodeInvalid(); })
            .OnEntryFrom(Trigger.Trg_OCR_ValidationNot_OK, () => { if (this.OnTransition_OCR_ValidationNot_OK != null) this.OnTransition_OCR_ValidationNot_OK(); })                
            .OnEntry(() => { if (this.OnEntry_FrameTransaction != null) OnEntry_FrameTransaction(); }); // on entry into this State, I have to frame a Transaction and commit it
    }

    public bool TryFireTrigger(Trigger etrigger)
    {
        bool bReturn = false;

        lock (this.oLock)
        {
            if (this._sMachine.CanFire(etrigger))
            {
                try
                {
                    this._sMachine.Fire(etrigger);
                    bReturn = true;
                }
                catch (Exception oException)
                {
                    bReturn = false;
                    Console.WriteLine(oException.StackTrace);
                }
            }
        }

        return bReturn;
    }
}

This State machine is for a vehicle when it enters an unattended booth in a parking lot. I can't figure out as to how to create a transaction object, because it's properties change as and how it undergoes a state change. Do I pass the Transaction object to each state and get it's modified state back and pass it to next state? I'm not sure how to go about it. Any help is appreciated.

Edit: Another question. What is a substate?

Substates inherit the allowed transitions of their superstate. When entering directly into a substate from outside of the superstate, entry actions for the superstate are executed. Likewise when leaving from the substate to outside the superstate, exit actions for the superstate will execute.

0 Answers
Related