示例#1
0
        /// <summary>
        /// Verifies transitions in order of onEvent, onResult and if not found will return the
        /// default transition
        /// </summary>
        /// <param name="stateFunc">
        /// The function that is invoked that will return return message from the state processing
        /// and use it to check against the onResult queue.
        /// </param>
        /// <param name="eventMsg">The incoming message to validate against the onEvent list</param>
        /// <returns>The OnEvent, OnResult or default transition</returns>
        private ISpStateTransition GetTransition(bool onEntry, Func <ISpEventMessage, ISpEventMessage> stateFunc, ISpEventMessage msg)
        {
            return(WrapErr.ToErrorReportException(9999, () => {
                // Query the OnEvent queue for a transition BEFORE calling state function (OnEntry, OnTick)
                ISpStateTransition tr = this.GetOnEventTransition(msg);
                if (tr != null)
                {
                    tr.ReturnMessage = (tr.ReturnMessage == null)
                        ? this.MsgFactory.GetResponse(msg)
                        : this.MsgFactory.GetResponse(tr.ReturnMessage);
                    return tr;
                }

                // Only considered entered if you do not encounter a preemptive OnEvent transition on entry. In this way
                // you could get a situation where you cascade down several state depths based on higher up events
                if (onEntry)
                {
                    this.isEntered = true;
                }

                // Get the transition object from the 'OnResult' queue
                if ((tr = this.GetOnResultTransition(stateFunc.Invoke(msg))) != null)
                {
                    tr.ReturnMessage = this.MsgFactory.GetResponse(msg, tr.ReturnMessage);
                    return tr;
                }

                // If no transitions registered return SameState with default success message
                return new SpStateTransition(SpStateTransitionType.SameState, null, this.MsgFactory.GetDefaultResponse(msg));
            }));
        }
示例#2
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;
            }));
        }
        /// <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;
            });
        }
示例#4
0
        public T GetObj <T>() where T : class
        {
            T?obj = WrapErr.ToErrorReportException(9999,
                                                   () => string.Format("Constructor for class {0} failed", typeof(T).Name),
                                                   () => { return(this.ReturnObj <T>()); });

            return(obj);
        }
示例#5
0
 /// <summary>
 /// Set the interval in  for wakeup for the next Start
 /// </summary>
 /// <param name="interval">The interval in </param>
 public void SetInterval(TimeSpan interval)
 {
     WrapErr.ChkDisposed(this.disposed, 50002);
     WrapErr.ChkTrue(interval.TotalMilliseconds > 0, 50000, "The interval cannot be 0 milliseconds total");
     WrapErr.ToErrorReportException(50001, () => {
         this.timespan = interval;
     });
 }
示例#6
0
 /// <summary>
 /// Excecuted once when the state becomes the current state
 /// </summary>
 /// <param name="msg">The incoming message</param>
 /// <returns>A state transition object</returns>
 public virtual ISpStateTransition OnEntry(ISpEventMessage msg)
 {
     Log.Info(this.className, "OnEntry", String.Format("'{0}' State {1} - Event", this.FullName, this.GetCachedEventId(msg.EventId)));
     WrapErr.ChkFalse(this.IsEntryExcecuted, 50201, "OnEntry Cannot be Executed More Than Once Until OnExit is Called");
     return(WrapErr.ToErrorReportException(9999, () => {
         return this.GetTransition(true, this.ExecOnEntry, msg);
     }));
 }
示例#7
0
        //private readonly static ClassLog log = new ("FileHelpers");

        #endregion


        /// <summary>Flip all slashes back or forth for cross-platform compatibility</summary>
        /// <param name="pathString">The path string to convert</param>
        /// <returns>The converted string</returns>
        public static string ConvertSlashes(string pathString)
        {
            WrapErr.ChkTrue(pathString.Length > 0, 9999, "Empty path string not allowed");
            return(WrapErr.ToErrorReportException(9999, "Failed to flip slashes", () => {
                // Cover all bases by converting forward or back slashes to OS specific
                string tmp = pathString.Replace('\\', Path.DirectorySeparatorChar);
                return tmp.Replace('/', Path.DirectorySeparatorChar);
            }));
        }
示例#8
0
 public void OnAction_NoException()
 {
     WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
         WrapErr.ToErrorReportException(12345, "Unexpected Error Processing Block", () => {
             Console.WriteLine("This is a non exception throwing block");
         });
     });
     Assert.AreEqual(0, err.Code);
     Assert.IsFalse(this.logged, "No exception - should not have been logged");
 }
示例#9
0
 public void OnAction_Exception()
 {
     WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
         WrapErr.ToErrorReportException(12345, "Unexpected Error Processing Block", () => {
             new ChkUtilsTestHelpers.OuterClass().DoNestedException();
         });
     });
     this.Validate(err, 12345, "OnAction_Exception", "Unexpected Error Processing Block");
     Assert.IsTrue(this.logged, "Exception - The log delegate should have fired");
 }
示例#10
0
 /// <summary>
 /// Called on every other period after the first
 /// </summary>
 /// <param name="msg">The incoming message</param>
 /// <returns>A state transition object</returns>
 public virtual ISpStateTransition OnTick(ISpEventMessage msg)
 {
     //Log.Info(this.className, "OnTick", String.Format("'{0}' State - {1}", this.FullName, this.ConvertEventIdToString(msg.EventId)));
     WrapErr.ChkTrue(this.IsEntryExcecuted, 50205, () => {
         return(String.Format("OnTick for '{0}' State Cannot be Executed Before OnEntry", this.FullName));
     });
     return(WrapErr.ToErrorReportException(9999, () => {
         return this.GetTransition(false, this.ExecOnTick, msg);
     }));
 }
示例#11
0
 public void OnAction_NoException_MsgFormatInvoked()
 {
     WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
         WrapErr.ToErrorReportException(12345, () => { this.msgFormated = true; return("blah"); }, () => {
             Console.WriteLine("This is a non exception throwing block");
         });
     });
     Assert.AreEqual(0, err.Code);
     Assert.IsFalse(this.msgFormated, "The message formatter should not have been invoked");
     Assert.IsFalse(this.logged, "No exception - should not have been logged");
 }
示例#12
0
 /// <summary>
 /// Get 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>
 private ISpStateTransition GetTransitionFromStore(Dictionary <int, ISpStateTransition> store, ISpEventMessage eventMsg)
 {
     return(WrapErr.ToErrorReportException(50204, () => {
         ISpStateTransition t = SpTools.GetTransitionCloneFromStore(store, eventMsg);
         if (t != null)
         {
             this.LogTransition(t, eventMsg);
         }
         return t;
     }));
 }
示例#13
0
 public void OnAction_Exception_MsgFormatInvoked()
 {
     WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
         WrapErr.ToErrorReportException(12345, () => { this.msgFormated = true; return("Unexpected Error Processing Block"); }, () => {
             new ChkUtilsTestHelpers.OuterClass().DoNestedException();
         });
     });
     this.Validate(err, 12345, "OnAction_Exception_MsgFormatInvoked", "Unexpected Error Processing Block");
     Assert.IsTrue(this.msgFormated, "The message formatter should have been invoked");
     Assert.IsTrue(this.logged, "Exception - The log delegate should have fired");
 }
示例#14
0
 /// <summary>
 /// Builds the fully resolved name by iterating through the  the name based on the
 /// </summary>
 private void BuildName()
 {
     WrapErr.ToErrorReportException(9999, () => {
         StringBuilder sb = new StringBuilder(75);
         this.IdChain.ForEach((item) => {
             sb.Append(String.Format(".{0}", this.GetCachedStateId(item)));
         });
         this.fullName = sb.Length > 0 ? sb.ToString(1, sb.Length - 1) : "FullNameSearchFailed";
         this.name     = this.idChain.Count > 0 ? this.GetCachedStateId(this.idChain[this.idChain.Count - 1]) : "NameSearchFailed";
     });
 }
示例#15
0
 /// <summary>Dispose resources</summary>
 /// <param name="disposeManagedResources">
 /// If true it was called by the Dispose method rather than finalizer
 /// </param>
 private void Dispose(bool disposeManagedResources)
 {
     if (!disposed)
     {
         if (disposeManagedResources)
         {
             WrapErr.ToErrorReportException(50173, () => this.DisposeManagedResources());
         }
         WrapErr.ToErrorReportException(50174, () => this.DisposeNativeResources());
     }
     this.disposed = true;
 }
示例#16
0
 /// <summary>
 /// Factor out the reporting of state transitions for clarity
 /// </summary>
 /// <param name="tr">The transition object</param>
 /// <param name="eventMsg">The event message which pushed this transition</param>
 private void LogTransition(ISpStateTransition tr, ISpEventMessage eventMsg)
 {
     WrapErr.ToErrorReportException(9999, () => {
         Log.Debug("SpState", "LogTransition",
                   String.Format(
                       "{0} OnMsg({1} - {2}) - From:{3} To:{4}",
                       tr.TransitionType,
                       this.GetCachedMsgTypeId(eventMsg.TypeId),
                       this.GetCachedEventId(eventMsg.EventId),
                       this.FullName,
                       tr.NextState == null ? "Unknown" : tr.NextState.FullName));
     });
 }
示例#17
0
 /// <summary>
 /// Start the periodic timer
 /// </summary>
 public void Start()
 {
     WrapErr.ChkDisposed(this.disposed, 50003);
     WrapErr.ToErrorReportException(50004, () => {
         lock (this.timerLock) {
             this.Stop();
             this.timer           = new Timer(this.timespan.TotalMilliseconds);
             this.timer.Elapsed  += this.onTimerWakeup;
             this.timer.AutoReset = true;
             this.timer.Start();
         }
     });
 }
示例#18
0
        /// <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;
            }));
        }
示例#19
0
        public void OnFunction_NoException()
        {
            string s = "";

            WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
                s = WrapErr.ToErrorReportException(12345, "Unexpected Error Processing Block", () => {
                    return("This is a non exception throwing block");
                });
            });
            Assert.AreEqual(0, err.Code);
            Assert.AreEqual("This is a non exception throwing block", s);
            Assert.IsFalse(this.logged, "No exception - should not have been logged");
        }
示例#20
0
        public void OnFunction_Exception()
        {
            string s = "lalala";

            WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
                s = WrapErr.ToErrorReportException(12345, "Unexpected Error Processing Block", () => {
                    new ChkUtilsTestHelpers.OuterClass().DoNestedException();
                    return("This should not be");
                });
            });
            this.Validate(err, 12345, "OnFunction_Exception", "Unexpected Error Processing Block");
            Assert.AreEqual("lalala", s);
            Assert.IsTrue(this.logged, "Exception - The log delegate should have fired");
        }
示例#21
0
        public void OnFunction_NoException_MsgFormatInvoked()
        {
            string s             = "";
            bool   formatInvoked = false;

            WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
                s = WrapErr.ToErrorReportException(12345, () => { formatInvoked = true; return("blah"); }, () => {
                    return("This is a non exception throwing block");
                });
            });
            Assert.AreEqual(0, err.Code);
            Assert.IsFalse(formatInvoked, "The message formatter should not have been invoked");
            Assert.AreEqual("This is a non exception throwing block", s);
            Assert.IsFalse(this.logged, "No exception - should not have been logged");
        }
示例#22
0
        public void OnFunction_Exception_NoLogging()
        {
            WrapErr.InitialiseOnExceptionLogDelegate(null);
            string s = "lalala";

            WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
                s = WrapErr.ToErrorReportException(12345, "Unexpected Error Processing Block", () => {
                    new ChkUtilsTestHelpers.OuterClass().DoNestedException();
                    return("This should not be");
                });
            });
            this.Validate(err, 12345, "OnFunction_Exception_NoLogging", "Unexpected Error Processing Block");
            Assert.AreEqual("lalala", s);
            Assert.IsFalse(this.logged, "Exception - But the logger should not have been fired");
        }
示例#23
0
 /// <summary>
 /// Initialise the state id chain from ancestors to this state
 /// </summary>
 /// <param name="parent"></param>
 /// <param name="id"></param>
 private void InitStateIds(ISpState parent, int id)
 {
     // Add any ancestor state ids to the chain
     WrapErr.ToErrorReportException(50207, () => {
         if (parent != null)
         {
             WrapErr.ChkVar(parent.IdChain, 50206, "The Parent has a Null Id Chain");
             this.idChain.Clear();
             parent.IdChain.ForEach((item) => this.idChain.Add(item));
         }
         // This state id is the leaf
         this.idChain.Add(id);
         this.BuildName();
     });
 }
示例#24
0
 public void OnAction_Exception_FinallyInvoked()
 {
     WrapErr.ToErrReport(out ErrReport err, 1111, "Validate arg", () => {
         WrapErr.ToErrorReportException(12345, "Unexpected Error Processing Block",
                                        delegate {
             new ChkUtilsTestHelpers.OuterClass().DoNestedException();
         },
                                        delegate {
             Console.WriteLine("Immediately before the finally var is set to true");
             this.finallyInvoked = true;
         });
     });
     this.Validate(err, 12345, "OnAction_Exception_FinallyInvoked", "Unexpected Error Processing Block");
     Assert.IsTrue(this.finallyInvoked, "Finally block was not executed on exception");
     Assert.IsTrue(this.logged, "Exception - The log delegate should have fired");
 }
示例#25
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);
        }
        public void OnAction_NoException_FinallyInvoked()
        {
            ErrReport err;

            WrapErr.ToErrReport(out err, 1111, "Validate arg", () => {
                WrapErr.ToErrorReportException(12345, "Unexpected Error Processing Block", () => {
                    Console.WriteLine("This is a non exception throwing block");
                },
                                               delegate {
                    this.finallyInvoked = true;
                });
            });
            Assert.AreEqual(0, err.Code);
            Assert.IsTrue(this.finallyInvoked, "Finally block was not executed");
            Assert.IsFalse(this.logged, "No exception - should not have been logged");
        }
示例#27
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;
            }));
        }
示例#28
0
 /// <summary>
 /// Always invoked on object exit
 /// </summary>
 public void OnExit()
 {
     Log.Info(this.className, "OnExit", String.Format("'{0}' State", this.FullName));
     // TODO - check that OnEntry has happened ??
     WrapErr.ToErrorReportException(9999, () => {
         // Only execute ExceOnExit code if the state had been entered
         if (this.IsEntryExcecuted)
         {
             this.ExecOnExit();
         }
         else
         {
             Log.Warning(9999, String.Format(
                             "ExecOnExit for State:{0} not called because OnEntry was preempted by an OnEvent Transition",
                             this.FullName));
         }
     },
                                    () => { this.isEntered = false; });
 }
示例#29
0
        /// <summary>
        /// Convert an integer to a generic enum
        /// </summary>
        /// <typeparam name="T">The enum type</typeparam>
        /// <param name="value">The integer value to convert from</param>
        /// <returns>The Enum or an exception on failure to convert</returns>
        public static T ToEnum <T>(this int value) where T : struct
        {
            T enumType = default(T);
            T ret      =
                WrapErr.ToErrorReportException(9999,
                                               () => { return(String.Format(
                                                                  "Enum Conversion Failed Attempting to Convert to Type '{0}' with Value '{1}'",
                                                                  enumType.GetType().Name, value)); },
                                               () => {
                // This will throw on non enum but not out of range
                return((T)Enum.Parse(typeof(T), value.ToString()));
            });

            // Do the enum range check
            WrapErr.ChkTrue(Enum.IsDefined(typeof(T), ret), 9999, () => {
                return(String.Format(
                           "Enum Conversion Out of Range Attempting to Convert to Type '{0}' with Value '{1}'",
                           enumType.GetType().Name, value));
            });
            return(ret);
        }
示例#30
0
 /// <summary>
 /// Dispose managed resources (those with Dispose methods)
 /// </summary>
 protected virtual void DisposeManagedResources()
 {
     WrapErr.ToErrorReportException(50175, () => this.wrappedObject.Dispose());
 }