public ChoiceStateTest(String name) : base(name, new NSFEventThread(name)) { // Events evaluateEvent = new NSFEvent("EvaluateEvent", this); waitEvent = new NSFEvent("WaitEvent", this); // Regions and states, from outer to inner initialChoiceStateTestState = new NSFInitialState("InitialChoiceStateTest", this); waitToEvaluateState = new NSFCompositeState("WaitToEvaluate", this, null, null); evaluateValueState = new NSFChoiceState("EvaluateValue", this); evaluatedState = new NSFCompositeState("Evaluated", this, null, null); initialEvaluatedState = new NSFInitialState("InitialEvaluatedState", evaluatedState); valueLowState = new NSFCompositeState("ValueLow", evaluatedState, null, null); valueMiddleState = new NSFCompositeState("ValueMiddle", evaluatedState, null, null); valueHighState = new NSFCompositeState("ValueHigh", evaluatedState, null, null); // Transitions, ordered internal, local, external initialChoiceStateTestToWaitToEvaluateTransition = new NSFExternalTransition("InitialChoiceStateTestToWaitToEvaluate", initialChoiceStateTestState, waitToEvaluateState, null, null, null); waitToEvaluateToEvaluateValueTransition = new NSFExternalTransition("State1ToState2", waitToEvaluateState, evaluateValueState, evaluateEvent, null, null); //waitToEvaluateToEvaluateValueTransition = new NSFExternalTransition("State1ToState2", waitToEvaluateState, evaluatedState, evaluateEvent, null, null); initialEvaluatedToValueLowTransition = new NSFExternalTransition("InitialEvaluatedToValueLowTransition", initialEvaluatedState, valueLowState, null, null, null); evaluateValueToValueLowTransition = new NSFExternalTransition("EvaluateValueToValueLowTransition", evaluateValueState, valueLowState, null, isValueLow, null); evaluateValueToValueMiddleTransition = new NSFExternalTransition("EvaluateValueToValueMiddleTransition", evaluateValueState, valueMiddleState, null, Else, null); evaluateValueToValueHighTransition = new NSFExternalTransition("EvaluateValueToValueHighTransition", evaluateValueState, valueHighState, null, isValueHigh, null); evaluatedToWaitToEvaluateTransition = new NSFExternalTransition("EvaluatedToWaitToEvaluateTransition", evaluatedState, waitToEvaluateState, waitEvent, null, addValue); }
private void createStateMachine() { // State Machine Components // Define and initialize in the order: // 1) Events // 2) Regions and states, from outer to inner // 3) Transitions, ordered internal, local, external // 4) Group states and transitions within a region together. // Events commReadyEvent = new NSFEvent("CommReady", this); hardwareResetEvent = new NSFEvent("HardwareReset", this); // Regions and states, from outer to inner // Initial state construtors take the form (name, parent) initialResetStrategyState = new NSFInitialState("InitialResetStrategy", this); // Composite state construtors take the form (name, parent, entry action, exit action) resetHardwareState = new NSFCompositeState("ResetHardware", this, resetHardwareEntryActions, null); reestablishCommunicationsState = new NSFCompositeState("ReestablishCommunications", this, reestablishCommunicationsEntryActions, null); readyState = new NSFCompositeState("ThreadReady", this, null, null); // Transitions, ordered internal, local, external // External transition construtors take the form (name, source, target, trigger, guard, action) initialResetStrategyToResetHardwareTransition = new NSFExternalTransition("InitialToResetHardware", initialResetStrategyState, resetHardwareState, null, null, resetVariables); resetHardwareToReestablishCommunicationsTransition = new NSFExternalTransition("ResetHardwareToReestablishCommunications", resetHardwareState, reestablishCommunicationsState, null, isHardwareReset, null); reestablishCommunicationsStateToReadyTransition = new NSFExternalTransition("ReestablishCommunicationsStateToReady", reestablishCommunicationsState, readyState, null, isCommReady, null); // Actions resetHardwareAction = new NSFScheduledAction("ReadHardware", resetHardware, EventThread); readyCommAction = new NSFScheduledAction("ResetComm", resetComm, EventThread); }
protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent) { NSFTransition elseTransition = null; // Check transitions out of state foreach (NSFTransition transition in outgoingTransitions) { if (!transition.Guards.isEmpty()) { if (transition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled) { return(NSFEventStatus.NSFEventHandled); } } else { if (elseTransition != null) { // A choice is ill formed if it has more than one "else" transition throw new Exception(Name + " invalid choice state with multiple else transitions"); } elseTransition = transition; } } if ((elseTransition != null) && (elseTransition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled)) { return(NSFEventStatus.NSFEventHandled); } // If no transition is taken, then the model is ill formed and an exception is thrown. throw new Exception(Name + " invalid model with no transition taken from a choice state"); }
/// <summary> /// Creates a deep copy. /// </summary> /// <param name="name">The new name for the copy.</param> /// <returns>A copy of the event.</returns> /// <remarks> /// A common design pattern is to queue data event copies, each with its own unique data payload, to state machines for handling. /// </remarks> public NSFEvent copy(NSFString name) { NSFEvent eventCopy = copy(); eventCopy.Name = name; return(eventCopy); }
protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent) { // Check if all incoming transitions are satisfied bool incomingTransitionsSatisfied = true; foreach (NSFTransition incomingTransition in incomingTransitions) { if (!completedTransitions.Contains(incomingTransition)) { incomingTransitionsSatisfied = false; break; } } if (incomingTransitionsSatisfied) { // Take all outgoing transitions foreach (NSFTransition outgoingTransition in outgoingTransitions) { // All outgoing transitions must be null transitions by UML2.x standard outgoingTransition.processEvent(nsfEvent); } return(NSFEventStatus.NSFEventHandled); } return(NSFEventStatus.NSFEventUnhandled); }
/// <summary> /// Determines if the queuing the an event causes a state to enter before defaultWaitTime elapses. /// </summary> /// <param name="eventToInject">The event to queue.</param> /// <param name="stateToWaitFor">The state to wait for.</param> /// <param name="waitTime">The time in ms to wait for the stateToWaitFor to enter.</param> /// <returns> /// True if the stateToWaitFor is entered. /// False if the stateToWaitFor is not entered before time expires. /// </returns> /// <remarks> /// This is a blocking call, the caller may be blocked for as long as waitTime. /// </remarks> public bool doesEventResultInState(NSFEvent eventToInject, NSFState stateToWaitFor, int waitTime) { firstSignal.clear(); stateToWaitFor.EntryActions += firstSignal.send; if (eventToInject != null) { eventToInject.queueEvent(); } if (stateToWaitFor.isActive()) { stateToWaitFor.EntryActions -= firstSignal.send; return true; } if (!firstSignal.wait(waitTime)) { stateToWaitFor.EntryActions -= firstSignal.send; return false; } stateToWaitFor.EntryActions -= firstSignal.send; return true; }
/// <summary> /// Performs common construction behaviors. /// </summary> /// <param name="thread">The state machine's thread.</param> private void construct(NSFEventThread thread) { ConsecutiveLoopDetectionEnabled = true; ConsecutiveLoopLimit = 1000; EventLimitDetectionEnabled = true; EventLimit = 100; EventThread = thread; QueuedEvents = 0; LoggingEnabled = true; RunStatus = NSFEventHandlerRunStatus.EventHandlerStopped; TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerReady; resetEvent = new NSFEvent("Reset", this); runToCompletionEvent = new NSFEvent("RunToCompletion", this); startEvent = new NSFEvent("Start", this); stopEvent = new NSFEvent("Stop", this); terminateEvent = new NSFEvent("Terminate", this); StateChangeActions.setExceptionAction(handleStateChangeActionException); if (isTopStateMachine()) { EventThread.addEventHandler(this); } }
protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent) { // Additional behavior // Let regions process event first NSFEventStatus eventStatus = NSFEventStatus.NSFEventUnhandled; foreach (NSFRegion region in regions) { NSFEventStatus status = region.processEvent(nsfEvent); if (status == NSFEventStatus.NSFEventHandled) { eventStatus = NSFEventStatus.NSFEventHandled; } } if (eventStatus == NSFEventStatus.NSFEventHandled) { return(NSFEventStatus.NSFEventHandled); } // Base class behavior return(base.processEvent(nsfEvent)); }
protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent) { NSFTransition elseTransition = null; // Check transitions out of state foreach (NSFTransition transition in outgoingTransitions) { if (!transition.Guards.isEmpty()) { if (transition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled) { return NSFEventStatus.NSFEventHandled; } } else { if (elseTransition != null) { // A choice is ill formed if it has more than one "else" transition throw new Exception(Name + " invalid choice state with multiple else transitions"); } elseTransition = transition; } } if ((elseTransition != null) && (elseTransition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled)) { return NSFEventStatus.NSFEventHandled; } // If no transition is taken, then the model is ill formed and an exception is thrown. throw new Exception(Name + " invalid model with no transition taken from a choice state"); }
public TimerAccuracyTest(String name) { Name = name; eventHandler = new NSFEventHandler(name, new NSFEventThread(name)); testEvent = new NSFEvent(name, eventHandler); eventHandler.startEventHandler(); }
/// <summary> /// Creates a deep copy, replacing the specified parameters. /// </summary> /// <param name="source">The new source for the copy.</param> /// <param name="destination">The new destination for the copy.</param> /// <returns>A copy of the event.</returns> /// <remarks> /// A common design pattern is to queue data event copies, each with its own unique data payload, to state machines for handling. /// </remarks> public NSFEvent copy(INSFNamedObject source, INSFEventHandler destination) { NSFEvent eventCopy = copy(); eventCopy.Source = source; eventCopy.Destination = destination; return(eventCopy); }
/// <summary> /// Creates a state machine context. /// </summary> /// <param name="source">The state machine.</param> /// <param name="enteringState">The state being entered.</param> /// <param name="exitingState">The state being exited.</param> /// <param name="transition">The associated transition.</param> /// <param name="trigger">The triggering event.</param> public NSFStateMachineContext(NSFStateMachine source, NSFState enteringState, NSFState exitingState, NSFTransition transition, NSFEvent trigger) : base(source) { EnteringState = enteringState; ExitingState = exitingState; Transition = transition; Trigger = trigger; }
/// <summary> /// Adds a trigger to the list of trigger events. /// </summary> public void addTrigger(NSFEvent trigger) { if (trigger == null) { return; } triggers.Add(trigger); }
/// <summary> /// Removes a reaction to a specified event. /// </summary> /// <param name="nsfEvent">The event causing the action.</param> /// <param name="action">The action taken as a result of the event.</param> public void removeEventReaction(NSFEvent nsfEvent, NSFVoidAction <NSFEventContext> action) { lock (eventHandlerMutex) { if (eventReactions.ContainsKey(nsfEvent.Id)) { eventReactions[nsfEvent.Id].remove(action); } } }
/// <summary> /// Adds the specified event to the state machine's event queue. /// </summary> /// <param name="nsfEvent">The event to queue.</param> /// <param name="isPriorityEvent">Flag indicating if the event should be queued to the back of the queue (false) or the front of the queue (true).</param> /// <param name="logEventQueued">Flag indicating if an event queued trace should be added to the trace log.</param> private void queueEvent(NSFEvent nsfEvent, bool isPriorityEvent, bool logEventQueued) { if (!isTopStateMachine()) { TopStateMachine.queueEvent(nsfEvent, isPriorityEvent, logEventQueued); return; } lock (stateMachineMutex) { // Do not allow events to be queued if terminating or terminated, // except for run to completion event, which may be queued if terminating to allow proper semantics to continue until terminated. if ((TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerTerminated) || ((TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerTerminating) && (nsfEvent != runToCompletionEvent))) { return; } // Handle special case of terminate event by setting status and queuing a single terminate event. // Terminate event must be the last event queued to guarantee safe deletion when it is handled. if (nsfEvent == terminateEvent) { if (TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerReady) { TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminating; } } // Event limit detection looks for too many events queued for the state machine. // If more than the specified number of events are queued, the state machine will remove // its queued events, call the event limit actions, and stop after executing any events queued // by the limit actions. if ((EventLimitDetectionEnabled) && (QueuedEvents == EventLimit)) { EventThread.removeEventsFor(this); QueuedEvents = 0; EventLimitActions.execute(new NSFStateMachineContext(this, null, null, null, nsfEvent)); // Stop the state machine so that no more event processing occurs until started again stopStateMachine(); NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.ErrorTag, NSFTraceTags.SourceTag, Name, NSFTraceTags.MessageTag, "EventLimit"); return; } nsfEvent.Destination = this; EventThread.queueEvent(nsfEvent, isPriorityEvent, logEventQueued); ++QueuedEvents; } }
/// <summary> /// Processes an event. /// </summary> /// <param name="nsfEvent">The event to process.</param> /// <returns>NSFEventStatus.EventHandled if the event is handled, otherwise NSFEventStatus.EventUnhandled.</returns> /// <remarks> /// This method is for use only by the North State Framework's internal logic. /// </remarks> protected internal virtual NSFEventStatus processEvent(NSFEvent nsfEvent) { foreach (NSFTransition transition in outgoingTransitions) { if (transition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled) { return(NSFEventStatus.NSFEventHandled); } } return(NSFEventStatus.NSFEventUnhandled); }
public State2Strategy(String name, NSFCompositeState parentState) : base(name, parentState) { // Events event3 = new NSFEvent("Event3", this); // Regions and states, from outer to inner intialState2 = new NSFInitialState("IntialState2", this); state4 = new NSFCompositeState("state4", this, null, null); state5 = new NSFCompositeState("State5", this, null, null); // Transitions, ordered internal, local, external intialState2ToState4Transition = new NSFExternalTransition("InitialToState4", intialState2, state4, null, null, null); state4ToState5Transition = new NSFExternalTransition("State4ToState5", state4, state5, event3, null, null); }
/// <summary> /// Creates an event handler /// </summary> /// <param name="name">The user defined name for the state machine.</param> /// <param name="thread">The thread on which events for the state machine are queued.</param> public NSFEventHandler(NSFString name, NSFEventThread thread) : base(name) { EventThread = thread; LoggingEnabled = true; RunStatus = NSFEventHandlerRunStatus.EventHandlerStopped; TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerReady; startEvent = new NSFEvent("Start", this); stopEvent = new NSFEvent("Stop", this); terminateEvent = new NSFEvent("Terminate", this); EventThread.addEventHandler(this); }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFString name, NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : base(name, source, target, trigger, guard, action) { compositeSource = source; // Target must be substate of source or the source itself if ((!Source.isParent(Target)) && (Source != Target)) { throw new Exception(Name + " invalid local transition, source is neither parent of nor equal to target"); } Source.addOutgoingTransition(this); }
/// <summary> /// Adds a reaction to a specified event. /// </summary> /// <param name="nsfEvent">The event causing the action.</param> /// <param name="action">The action taken as a result of the event.</param> public void addEventReaction(NSFEvent nsfEvent, NSFVoidAction <NSFEventContext> action) { lock (eventHandlerMutex) { if (!eventReactions.ContainsKey(nsfEvent.Id)) { eventReactions.Add(nsfEvent.Id, new NSFVoidActions <NSFEventContext>()); eventReactions[nsfEvent.Id].setExceptionAction(handleEventReactionException); } eventReactions[nsfEvent.Id].add(action); } }
/// <summary> /// Indicates if the event queue contains an event that matches the specified event. /// </summary> /// <param name="nsfEvent">The event to match.</param> /// <returns>True if the event queue contains a matching event, false otherwise.</returns> /// <remarks> /// Two events match if they have the same id. Events may be copied to create new events with the same id. /// </remarks> public bool hasEvent(NSFEvent nsfEvent) { lock (threadMutex) { foreach (NSFEvent queuedEvent in nsfEvents) { if (queuedEvent.Id == nsfEvent.Id) { return(true); } } return(false); } }
/// <summary> /// Creates a scheduled action. /// </summary> /// <param name="name">The name of the scheduled action.</param> /// <param name="action">The action to execute.</param> /// <param name="eventThread">The thread on which the action will execute.</param> /// <remarks> /// Use null or String.Empty for the name if no name is desired. /// The action will be logged in the trace if the name is anything other than null or String.Empty. /// </remarks> public NSFScheduledAction(NSFString name, NSFVoidAction <NSFContext> action, NSFEventThread eventThread) : base(name) { Actions += action; Actions.setExceptionAction(handleActionException); eventHandler = new NSFEventHandler(Name, eventThread); executeActionsEvent = new NSFEvent(Name, this, eventHandler); eventHandler.LoggingEnabled = false; eventHandler.addEventReaction(executeActionsEvent, executeActions); eventHandler.startEventHandler(); }
/// <summary> /// Handles an event. /// </summary> /// <param name="nsfEvent">The event to handle.</param> /// <returns>Status indicating if the event was handled or not.</returns> /// <remarks> /// This method is for use only by the North State Framework's internal logic. /// It calls the actions associated with the event, if any. /// </remarks> public NSFEventStatus handleEvent(NSFEvent nsfEvent) { // Handle status changing events if ((nsfEvent == startEvent)) { RunStatus = NSFEventHandlerRunStatus.EventHandlerStarted; } else if (nsfEvent == stopEvent) { RunStatus = NSFEventHandlerRunStatus.EventHandlerStopped; } else if (nsfEvent == terminateEvent) { TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminated; EventThread.removeEventHandler(this); return(NSFEventStatus.NSFEventHandled); } // Don't process events if stopped if (RunStatus == NSFEventHandlerRunStatus.EventHandlerStopped) { return(NSFEventStatus.NSFEventUnhandled); } // Process the event bool actionsToExecute = false; lock (eventHandlerMutex) { if (eventReactions.ContainsKey(nsfEvent.Id)) { actionsToExecute = true; } } if (actionsToExecute) { eventReactions[nsfEvent.Id].execute(new NSFEventContext(this, nsfEvent)); return(NSFEventStatus.NSFEventHandled); } else { return(NSFEventStatus.NSFEventUnhandled); } }
public MultipleTriggersOnTransitionTest(String name) : base(name, new NSFEventThread(name)) { event1 = new NSFEvent("Event1", this); event2 = new NSFEvent("Event2", this); event3 = new NSFEvent("Evnet3", this); event4 = new NSFEvent("Event4", this); // Regions and states, from outer to inner initialState = new NSFInitialState("InitialTest2", this); state1 = new NSFCompositeState("State1", this, null, null); state2 = new NSFCompositeState("State2", this, null, null); // Transitions, ordered internal, local, external initialAToState1Transition = new NSFExternalTransition("InitialAToState1", initialState, state1, null, null, null); state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event1, null, null); state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event2, null, null); state1ToState2Transition.addTrigger(event3); state2ToState1Transition.addTrigger(event4); }
/// <summary> /// Implements the main event processing loop. /// </summary> protected override void threadLoop() { while (true) { // Wait for signal to indicate there's work to do signal.wait(); while (true) { NSFEvent nsfEvent = null; lock (threadMutex) { if (nsfEvents.Count != 0) { nsfEvent = nsfEvents.First.Value; nsfEvents.RemoveFirst(); } } if (nsfEvent == null) { break; } // Guard a bad event from taking down event thread try { nsfEvent.Destination.handleEvent(nsfEvent); } catch (Exception exception) { handleException(new Exception(Name + " event handling exception", exception)); } } // Thread loop will exit when terminating and all event handlers are terminated if ((TerminationStatus == NSFThreadTerminationStatus.ThreadTerminating) && allEventHandlersTerminated()) { nsfEvents.Clear(); return; } } }
public ExceptionHandlingTest(String name) : base(name, new NSFEventThread(name)) { event1 = new NSFEvent("Event1", this); event2 = new NSFEvent("Event2", this); // Regions and states, from outer to inner initialState = new NSFInitialState("InitialTest14", this); state1 = new NSFCompositeState("State1", this, null, null); state2 = new NSFCompositeState("State2", this, state2EntryActions, null); state3 = new NSFCompositeState("State3", this, null, null); // Transitions, ordered internal, local, external initialToState1Transition = new NSFExternalTransition("InitialToState1", initialState, state1, null, null, null); state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event1, null, null); state2ToState3Transition = new NSFExternalTransition("State2ToState3", state2, state3, event2, null, null); state3ToState2Transition = new NSFExternalTransition("State3ToState2", state3, state2, event1, null, null); state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event1, null, null); ExceptionActions += localHandleException; }
public ExtendedRunTest(String name) : base(name, new NSFEventThread(name)) { event1 = new NSFEvent("Event1", this); event2 = new NSFEvent("Event2", this); // Regions and states, from outer to inner initialState = new NSFInitialState("InitialTest1", this); state1 = new NSFCompositeState("State1", this, null, null); state2 = new NSFCompositeState("State2", this, null, null); state3 = new NSFCompositeState("State3", this, null, null); // Transitions, ordered internal, local, external state2ReactionToEvent1 = new NSFInternalTransition("State2ReactionToEvent1", state2, event1, null, state2ReactionToEvent1Actions); test1ReactionToEvent2 = new NSFInternalTransition("Test1ReactionToEvent2", this, event2, null, test13ReactionToEvent2Actions); initialToState1Transition = new NSFExternalTransition("InitialToState1", initialState, state1, null, null, null); state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event1, null, null); state2ToState3Transition = new NSFExternalTransition("State2ToState3", state2, state3, event2, null, null); state3ToState2Transition = new NSFExternalTransition("State3ToState2", state3, state2, event1, null, null); state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event1, null, null); }
/// <summary> /// Queues the specified event. /// </summary> /// <param name="nsfEvent">The event to queue.</param> /// <param name="isPriorityEvent">Flag indicating if the event should be queued to the back of the queue (false) or the front of the queue (true).</param> /// <param name="logEventQueued">Flag indicating if an event queued trace should be added to the trace log.</param> public void queueEvent(NSFEvent nsfEvent, bool isPriorityEvent, bool logEventQueued) { // Do not allow events to be queued if terminated if (TerminationStatus == NSFThreadTerminationStatus.ThreadTerminated) { return; } lock (threadMutex) { if (logEventQueued) { if (nsfEvent.Source != null) { NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.EventQueuedTag, NSFTraceTags.NameTag, nsfEvent.Name, NSFTraceTags.SourceTag, nsfEvent.Source.Name, NSFTraceTags.DestinationTag, nsfEvent.Destination.Name); } else { NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.EventQueuedTag, NSFTraceTags.NameTag, nsfEvent.Name, NSFTraceTags.SourceTag, NSFTraceTags.UnknownTag, NSFTraceTags.DestinationTag, nsfEvent.Destination.Name); } } if (isPriorityEvent) { nsfEvents.AddFirst(nsfEvent); } else { nsfEvents.AddLast(nsfEvent); } } signal.send(); }
/// <summary> /// Creates a transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> /// <remarks>Deprecated - Use NSFExternalTransition or NSFLocalTransition</remarks> protected NSFTransition(NSFString name, NSFState source, NSFState target, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : base(name) { this.source = source; this.target = target; Guards += guard; Actions += action; addTrigger(trigger); // Validity check if ((source == target) && (triggers.Count == 0) && Guards.isEmpty()) { throw new Exception(Name + " invalid self-transition with no trigger or guard"); } target.addIncomingTransition(this); // Outgoing transitions must be added by concrete classes Guards.setExceptionAction(handleGuardException); Actions.setExceptionAction(handleActionException); }
/// <summary> /// Creates a transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> /// <remarks>Deprecated - Use NSFExternalTransition or NSFLocalTransition</remarks> protected NSFTransition(NSFString name, NSFState source, NSFState target, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : base(name) { this.source = source; this.target = target; Guards += guard; Actions += action; addTrigger(trigger); // Validity check if ((source == target) && (triggers.Count == 0) && Guards.isEmpty()) { throw new Exception(Name + " invalid self-transition with no trigger or guard"); } target.addIncomingTransition(this); // Outgoing transitions must be added by concrete classes Guards.setExceptionAction(handleGuardException); Actions.setExceptionAction(handleActionException); }
public DeepHistoryTest(String name) : base(name, new NSFEventThread(name)) { // Events event1 = new NSFEvent("Event1", this); event2 = new NSFEvent("Event2", this); event3 = new NSFEvent("Event3", this); event4 = new NSFEvent("Event4", this); event5 = new NSFEvent("Event5", this); event6 = new NSFEvent("Event6", this); //States test2InitialState = new NSFInitialState("InitialTest3", this); state1 = new NSFCompositeState("State1", this, null, null); state2 = new NSFCompositeState("State2", this, null, null); //State 1 Region state1InitialState = new NSFInitialState("State1Initial", state1); state1History = new NSFDeepHistory("State1History", state1); state1_1 = new NSFCompositeState("State1_1", state1, null, null); state1_2 = new NSFCompositeState("State1_2", state1, null, null); // State1_2 Region state1_2InitialState = new NSFInitialState("State1_2Initial", state1_2); state1_2_1 = new NSFCompositeState("State1_2_1", state1_2, null, null); state1_2_2 = new NSFCompositeState("State1_2_2", state1_2, null, null); //Transitions // Test1 Region test1InitialToState1Transition = new NSFExternalTransition("Test1InitialToState1", test2InitialState, state1, null, null, null); state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event5, null, null); state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event6, null, null); // State1 Region state1InitialToState1HistoryTransition = new NSFExternalTransition("State1InitialToState1History", state1InitialState, state1History, null, null, null); state1HistoryToState1_1Transition = new NSFExternalTransition("State1HistoryToState1_1", state1History, state1_1, null, null, null); state1_1ToState1_2Transition = new NSFExternalTransition("State1_1ToState1_2", state1_1, state1_2, event1, null, null); state1_2ToState1_1Transition = new NSFExternalTransition("State1_2ToState1_1", state1_2, state1_1, event2, null, null); // State1_2 Region state1_2InitialStateToState1_2_1Transition = new NSFExternalTransition("State1_2InitialStateToState1_2_1", state1_2InitialState, state1_2_1, null, null, null); state1_2_1ToState1_2_2Transition = new NSFExternalTransition("State1_2_1ToState1_2_2", state1_2_1, state1_2_2, event3, null, null); state1_2_2ToState1_2_1Transition = new NSFExternalTransition("State1_2_2ToState1_2_1", state1_2_2, state1_2_1, event4, null, null); }
public TransitionOrderTest(String name) : base(name, new NSFEventThread(name)) { // Events event1 = new NSFEvent("Event1", this); event2 = new NSFEvent("Event2", this); event3 = new NSFEvent("Event3", this); // Regions and states, from outer to inner initialTest15 = new NSFInitialState("InitialTest16", this); state1 = new NSFCompositeState("State1", this, null, null); state2 = new NSFCompositeState("State2", this, null, null); intialState2 = new NSFInitialState("IntialState2", state2); state2_1 = new NSFCompositeState("State2_1", state2, null, state2_1ExitActions); state3 = new NSFCompositeState("State3", this, null, null); initialState3 = new NSFInitialState("InitialState3", state3); state3_1 = new NSFCompositeState("State3_1", state3, null, state3_1ExitActions); state4 = new NSFCompositeState("State4", this, null, null); errorState = new NSFCompositeState("Error", this, null, null); // Transitions, ordered internal, local, external initialTest15ToState1Transition = new NSFExternalTransition("InitialTest15ToState1", initialTest15, state1, null, null, null); state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event2, null, null); state1ReactionToEvent1 = new NSFInternalTransition("State1ReactionToEvent1", state1, event1, null, state1ReactionToEvent1Actions); state1ToErrorTransition = new NSFExternalTransition("State1ToError", state1, errorState, event1, null, null); state2ToState3Transition = new NSFExternalTransition("State2ToState3Transition", state2, state3, event2, null, null); state2ToErrorTransition = new NSFExternalTransition("State2ToErrorTransition", state2, errorState, event1, null, null); state2ToState2Transition = new NSFLocalTransition("State2ToState2Transition", state2, state2, event1, null, null); intialState2ToState2_1Transition = new NSFExternalTransition("intialState2ToState2_1Transition", intialState2, state2_1, null, null, null); state3ToState4Transition = new NSFExternalTransition("State3ToState4Transition", state3, state4, event2, null, null); state3ToState3Transition = new NSFLocalTransition("State3ToState3Transition", state3, state3, event1, null, null); state3ReactionToEvent1 = new NSFInternalTransition("state3ReactionToEvent1", state3, event1, null, state3ReactionToEvent1Actions); initialState3ToState3_1Transition = new NSFExternalTransition("InitialState3ToState3_1Transition", initialState3, state3_1, null, null, null); state3ToErrorTransition = new NSFExternalTransition("State3ToErrorTransition", state3, errorState, event3, null, null); }
/// <summary> /// Processes an event, evaluating if the event results in the transition firing. /// </summary> /// <remarks> /// This method is for use only by the North State Framework's internal logic. /// </remarks> protected internal NSFEventStatus processEvent(NSFEvent nsfEvent) { bool transitionTriggered = false; if (triggers.Count == 0) { transitionTriggered = true; } else { foreach (NSFEvent trigger in Triggers) { if (trigger.Id == nsfEvent.Id) { transitionTriggered = true; break; } } } if (!transitionTriggered) { return(NSFEventStatus.NSFEventUnhandled); } NSFStateMachineContext newContext = new NSFStateMachineContext(Source.TopStateMachine, null, null, this, nsfEvent); if (!Guards.execute(newContext)) { return(NSFEventStatus.NSFEventUnhandled); } fireTransition(newContext); return(NSFEventStatus.NSFEventHandled); }
public void queueEvent(NSFEvent nsfEvent) { lock (eventHandlerMutex) { // Do not allow events to be queued if terminating or terminated (i.e. not ready) if (TerminationStatus != NSFEventHandlerTerminationStatus.EventHandlerReady) { return; } // Handle special case of terminate event by setting status and queuing a single terminate event. // Terminate event must be the last event queued to guarantee safe deletion when it is handled. if (nsfEvent == terminateEvent) { if (TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerReady) { TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminating; } } nsfEvent.Destination = this; EventThread.queueEvent(nsfEvent, false, LoggingEnabled); } }
/// <summary> /// Handles an event. /// </summary> /// <param name="nsfEvent">The event to handle.</param> /// <returns>Status indicating if the event was handled or not.</returns> /// <remarks> /// This method is for use only by the North State Framework's internal logic. /// It processes the event using UML defined behavior, including run to completion. /// </remarks> public NSFEventStatus handleEvent(NSFEvent nsfEvent) { lock (stateMachineMutex) { --QueuedEvents; // This should only happen if events are queued without using the queueEvent method if (QueuedEvents < 0) { QueuedEvents = 0; } } // Handle status changing events if ((nsfEvent == startEvent)) { RunStatus = NSFEventHandlerRunStatus.EventHandlerStarted; } else if (nsfEvent == stopEvent) { RunStatus = NSFEventHandlerRunStatus.EventHandlerStopped; } else if (nsfEvent == terminateEvent) { TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminated; EventThread.removeEventHandler(this); return NSFEventStatus.NSFEventHandled; } else if (nsfEvent == resetEvent) { reset(); } // Don't process events if stopped if (RunStatus == NSFEventHandlerRunStatus.EventHandlerStopped) { return NSFEventStatus.NSFEventUnhandled; } // If not already active, enter state machine at the root if (!active) { enter(new NSFStateMachineContext(this, this, null, null, startEvent), false); } // Process the event NSFEventStatus eventStatus = NSFEventStatus.NSFEventUnhandled; try { eventStatus = processEvent(nsfEvent); if (eventStatus == NSFEventStatus.NSFEventHandled) { runToCompletion(); } // Consecutive loop detection looks for too many events without the state machine pausing. // If more than the specified number of transitions occur without a pause, the state machine will remove // its queued events, call the consecutive loop limit actions, and stop after executing any events queued // by the actions. if (ConsecutiveLoopDetectionEnabled) { ++consecutiveLoopCount; if (consecutiveLoopCount == ConsecutiveLoopLimit) { lock (stateMachineMutex) { EventThread.removeEventsFor(this); QueuedEvents = 0; } ConsecutiveLoopLimitActions.execute(new NSFStateMachineContext(this, null, null, null, nsfEvent)); // Stop the state machine so that no more event processing occurs until started again stopStateMachine(); // Reset consecutive loop count in case state machine is started again consecutiveLoopCount = 0; NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.ErrorTag, NSFTraceTags.SourceTag, Name, NSFTraceTags.MessageTag, "ConsecutiveLoopLimit"); } else if (QueuedEvents == 0) { // If no events are queued for this state machine, then it has paused, indicating it's not in an infinite loop. consecutiveLoopCount = 0; } } } catch (Exception exception) { handleException(new Exception(nsfEvent.Name + " event handling exception", exception)); } return eventStatus; }
/// <summary> /// Creates an internal transition. /// </summary> /// <param name="state">Transition state.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> /// <remarks>The default name for the transition is [state.Name]ReactionsTo[trigger.Name]</remarks> public NSFInternalTransition(NSFState state, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : this(state.Name + "ReactionsTo" + trigger.Name, state, trigger, guard, action) { }
/// <summary> /// Determines if the queuing the an event causes two states to enter before waitTime elapses. /// </summary> /// <param name="eventToInject">The event to queue.</param> /// <param name="stateToWaitFor">The first of two states to wait for.</param> /// <param name="secondStateToWaitFor">The second of two states to wait for.</param> /// <param name="waitTime">The time in ms to wait for the each state to enter.</param> /// <returns> /// True if both states are entered. /// False if either of the states fails to enter before time expires. /// </returns> /// <remarks> /// This is a blocking call, the caller may be blocked for as long as twice waitTime. /// The states may be congruently entered. /// </remarks> public bool doesEventResultInState(NSFEvent eventToInject, NSFState stateToWaitFor, NSFState secondStateToWaitFor, int waitTime) { secondSignal.clear(); stateToWaitFor.EntryActions += secondSignal.send; secondStateToWaitFor.EntryActions += secondSignal.send; if (!doesEventResultInState(eventToInject, stateToWaitFor, waitTime)) { secondStateToWaitFor.EntryActions -= secondSignal.send; return false; } if (secondStateToWaitFor.isActive()) { secondStateToWaitFor.EntryActions -= secondSignal.send; return true; } if (!secondSignal.wait(waitTime)) { secondStateToWaitFor.EntryActions -= secondSignal.send; return false; } secondStateToWaitFor.EntryActions -= secondSignal.send; return true; }
/// <summary> /// Processes an event. /// </summary> /// <param name="nsfEvent">The event to process</param> /// <returns>NSFEventHandled if the event is acted upon, otherwise NSFEventUnhandled.</returns> internal NSFEventStatus processEvent(NSFEvent nsfEvent) { return activeSubstate.processEvent(nsfEvent); }
/// <summary> /// Checks if an event is queued for processing. /// </summary> /// <param name="nsfEvent">The event in queustion.</param> /// <returns>True if the event is the in queue, otherwise false.</returns> protected bool hasEvent(NSFEvent nsfEvent) { return EventThread.hasEvent(nsfEvent); }
/// <summary> /// Indicates if the event queue contains an event that matches the specified event. /// </summary> /// <param name="nsfEvent">The event to match.</param> /// <returns>True if the event queue contains a matching event, false otherwise.</returns> /// <remarks> /// Two events match if they have the same id. Events may be copied to create new events with the same id. /// </remarks> public bool hasEvent(NSFEvent nsfEvent) { lock (threadMutex) { foreach (NSFEvent queuedEvent in nsfEvents) { if (queuedEvent.Id == nsfEvent.Id) { return true; } } return false; } }
public ForkJoinToForkJoinTransitionTest(String name) : base(name, new NSFEventThread(name)) { // Fork Joins bSynch = new NSFForkJoin("BSynch", this); abForkJoin = new NSFForkJoin("ABForkJoin", this); bcForkJoin = new NSFForkJoin("BCForkJoin", this); // ARegion // Events evA1 = new NSFEvent("EvA1", this); // States aRegion = new NSFRegion("ARegion", this); initialAState = new NSFInitialState("InitialA", aRegion); stateA1 = new NSFCompositeState("StateA1", aRegion, null, null); stateA2 = new NSFCompositeState("StateA2", aRegion, null, null); // Transitions, ordered internal, local, external initialAToStateA1Transition = new NSFExternalTransition("InitialAToStateA1", initialAState, stateA1, null, null, null); stateA1ToABForkJoinTransition = new NSFExternalTransition("StateA1ToABForkJoin", stateA1, abForkJoin, evA1, null, null); abForkJoinToA2Transition = new NSFExternalTransition("ABForkJoinToA2", abForkJoin, stateA2, null, null, null); // B Region // Events evB1 = new NSFEvent("EvB1", this); // States bRegion = new NSFRegion("BRegion", this); initialBState = new NSFInitialState("InitialB", bRegion); stateB1 = new NSFCompositeState("StateB1", bRegion, null, null); stateB2 = new NSFCompositeState("StateB2", bRegion, null, null); // Transitions, ordered internal, local, external initialBToStateB1Transition = new NSFExternalTransition("InitialBToStateB1", initialBState, stateB1, null, null, null); stateB1ToBSynchTransition = new NSFExternalTransition("StateB1ToBSynch", stateB1, bSynch, evB1, null, null); bSynchToStateB2Transition = new NSFExternalTransition("BSynchToStateB2", bSynch, stateB2, null, null, null); // C Region // Events evC1 = new NSFEvent("EvC1", this); // States cRegion = new NSFRegion("CRegion", this); initialCState = new NSFInitialState("InitialC", cRegion); stateC1 = new NSFCompositeState("StateC1", cRegion, null, null); stateC2 = new NSFCompositeState("StateC2", cRegion, null, null); // Transitions, ordered internal, local, external initialCToStateC1Transition = new NSFExternalTransition("InitialCToStateC1", initialCState, stateC1, null, null, null); stateC1ToBCForkJoinTransition = new NSFExternalTransition("StateC1ToBCForkJoin", stateC1, bcForkJoin, evC1, null, null); bcForkJoinToC2Transition = new NSFExternalTransition("BCForkJoinToC2", bcForkJoin, stateC2, null, null, null); // Extra Regional Transitions bSynchToABForkJoinTransition = new NSFExternalTransition("BSynchToABForkJoin", bSynch, abForkJoin, null, null, null); bSynchToBCForkJoinTransition = new NSFExternalTransition("BSynchToBCForkJoin", bSynch, bcForkJoin, null, null, null); }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : this(source.Name + "To" + target.Name, source, target, trigger, guard, action) { }
/// <summary> /// Creates an NSF event context. /// </summary> /// <param name="source">The source of invocation.</param> /// <param name="nsfEvent">The event.</param> public NSFEventContext(object source, NSFEvent nsfEvent) : base(source) { Event = nsfEvent; }
/// <summary> /// Processes an event. /// </summary> /// <param name="nsfEvent">The event to process</param> /// <returns>NSFEventHandled if the event is acted upon, otherwise NSFEventUnhandled.</returns> internal NSFEventStatus processEvent(NSFEvent nsfEvent) { return(activeSubstate.processEvent(nsfEvent)); }
public void queueEvent(NSFEvent nsfEvent) { queueEvent(nsfEvent, false, LoggingEnabled); }
public void queueEvent(NSFEvent nsfEvent, INSFNamedObject source) { nsfEvent.Source = source; queueEvent(nsfEvent); }
/// <summary> /// Creates an event. /// </summary> /// <param name="nsfEvent">The event to copy.</param> public NSFEvent(NSFEvent nsfEvent) : base(nsfEvent.Name) { construct(nsfEvent.Id, nsfEvent.Source, nsfEvent.Destination); }
/// <summary> /// Determines if the queuing the an event causes a state to enter before defaultWaitTime elapses. /// </summary> /// <param name="eventToInject">The event to queue.</param> /// <param name="stateToWaitFor">The state to wait for.</param> /// <returns> /// True if the stateToWaitFor is entered. /// False if the stateToWaitFor is not entered before time expires. /// </returns> /// <remarks> /// This is a blocking call, the caller may be blocked for as long as <see cref="defaultWaitTime"/>. /// </remarks> public bool doesEventResultInState(NSFEvent eventToInject, NSFState stateToWaitFor) { return doesEventResultInState(eventToInject, stateToWaitFor, defaultWaitTime); }
/// <summary> /// Checks if an event is queued for handling. /// </summary> /// <param name="nsfEvent">The event in queustion.</param> /// <returns>True if the event is the in queue, otherwise false.</returns> public bool hasEvent(NSFEvent nsfEvent) { return(EventThread.hasEvent(nsfEvent)); }
private void createStateMachine() { // State Machine Components // Define and initialize in the order: // 1) Events // 2) Regions and states, from outer to inner // 3) Transitions, ordered internal, local, external // 4) Group states and transitions within a region together. // Events // Event constructors take the form (name, parent) // Data event constructors take the form (name, parent, data payload) newCommandEvent = new NSFDataEvent<String>("NewCommand", this, "CommandPayload"); newResponseEvent = new NSFDataEvent<String>("NewResponse", this, "ResponsePayload"); responseTimeoutEvent = new NSFEvent("ResponseTimeout", this); resetEvent = new NSFEvent("Reset", this); // Regions and states, from outer to inner // Initial state construtors take the form (name, parent) initialCommandProcessorState = new NSFInitialState("InitialCommandProcessor", this); // Composite state construtors take the form (name, parent, entry action, exit action) waitForCommandState = new NSFCompositeState("WaitForCommand", this, null, null); waitForResponseState = new NSFCompositeState("WaitForResponse", this, waitForResponseEntryActions, waitForResponseExitActions); errorState = new NSFCompositeState("Error", this, errorEntryActions, null); resetState = new NSFCompositeState("Reset", this, resetEntryActions, null); // Transitions, ordered internal, local, external // Internal transition construtors take the form (name, state, trigger, guard, action) reactionToNewCommand = new NSFInternalTransition("ReactionToNewCommand", this, newCommandEvent, null, queueCommand); // External transition construtors take the form (name, source, target, trigger, guard, action) initialCommandProcessorToWaitForCommandTransition = new NSFExternalTransition("InitialToWaitForCommand", initialCommandProcessorState, waitForCommandState, null, null, null); waitForCommandToWaitForResponseTransition = new NSFExternalTransition("WaitForCommandToWaitForResponse", waitForCommandState, waitForResponseState, null, hasCommand, sendCommand); waitForResponseToWaitForCommandTransition = new NSFExternalTransition("WaitForResponseToWaitForCommand", waitForResponseState, waitForCommandState, newResponseEvent, isResponse, handleResponse); waitForResponseToErrorTransition = new NSFExternalTransition("WaitForResponseToError", waitForResponseState, errorState, responseTimeoutEvent, null, null); errorToResetTransition = new NSFExternalTransition("ErrorToReset", errorState, resetState, resetEvent, null, null); resetToWaitForCommandTransition = new NSFExternalTransition("ResetToWaitForCommand", resetState, waitForCommandState, null, isReady, null); }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : this(source.Name + "To" + target.Name, source, target, trigger, guard, action) { }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFString name, NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : base(name, source, target, trigger, guard, action) { compositeSource = source; // Target must be substate of source or the source itself if ((!Source.isParent(Target)) && (Source != Target)) { throw new Exception(Name + " invalid local transition, source is neither parent of nor equal to target"); } Source.addOutgoingTransition(this); }
/// <summary> /// Creates an internal transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="state">Transition state.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFInternalTransition(NSFString name, NSFState state, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : base(name, state, state, trigger, guard, action) { Source.addOutgoingTransition(this); }
/// <summary> /// Processes an event, evaluating if the event results in the transition firing. /// </summary> /// <remarks> /// This method is for use only by the North State Framework's internal logic. /// </remarks> protected internal NSFEventStatus processEvent(NSFEvent nsfEvent) { bool transitionTriggered = false; if (triggers.Count == 0) { transitionTriggered = true; } else { foreach (NSFEvent trigger in Triggers) { if (trigger.Id == nsfEvent.Id) { transitionTriggered = true; break; } } } if (!transitionTriggered) { return NSFEventStatus.NSFEventUnhandled; } NSFStateMachineContext newContext = new NSFStateMachineContext(Source.TopStateMachine, null, null, this, nsfEvent); if (!Guards.execute(newContext)) { return NSFEventStatus.NSFEventUnhandled; } fireTransition(newContext); return NSFEventStatus.NSFEventHandled; }