/SimpleServiceBus/Bus/Pipeline/MessagePipeline.cs

# · C# · 229 lines · 175 code · 54 blank · 0 comment · 26 complexity · 9b1d966b9704b2b03bb4516f38af2618 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using SimpleServiceBus.Bus.MessageManagement;
  4. using SimpleServiceBus.Endpoint;
  5. namespace SimpleServiceBus.Bus.Pipeline
  6. {
  7. public enum PipelineStatus
  8. {
  9. Uninitialized = 0,
  10. Initializing,
  11. Initialized,
  12. Processing,
  13. Complete
  14. }
  15. public class MessagePipeline : IMessagePipeline
  16. {
  17. private PipelineStatus _status;
  18. protected PipelineEvents _events;
  19. protected MessagePipeline(PipelineEvents events):this()
  20. {
  21. if (events != null)
  22. _events = events;
  23. }
  24. public MessagePipeline()
  25. {
  26. _events = new PipelineEvents();
  27. PipelineComponents = new List<IMessagePipelineComponent>();
  28. }
  29. public IMessagingEndpoint Endpoint { get; private set; }
  30. public PipelineDirection PipelineDirection { get; private set; }
  31. public IPipelineEvents PipelineEvents
  32. {
  33. get { return _events; }
  34. }
  35. public IList<IMessagePipelineComponent> PipelineComponents { get; protected set; }
  36. public PipelineStatus Status
  37. {
  38. get { return _status; }
  39. private set
  40. {
  41. if (_status != value)
  42. {
  43. PipelineStatus prev = _status;
  44. _status = value;
  45. var message = CurrentContext == null ? null : CurrentContext.MessageEnvelope;
  46. _events.OnPipelineStatusChanged(new MessagePipelineStatusChangedEventArgs
  47. {Pipeline = this, PreviousStatus = prev, CurrentStatus = value,Message = message});
  48. }
  49. }
  50. }
  51. public int CurrentComponentIndex { get; private set; }
  52. #region IMessagePipeline Members
  53. public IMessageContext CurrentContext { get; private set; }
  54. public IMessagePipelineComponent CurrentComponent { get; private set; }
  55. public virtual void Initialize(MessageEnvelope messageEnvelope,IMessagingEndpoint endpoint,PipelineDirection direction,params IMessagePipelineComponent[] pipelineComponents)
  56. {
  57. SetCurrentPipeline(this, direction);
  58. PipelineDirection = direction;
  59. Endpoint = endpoint;
  60. if (pipelineComponents != null)
  61. ((List<IMessagePipelineComponent>)PipelineComponents).AddRange(pipelineComponents);
  62. if (Status > PipelineStatus.Uninitialized)
  63. throw new InvalidOperationException(
  64. "This MessageEnvelope Processing Pipeline has already been initialized. Initialized can only be called once.");
  65. Status = PipelineStatus.Initializing;
  66. CurrentContext = CreateMessageContext(messageEnvelope);
  67. InitializePipelineComponents();
  68. Status = PipelineStatus.Initialized;
  69. _events.OnPipelineInitialized(new MessagePipelineEventArgs{Pipeline = this,Message = CurrentContext.MessageEnvelope});
  70. }
  71. public void ProcessMessage()
  72. {
  73. try
  74. {
  75. if (Status != PipelineStatus.Initialized)
  76. throw new InvalidOperationException("The current status of this MessageEnvelope Pipeline is " + Status +
  77. ". Process() can only be called when the current status is Initialized.");
  78. Status = PipelineStatus.Processing;
  79. _events.OnPipelineStarted(new MessagePipelineEventArgs { Pipeline = this, Message = CurrentContext.MessageEnvelope});
  80. if (PipelineComponents != null)
  81. {
  82. for (CurrentComponentIndex = 0; CurrentComponentIndex < PipelineComponents.Count; CurrentComponentIndex++)
  83. {
  84. IMessagePipelineComponent component = PipelineComponents[CurrentComponentIndex];
  85. CurrentComponent = component;
  86. if (component.Enabled == false ||
  87. component.EnabledFor(CurrentContext.MessageEnvelope) == false)
  88. continue;
  89. _events.OnProcessingComponentStarted(new MessagePipelineEventArgs { Pipeline = this, Message = CurrentContext.MessageEnvelope });
  90. component.ProcessMessage(CurrentContext.MessageEnvelope);
  91. _events.OnProcessingComponentCompleted(new MessagePipelineEventArgs { Pipeline = this, Message = CurrentContext.MessageEnvelope });
  92. if (CurrentContext.AbortMessageProcessing)
  93. break;
  94. }
  95. }
  96. Status = PipelineStatus.Complete;
  97. CurrentComponent = null;
  98. _events.OnPipelineCompleted(new MessagePipelineEventArgs { Pipeline = this, Message = CurrentContext.MessageEnvelope });
  99. }
  100. catch (Exception ex)
  101. {
  102. ex =
  103. new MessageProcessingException(
  104. "An error occurred processing a message in pipeline component " + GetType().Name, ex,
  105. CurrentContext.MessageEnvelope);
  106. if (!_events.OnPipelineError(new MessagePipelineErrorEventArgs {Pipeline = this, Error = ex, Message = CurrentContext.MessageEnvelope}))
  107. throw;
  108. }
  109. finally
  110. {
  111. ClearCurrentPipeline(PipelineDirection);
  112. }
  113. }
  114. public virtual void Dispose()
  115. {
  116. CurrentReceivePipeline = null;
  117. CurrentContext = null;
  118. foreach (IMessagePipelineComponent component in PipelineComponents)
  119. {
  120. component.Dispose();
  121. }
  122. }
  123. #endregion
  124. protected virtual void InitializePipelineComponents()
  125. {
  126. foreach (IMessagePipelineComponent pipelineComponent in PipelineComponents)
  127. {
  128. pipelineComponent.Pipeline = this;
  129. }
  130. }
  131. protected virtual IMessageContext CreateMessageContext(MessageEnvelope messageEnvelope)
  132. {
  133. return new MessageContext(messageEnvelope, this);
  134. }
  135. #region Thead Status Singleton
  136. [ThreadStatic] private static IMessagePipeline _currentReceivePipeline;
  137. public static IMessagePipeline CurrentReceivePipeline
  138. {
  139. get { return _currentReceivePipeline; }
  140. protected set { _currentReceivePipeline = value; }
  141. }
  142. [ThreadStatic]
  143. private static IMessagePipeline _currentSendPipeline;
  144. public static IMessagePipeline CurrentSendPipeline
  145. {
  146. get { return _currentSendPipeline; }
  147. protected set { _currentSendPipeline = value; }
  148. }
  149. public static void SetCurrentPipeline(IMessagePipeline pipeline,PipelineDirection direction)
  150. {
  151. if (direction == PipelineDirection.Receive)
  152. {
  153. if (CurrentReceivePipeline != null)
  154. throw new InvalidOperationException(
  155. "Only oneReceivePipeline is allowed per thread. A MessagePipline has already been asigned to this thread.");
  156. CurrentReceivePipeline = pipeline;
  157. }
  158. else
  159. {
  160. if (CurrentSendPipeline != null)
  161. throw new InvalidOperationException(
  162. "Only one SendPipeline is allowed per thread. A MessagePipline has already been asigned to this thread.");
  163. CurrentSendPipeline = pipeline;
  164. }
  165. }
  166. public static void ClearCurrentPipeline(PipelineDirection direction)
  167. {
  168. if (direction == PipelineDirection.Receive)
  169. CurrentReceivePipeline = null;
  170. else
  171. CurrentSendPipeline = null;
  172. }
  173. #endregion
  174. }
  175. }