/// <summary> /// Traverse the specified connector, if possible. /// This is NOT thread-safe, you must call it in a critical section. /// </summary> /// <param name="connector"></param> /// <param name="args">Optional event args related to the connector traversal</param> /// <returns>true if the connector was traversed.</returns> protected bool TraverseConnector(IUmlConnector connector, TransitionEventArgs args = null) { bool traversed = false; if (CurrentNode == connector.Supplier && connector.CanTraverse && (connector.Consumer.CanEnter || connector.Consumer == connector.Supplier)) { // Broke this condition out separately because the order of TryExit is important. if (connector.Supplier.TryExit() // If Consumer is Supplier, just make sure again that Consumer can enter now that it has been exited. && (connector.Consumer != connector.Supplier || connector.Consumer.CanEnter)) { // Hook up to the connector's traversed event so that the CurrentNode value will be set before the node is entered. // This allows a node's ENTER and DO behaviors to rely on the new current state. connector.Traversed += HandleConnectorTraversed; // Successful traversal will first set the current state in this machine, // then set the new state on this machine's IStatefulModel. This order is important. traversed = connector.Traverse(args); // Traversal attempt is finished. Whether it succeeded or failed, the event handling is no longer needed. connector.Traversed -= HandleConnectorTraversed; } } return(traversed); }
public void AddConnector(IUmlConnector connector) { if (connector == null) { return; } _connectors.Add(connector); connector.Traversed += HandleOutboundConnectorTraversed; }
protected bool TraverseConnector(IUmlConnector connector, TransitionEventArgs args = null) { // If this machine is paused, don't allow transitions. lock (_executionLock) { if (ExecutableState == ExecutableState.Paused && CompletionCause == CompletionCause.Pending) { return(false); } } bool transitioned = false; lock (_connectorTraversalLock) { if (CurrentNode == connector.Supplier && connector.CanTraverse && connector.Consumer != null && connector.Consumer.CanEnter && connector.Supplier != null && connector.Supplier.TryExit()) { // Hook up to the connector's traversed event so that the CurrentNode value will be set before the node is entered. // This allows a node's ENTER and DO behaviors to rely on the new current state. connector.Traversed += HandleConnectorTraversed; transitioned = connector.Traverse(args); if (!transitioned) { LogService.Log(LogType, LogMessageType.Error, Name, string.Format(CultureInfo.InvariantCulture, "Exited '{0}' but failed to transition into '{1}' node. Machine is in a limbo state.", connector.Supplier.Name, connector.Consumer.Name)); } // Traversal attempt is finished. Whether it succeeded or failed, the event handling is no longer needed. connector.Traversed -= HandleConnectorTraversed; } } if (transitioned) { // Try to keep this activation running. RunToCompletion(); } return(transitioned); }