PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/objectflow.core/Framework/Workflow.cs

http://objectflow.codeplex.com
C# | 303 lines | 169 code | 43 blank | 91 comment | 7 complexity | 228511745c8fc6c00602cd84e076bd4d MD5 | raw file
  1. using System;
  2. using Rainbow.Exceptions;
  3. using Rainbow.ObjectFlow.Engine;
  4. using Rainbow.ObjectFlow.Interfaces;
  5. using Rainbow.ObjectFlow.Language;
  6. using Rainbow.ObjectFlow.Policies;
  7. using System.Linq;
  8. namespace Rainbow.ObjectFlow.Framework
  9. {
  10. /// <summary>
  11. /// Pipelines are composed of generic IOperations. A pipeline
  12. /// controls the workflow whereas the IOperation encapsalates logic.
  13. /// </summary>
  14. public class Workflow<T> : IWorkflow<T>, IDefine<T>, ICompose<T>, IMerge<T>, IExecuteWorkflow<T> where T : class
  15. {
  16. private WorkflowBuilder<T> _workflowBuilder;
  17. private readonly Dispatcher<T> _workflowEngine;
  18. private TaskList<T> _tasklist;
  19. private AndOperand<T> _andOperand;
  20. /// <summary>
  21. /// default constructor
  22. /// </summary>
  23. public Workflow()
  24. {
  25. _workflowEngine = new Dispatcher<T>();
  26. _workflowBuilder = new SequentialBuilder<T>();
  27. _tasklist = new TaskList<T>();
  28. _workflowBuilder.OperationAdded += _tasklist.OperationAdded;
  29. ExceptionHandler = new ExceptionHandler();
  30. }
  31. internal Workflow(WorkflowBuilder<T> builder)
  32. {
  33. _workflowBuilder = builder;
  34. }
  35. internal Workflow(Dispatcher<T> workflowEngine, TaskList<T> tasklist)
  36. : this()
  37. {
  38. _workflowEngine = workflowEngine;
  39. _tasklist = tasklist;
  40. _workflowBuilder.OperationAdded += _tasklist.OperationAdded;
  41. }
  42. /// <summary>
  43. /// Joins one operation onto another to run in parallel
  44. /// <remarks>
  45. /// Although data will be passed to operations or functions running in parallel
  46. /// these operations will not affect the data passed to subsequent operations. This was to reduce the
  47. /// complexity of parallel operations in Version 1.x and this behaviour may be extended to
  48. /// pass state in the future.
  49. /// </remarks>
  50. /// </summary>
  51. public IAnd<T> And
  52. {
  53. get
  54. {
  55. if (IsSequentialBuilder(_workflowBuilder))
  56. {
  57. var operation = RemoveLastOperation();
  58. _andOperand = CreateAndInitialiseAndJoin(operation);
  59. }
  60. return _andOperand;
  61. }
  62. }
  63. private AndOperand<T> CreateAndInitialiseAndJoin(OperationDuplex<T> operation)
  64. {
  65. _workflowBuilder = new ParallelSplitBuilder<T>();
  66. _workflowBuilder.OperationAdded += _tasklist.OperationAdded;
  67. _andOperand = new AndOperand<T>(this, _workflowBuilder);
  68. _andOperand.Do(operation);
  69. return _andOperand;
  70. }
  71. private OperationDuplex<T> RemoveLastOperation()
  72. {
  73. // TODO: and should probably subscribe to events and raise it to workflow builder. this would decouple the builder from the and.
  74. var operation = _tasklist.Tasks[_tasklist.Tasks.Count - 1];
  75. _tasklist.Tasks.RemoveAt(_tasklist.Tasks.Count - 1);
  76. return operation;
  77. }
  78. /// <summary>
  79. /// Gets or sets the context of the workflow.
  80. /// </summary>
  81. /// <value>The context for the workflow operations.</value>
  82. public T Context
  83. {
  84. get { return _workflowEngine.Context; }
  85. set { _workflowEngine.Context = value; }
  86. }
  87. //TODO remove?
  88. internal TaskList<T> RegisteredOperations
  89. {
  90. get { return _tasklist; }
  91. }
  92. internal ExceptionHandler ExceptionHandler { get; set; }
  93. /// <summary>
  94. /// Adds an operation into the workflow definition
  95. /// </summary>
  96. /// <param name="operation">The operation to execute as a generic of IOperation</param>
  97. /// <remarks>Operations must inherit from the BasicOperation class</remarks>
  98. public virtual IWorkflow<T> Do(IOperation<T> operation)
  99. {
  100. Check.IsNotNull(operation, "operation");
  101. Check.IsInstanceOf<BasicOperation<T>>(operation, "operation");
  102. _workflowBuilder.AddOperation(operation);
  103. return this;
  104. }
  105. /// <summary>
  106. /// Adds an operation into the workflow definition given the constraint. The constraint runs if
  107. /// the constraint evaluates to true.
  108. /// </summary>
  109. /// <param name="operation">The operation to execute as a generic of IOperation</param>
  110. /// <param name="constraint">The constraint to evaluate</param>
  111. /// <remarks>Operations must inherit from the BasicOperation class</remarks>
  112. public virtual IWorkflow<T> Do(IOperation<T> operation, ICheckConstraint constraint)
  113. {
  114. Check.IsNotNull(operation, "operation");
  115. Check.IsNotNull(constraint, "constraint");
  116. Check.IsInstanceOf<BasicOperation<T>>(operation, "operation");
  117. _workflowBuilder.AddOperation(operation, constraint);
  118. return this;
  119. }
  120. /// <summary>
  121. /// Adds a function into the workflow definition
  122. /// </summary>
  123. /// <param name="function">Function to add</param>
  124. public IWorkflow<T> Do(Func<T, T> function)
  125. {
  126. Check.IsNotNull(function, "function");
  127. _workflowBuilder.AddOperation(function);
  128. return this;
  129. }
  130. /// <summary>
  131. /// Adds a function into the workflow definition
  132. /// </summary>
  133. /// <param name="function">Function to add</param>
  134. /// <param name="constraint">constraint defines if function will be executed</param>
  135. public IWorkflow<T> Do(Func<T, T> function, ICheckConstraint constraint)
  136. {
  137. Check.IsNotNull(function, "function");
  138. Check.IsNotNull(constraint, "constraint");
  139. _workflowBuilder.AddOperation(function, constraint);
  140. return this;
  141. }
  142. /// <summary>
  143. /// Begins the execution of a workflow
  144. /// </summary>
  145. /// <returns>The data after being transformed by the Operation objects</returns>
  146. /// <remarks>
  147. /// This is only valid for state objects where operations on null can be performed as this delegates to Start(T data) by passing it null.
  148. /// </remarks>
  149. public virtual T Start()
  150. {
  151. return Start(default(T));
  152. }
  153. /// <summary>
  154. /// Runs the workflow definition
  155. /// </summary>
  156. /// <param name="data">Data to transform</param>
  157. /// <returns>Result of the workflow</returns>
  158. public virtual T Start(T data)
  159. {
  160. Then();
  161. ExceptionHandler.When(() => _workflowEngine.Execute(_tasklist.Tasks, data));
  162. return Context;
  163. }
  164. /// <summary>
  165. /// Subsequent Operations and functions will execute after the previous one has completed.
  166. /// </summary>
  167. public virtual IMerge<T> Then()
  168. {
  169. if (!IsSequentialBuilder(_workflowBuilder))
  170. {
  171. _tasklist.Tasks.Add(new OperationDuplex<T>(_workflowBuilder.ParallelOperations));
  172. _workflowBuilder = new SequentialBuilder<T>();
  173. //SetCurrentTasksFromList(_tasklist.Tasks.ToArray());
  174. _workflowBuilder.OperationAdded += _tasklist.OperationAdded;
  175. }
  176. return this;
  177. }
  178. private static bool IsSequentialBuilder(WorkflowBuilder<T> builder)
  179. {
  180. return null == builder || (typeof(SequentialBuilder<T>) == builder.GetType());
  181. }
  182. /// <summary>
  183. /// Instantiates a workflow object
  184. /// </summary>
  185. public static IDefine<T> Definition()
  186. {
  187. return new Workflow<T>();
  188. }
  189. /// <summary>
  190. /// Adds a sub-workflow into the workflow definition
  191. /// </summary>
  192. /// <param name="workflow">Workflow to add</param>
  193. public IWorkflow<T> Do(IExecuteWorkflow<T> workflow)
  194. {
  195. Check.IsNotNull(workflow, "workflow");
  196. _workflowBuilder.AddOperation(workflow);
  197. return this;
  198. }
  199. /// <summary>
  200. /// Adds a sub-workflow into the workflow definition
  201. /// </summary>
  202. /// <param name="workflow">Workflow to add</param>
  203. /// <param name="constraint">pre-condition for execution</param>
  204. public IWorkflow<T> Do(IExecuteWorkflow<T> workflow, ICheckConstraint constraint)
  205. {
  206. Check.IsNotNull(workflow, "workflow");
  207. Check.IsNotNull(constraint, "constraint");
  208. _workflowBuilder.AddOperation(workflow, constraint);
  209. return this;
  210. }
  211. /// <summary>
  212. /// Allows an operation to be attempted again
  213. /// </summary>
  214. public IRetryPolicy Retry()
  215. {
  216. IRetryPolicy policy = new Retry(this);
  217. if (_tasklist.Tasks.Count > 0)
  218. {
  219. _tasklist.Tasks[_tasklist.Tasks.Count - 1].Command.Policies.Add(policy);
  220. }
  221. return policy;
  222. }
  223. /// <summary>
  224. /// Does the operation again. Unlike Retry, this does not check on success or failure
  225. /// </summary>
  226. /// <returns></returns>
  227. public IRepeat Repeat()
  228. {
  229. IRepeat policy = new Repeat(this);
  230. if (_tasklist.Tasks.Count > 0)
  231. {
  232. _tasklist.Tasks[_tasklist.Tasks.Count - 1].Command.Policies.Add(policy);
  233. }
  234. return policy;
  235. }
  236. /// <summary>
  237. /// Registers an instance of the type specified in the workflow
  238. /// </summary>
  239. /// <typeparam name="TOperation">Type that inherits from BasicOperation of T</typeparam>
  240. public IWorkflow<T> Do<TOperation>() where TOperation : BasicOperation<T>
  241. {
  242. _workflowBuilder.AddOperation<TOperation>();
  243. return this;
  244. }
  245. /// <summary>
  246. /// Registers an instance of the type specified in the workflow
  247. /// </summary>
  248. /// <typeparam name="TOperation">Type that inherits from BasicOperation of T</typeparam>
  249. /// <param name="constraint">The constraint to evaluate</param>
  250. public IWorkflow<T> Do<TOperation>(ICheckConstraint constraint) where TOperation : BasicOperation<T>
  251. {
  252. _workflowBuilder.AddOperation<TOperation>(constraint);
  253. return this;
  254. }
  255. // public static IHandle Configure()
  256. // {
  257. // return new ExceptionHandler();
  258. // }
  259. }
  260. }