/// <summary>
        /// Constructor
        /// </summary>
        /// <param name="msgListner">The event listner object that receives events</param>
        /// <param name="msgStore">The object that stores the messages</param>
        /// <param name="eventBehavior">The behavior object that interacts with incoming events</param>
        /// <param name="stateMachine">The state machine that interprets the events</param>
        /// <param name="timer">The periodic timer</param>
        public SpStateMachineEngine(ISpEventListner msgListner, ISpEventStore msgStore, ISpBehaviorOnEvent eventBehavior, ISpStateMachine stateMachine, ISpPeriodicTimer timer)
        {
            WrapErr.ChkParam(msgListner, "msgListner", 50050);
            WrapErr.ChkParam(msgStore, "msgStore", 50051);
            WrapErr.ChkParam(eventBehavior, "eventBehavior", 50052);
            WrapErr.ChkParam(stateMachine, "stateMachine", 50053);
            WrapErr.ChkParam(timer, "timer", 50054);

            WrapErr.ToErrorReportException(50055, () => {
                this.wakeUpAction      = new Action(timer_OnWakeup);
                this.msgReceivedAction = new Action <ISpEventMessage>(this.eventListner_MsgReceived);

                this.msgListner    = msgListner;
                this.msgStore      = msgStore;
                this.eventBehavior = eventBehavior;
                this.stateMachine  = stateMachine;
                this.timer         = timer;

                this.driverThread = new Thread(new ThreadStart(this.DriverThread));
                this.driverThread.Start();

                this.msgListner.MsgReceived += this.msgReceivedAction;
                this.timer.OnWakeup         += this.wakeUpAction;
            });
        }
Beispiel #2
0
        /// <summary>Tick current state to execute the action based on the inputed message</summary>
        /// <param name="msg">The inputed message</param>
        /// <returns>The return message from the action</returns>
        public ISpEventMessage Tick([NotNull] ISpEventMessage?msg)
        {
            WrapErr.ChkDisposed(this.disposed, 50176);
            WrapErr.ChkParam(msg, "msg", 50172);

            // First tick to drive it from entry to regular
            ISpStateTransition <TMsgId>?tr = null;
            bool tmpIsStarted = this.isStarted;

            //Log.Debug("SpMachine", "Tick", String.Format("isStarted:{0}", this.isStarted));

            if (!this.isStarted)
            {
                // The OnEntry must be called directly from the state machine for the first state. Subsequent
                // state transitions will insure that the OnEntry for the new state is called
                this.isStarted = true;
                tr             = this.state.OnEntry(msg);
            }
            else
            {
                tr = this.state.OnTick(msg);
            }
            WrapErr.ChkVar(tr, 50177, () => String.Format(
                               "The State '{0}' {1} Returned a Null Transition", this.state.FullName, tmpIsStarted ? "OnTick" : "OnEntry"));
            WrapErr.ChkVar(tr.ReturnMessage, 9999, "Null ReturnMessage");
            return(tr.ReturnMessage);
        }
Beispiel #3
0
        /// <summary>
        /// Get a clone of the transition object from the store or null if not found
        /// </summary>
        /// <param name="store">The store to search</param>
        /// <param name="eventMsg">The message to insert in the transition object</param>
        /// <returns>The transition object from the store or null if not found</returns>
        public static ISpStateTransition GetTransitionCloneFromStore(Dictionary <int, ISpStateTransition> store, ISpEventMessage eventMsg)
        {
            WrapErr.ChkParam(store, "store", 51009);
            WrapErr.ChkParam(eventMsg, "eventMsg", 51010);

            return(WrapErr.ToErrorReportException(51011, () => {
                if (store.Keys.Contains(eventMsg.EventId))
                {
                    // Clone Transition object from store since its pointers get reset later
                    ISpStateTransition tr = (ISpStateTransition)store[eventMsg.EventId].Clone();

                    if (tr.ReturnMessage == null)
                    {
                        tr.ReturnMessage = eventMsg;
                    }
                    else
                    {
                        //Log.Info("SpTools", "GetTransitionCloneFromStore", "Found a transition AND - Held msg - transfering GUID");
                    }

                    // TODO - Look at transfering the GUID here
                    tr.ReturnMessage.Uid = eventMsg.Uid;


                    //tr.ReturnMessage = eventMsg;
                    return tr;
                }
                return null;
            }));
        }
Beispiel #4
0
 /// <summary>Constructor</summary>
 /// <param name="wrappedObject">Has common data and functions for all states</param>
 /// <param name="state">The state machine's main state</param>
 /// <remarks>
 /// The main state will be a super state or parallel super state implementation. You
 /// can use a single state implementation if you only want the wrapped object to be
 /// driven by periodic timer and have access to the messaging architecture
 /// </remarks>
 public SpMachine([NotNull] TMachine?wrappedObject, [NotNull] ISpState <TMsgId>?state)
 {
     WrapErr.ChkParam(wrappedObject, "wrappedObject", 50170);
     WrapErr.ChkParam(state, "state", 50171);
     this.wrappedObject = wrappedObject;
     this.state         = state;
 }
Beispiel #5
0
 /// <summary>
 /// Constructor with DI injectable main state
 /// </summary>
 /// <param name="wrappedObject"></param>
 /// <param name="state">The state machine's main state</param>
 /// <remarks>
 /// The main state will be a super state or parallel super state implementation. You
 /// can use a single state implementation if you only want the wrapped object to be
 /// driven by periodic timer and have access to the messaging architecture
 /// </remarks>
 public SpMachine(T wrappedObject, ISpState state)
 {
     WrapErr.ChkParam(wrappedObject, "wrappedObject", 50170);
     WrapErr.ChkParam(state, "state", 50171);
     this.wrappedObject = wrappedObject;
     this.state         = state;
 }
 public void Param_NullArg_FaultException()
 {
     WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
         WrapErr.ChkParam(null, "zork", 8888);
     });
     this.Validate(err, 8888, "Param_NullArg_FaultException", "Null zork Argument");
 }
 /// <summary>
 /// Add and event object to the store
 /// </summary>
 /// <param name="msg">The message event</param>
 public void Add(ISpEventMessage msg)
 {
     WrapErr.ChkDisposed(this.disposed, 50111);
     WrapErr.ChkParam(msg, "msg", 50112);
     lock (this.queueLock) {
         this.AddEvent(msg);
     }
 }
Beispiel #8
0
 /// <summary>Constructor</summary>
 /// <param name="parent">The parent state</param>
 /// <param name="msgFactory">Message Factory</param>
 /// <param name="idConverter">The integer id to string converter</param>
 /// <param name="id">Unique state id converter</param>
 /// <param name="wrappedObject">The generic object that the states represent</param>
 public SpStateBase(ISpState parent, ISpMsgFactory msgFactory, ISpIdConverter idConverter, ISpToInt id, T wrappedObject)
 {
     WrapErr.ChkParam(msgFactory, "msgFactory", 9999);
     WrapErr.ChkParam(wrappedObject, "wrappedObject", 50200);
     this.msgFactory  = msgFactory;
     this.idConverter = idConverter;
     this.InitStateIds(parent, id.ToInt());
     this.wrappedObject = wrappedObject;
 }
        public void Param_ValidArg_FaultException()
        {
            string zork = "Zorker";

            WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
                WrapErr.ChkParam(zork, "zork", 8888);
            });
            Assert.AreEqual(0, err.Code, "Should not have been an error");
        }
        /// <summary>Safely execute function and transfer the GUID to the response</summary>
        /// <param name="msg">The incoming message</param>
        /// <param name="func">The function to invoke to generate the response message</param>
        /// <returns>A correlated response message</returns>
        private ISpEventMessage GetMsg(ISpEventMessage msg, Func <ISpEventMessage> func)
        {
            WrapErr.ChkParam(msg, "msg", 9999);

            return(WrapErr.ToErrorReportException(9999, () => {
                ISpEventMessage ret = func.Invoke();
                WrapErr.ChkVar(ret, 9999, "The Provider Returned a Null Message");

                // Transfer the GUID for correlation
                ret.Uid = msg.Uid;
                return ret;
            }));
        }
Beispiel #11
0
        /// <summary>
        /// Register a state transition for an event
        /// </summary>
        /// <param name="eventId">The id converter of the event type</param>
        /// <param name="transition">The transition object</param>
        public static void RegisterTransition(string type, ISpToInt eventId, ISpStateTransition transition, Dictionary <int, ISpStateTransition> store)
        {
            WrapErr.ChkParam(eventId, "eventId", 51004);
            WrapErr.ChkParam(transition, "transition", 51005);
            WrapErr.ChkParam(store, "store", 51006);

            // Wrap the id converter separately
            int tmp = WrapErr.ToErrorReportException(51007,
                                                     () => { return(String.Format("Error on Event Id Converter for '{0}' Event Type", type)); },
                                                     () => { return(eventId.ToInt()); });

            // Duplicate transitions on same Event is a no no.
            WrapErr.ChkFalse(store.Keys.Contains(tmp), 51008,
                             () => { return(String.Format("Already Contain a '{0}' Transition for Id:{1}", type, tmp)); });
            store.Add(tmp, transition);
        }
Beispiel #12
0
        /// <summary>
        /// Search through a dictionary for a string equivalent and add if not found
        /// </summary>
        /// <param name="key">The key for the string requested</param>
        /// <param name="currentStrings">The dictionary of strings to query and add to</param>
        /// <param name="converterFunc">The converted to convert the key to a string value if not in the Dictionary</param>
        /// <returns></returns>
        public static string GetIdString(int key, Dictionary <int, string> currentStrings, Func <int, string> converterFunc)
        {
            WrapErr.ChkParam(currentStrings, "currentStrings", 51000);
            WrapErr.ChkParam(converterFunc, "converterFunc", 51001);
            return(WrapErr.ToErrorReportException(51002, () => {
                if (currentStrings.Keys.Contains(key))
                {
                    return currentStrings[key];
                }

                // Do another wrap level to isolate the user defined conversion failure
                string ret = WrapErr.ToErrorReportException(51003, "Error in Calling Id to String Converter Method", () => {
                    return converterFunc.Invoke(key);
                });
                currentStrings.Add(key, ret);
                return ret;
            }));
        }
Beispiel #13
0
        /// <summary>Register a transition for a state</summary>
        /// <param name="type">string of transition type</param>
        /// <typeparam name="TMsgId">Event id</typeparam>
        /// <param name="msgId">The event message id</param>
        /// <param name="transition">Transition object</param>
        /// <param name="store">Transition store</param>
        public static void RegisterTransition <TMsgId>(string type, TMsgId msgId, ISpStateTransition <TMsgId>?transition, Dictionary <int, ISpStateTransition <TMsgId> >?store) where TMsgId : struct
        {
            //WrapErr.ChkParam(eventId, "msgId", 51004);
            WrapErr.ChkParam(transition, "transition", 51005);
            WrapErr.ChkParam(store, "store", 51006);

            WrapErr.ChkTrue(typeof(TMsgId).IsEnum, 9999, () => string.Format("Transition type {0} must be Enum", msgId.GetType().Name));
            WrapErr.ChkTrue(typeof(TMsgId).GetEnumUnderlyingType() == typeof(Int32), 9999,
                            () => string.Format("Transition type enum {0} must be derived from int", msgId.GetType().Name));

            int tmp = Convert.ToInt32(msgId);

            // 51007 - failure of conversion number

            // Duplicate transitions on same Event is a no no.
            WrapErr.ChkFalse(store.Keys.Contains(tmp), 51008,
                             () => { return(String.Format("Already Contain a '{0}' Transition for Id:{1}", type, tmp)); });
            store.Add(tmp, transition);
        }
 public void ExceptionType_Regular_Param()
 {
     CheckExceptionType(() => { WrapErr.ChkParam(null, "zork", 8888); });
 }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="defaultTick">
 /// The default tick event if to provide if there are no queued event objects
 /// </param>
 public BaseEventStore(ISpEventMessage defaultTick)
 {
     WrapErr.ChkParam(defaultTick, "defaultTick", 50110);
     this.defaultTick = defaultTick;
 }
 /// <summary>Constructor</summary>
 /// <param name="provider">The message provider</param>
 public SpMsgFactory(ISpMsgProvider provider)
 {
     WrapErr.ChkParam(provider, "provider", 9999);
     this.provider = provider;
 }