ruote-maestrodev 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. data/CHANGELOG.txt +290 -0
  2. data/CREDITS.txt +99 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.rdoc +88 -0
  5. data/Rakefile +108 -0
  6. data/TODO.txt +488 -0
  7. data/lib/ruote.rb +7 -0
  8. data/lib/ruote/context.rb +194 -0
  9. data/lib/ruote/engine.rb +1062 -0
  10. data/lib/ruote/engine/process_error.rb +122 -0
  11. data/lib/ruote/engine/process_status.rb +448 -0
  12. data/lib/ruote/exp/command.rb +87 -0
  13. data/lib/ruote/exp/commanded.rb +69 -0
  14. data/lib/ruote/exp/condition.rb +227 -0
  15. data/lib/ruote/exp/fe_add_branches.rb +138 -0
  16. data/lib/ruote/exp/fe_apply.rb +154 -0
  17. data/lib/ruote/exp/fe_cancel_process.rb +78 -0
  18. data/lib/ruote/exp/fe_command.rb +156 -0
  19. data/lib/ruote/exp/fe_concurrence.rb +321 -0
  20. data/lib/ruote/exp/fe_concurrent_iterator.rb +219 -0
  21. data/lib/ruote/exp/fe_cron.rb +141 -0
  22. data/lib/ruote/exp/fe_cursor.rb +324 -0
  23. data/lib/ruote/exp/fe_define.rb +112 -0
  24. data/lib/ruote/exp/fe_echo.rb +60 -0
  25. data/lib/ruote/exp/fe_equals.rb +115 -0
  26. data/lib/ruote/exp/fe_error.rb +82 -0
  27. data/lib/ruote/exp/fe_filter.rb +648 -0
  28. data/lib/ruote/exp/fe_forget.rb +88 -0
  29. data/lib/ruote/exp/fe_given.rb +154 -0
  30. data/lib/ruote/exp/fe_if.rb +127 -0
  31. data/lib/ruote/exp/fe_inc.rb +205 -0
  32. data/lib/ruote/exp/fe_iterator.rb +234 -0
  33. data/lib/ruote/exp/fe_let.rb +75 -0
  34. data/lib/ruote/exp/fe_listen.rb +304 -0
  35. data/lib/ruote/exp/fe_lose.rb +110 -0
  36. data/lib/ruote/exp/fe_noop.rb +45 -0
  37. data/lib/ruote/exp/fe_once.rb +215 -0
  38. data/lib/ruote/exp/fe_participant.rb +287 -0
  39. data/lib/ruote/exp/fe_read.rb +69 -0
  40. data/lib/ruote/exp/fe_redo.rb +82 -0
  41. data/lib/ruote/exp/fe_ref.rb +152 -0
  42. data/lib/ruote/exp/fe_registerp.rb +110 -0
  43. data/lib/ruote/exp/fe_reserve.rb +126 -0
  44. data/lib/ruote/exp/fe_restore.rb +102 -0
  45. data/lib/ruote/exp/fe_save.rb +72 -0
  46. data/lib/ruote/exp/fe_sequence.rb +59 -0
  47. data/lib/ruote/exp/fe_set.rb +154 -0
  48. data/lib/ruote/exp/fe_subprocess.rb +211 -0
  49. data/lib/ruote/exp/fe_that.rb +92 -0
  50. data/lib/ruote/exp/fe_undo.rb +67 -0
  51. data/lib/ruote/exp/fe_unregisterp.rb +69 -0
  52. data/lib/ruote/exp/fe_wait.rb +95 -0
  53. data/lib/ruote/exp/flowexpression.rb +886 -0
  54. data/lib/ruote/exp/iterator.rb +81 -0
  55. data/lib/ruote/exp/merge.rb +118 -0
  56. data/lib/ruote/exp/ro_attributes.rb +212 -0
  57. data/lib/ruote/exp/ro_filters.rb +136 -0
  58. data/lib/ruote/exp/ro_persist.rb +154 -0
  59. data/lib/ruote/exp/ro_variables.rb +189 -0
  60. data/lib/ruote/exp/ro_vf.rb +68 -0
  61. data/lib/ruote/fei.rb +260 -0
  62. data/lib/ruote/id/mnemo_wfid_generator.rb +43 -0
  63. data/lib/ruote/id/wfid_generator.rb +81 -0
  64. data/lib/ruote/log/default_history.rb +122 -0
  65. data/lib/ruote/log/pretty.rb +176 -0
  66. data/lib/ruote/log/storage_history.rb +159 -0
  67. data/lib/ruote/log/test_logger.rb +208 -0
  68. data/lib/ruote/log/wait_logger.rb +64 -0
  69. data/lib/ruote/part/block_participant.rb +137 -0
  70. data/lib/ruote/part/code_participant.rb +81 -0
  71. data/lib/ruote/part/engine_participant.rb +189 -0
  72. data/lib/ruote/part/local_participant.rb +138 -0
  73. data/lib/ruote/part/no_op_participant.rb +60 -0
  74. data/lib/ruote/part/null_participant.rb +54 -0
  75. data/lib/ruote/part/rev_participant.rb +169 -0
  76. data/lib/ruote/part/smtp_participant.rb +116 -0
  77. data/lib/ruote/part/storage_participant.rb +392 -0
  78. data/lib/ruote/part/template.rb +84 -0
  79. data/lib/ruote/participant.rb +7 -0
  80. data/lib/ruote/reader.rb +278 -0
  81. data/lib/ruote/reader/json.rb +49 -0
  82. data/lib/ruote/reader/radial.rb +290 -0
  83. data/lib/ruote/reader/ruby_dsl.rb +186 -0
  84. data/lib/ruote/reader/xml.rb +99 -0
  85. data/lib/ruote/receiver/base.rb +212 -0
  86. data/lib/ruote/storage/base.rb +364 -0
  87. data/lib/ruote/storage/composite_storage.rb +121 -0
  88. data/lib/ruote/storage/fs_storage.rb +139 -0
  89. data/lib/ruote/storage/hash_storage.rb +211 -0
  90. data/lib/ruote/svc/dispatch_pool.rb +158 -0
  91. data/lib/ruote/svc/dollar_sub.rb +298 -0
  92. data/lib/ruote/svc/error_handler.rb +138 -0
  93. data/lib/ruote/svc/expression_map.rb +97 -0
  94. data/lib/ruote/svc/participant_list.rb +397 -0
  95. data/lib/ruote/svc/tracker.rb +172 -0
  96. data/lib/ruote/svc/treechecker.rb +141 -0
  97. data/lib/ruote/tree_dot.rb +85 -0
  98. data/lib/ruote/util/filter.rb +525 -0
  99. data/lib/ruote/util/hashdot.rb +79 -0
  100. data/lib/ruote/util/look.rb +128 -0
  101. data/lib/ruote/util/lookup.rb +127 -0
  102. data/lib/ruote/util/misc.rb +167 -0
  103. data/lib/ruote/util/ometa.rb +71 -0
  104. data/lib/ruote/util/serializer.rb +103 -0
  105. data/lib/ruote/util/subprocess.rb +88 -0
  106. data/lib/ruote/util/time.rb +100 -0
  107. data/lib/ruote/util/tree.rb +58 -0
  108. data/lib/ruote/version.rb +29 -0
  109. data/lib/ruote/worker.rb +386 -0
  110. data/lib/ruote/workitem.rb +394 -0
  111. data/phil.txt +14 -0
  112. data/ruote.gemspec +44 -0
  113. data/test/bm/ci.rb +55 -0
  114. data/test/bm/ici.rb +71 -0
  115. data/test/bm/juuman.rb +54 -0
  116. data/test/bm/launch_bench.rb +37 -0
  117. data/test/bm/load_26c.rb +97 -0
  118. data/test/bm/mega.rb +64 -0
  119. data/test/bm/seq_thousand.rb +31 -0
  120. data/test/bm/t.rb +35 -0
  121. data/test/functional/base.rb +247 -0
  122. data/test/functional/concurrent_base.rb +98 -0
  123. data/test/functional/crunner.rb +31 -0
  124. data/test/functional/ct_0_concurrence.rb +65 -0
  125. data/test/functional/ct_1_iterator.rb +67 -0
  126. data/test/functional/ct_2_cancel.rb +81 -0
  127. data/test/functional/eft_0_process_definition.rb +65 -0
  128. data/test/functional/eft_10_cancel_process.rb +46 -0
  129. data/test/functional/eft_11_wait.rb +109 -0
  130. data/test/functional/eft_12_listen.rb +500 -0
  131. data/test/functional/eft_13_iterator.rb +342 -0
  132. data/test/functional/eft_14_cursor.rb +456 -0
  133. data/test/functional/eft_15_loop.rb +69 -0
  134. data/test/functional/eft_16_if.rb +183 -0
  135. data/test/functional/eft_17_equals.rb +55 -0
  136. data/test/functional/eft_18_concurrent_iterator.rb +410 -0
  137. data/test/functional/eft_19_reserve.rb +136 -0
  138. data/test/functional/eft_1_echo.rb +68 -0
  139. data/test/functional/eft_20_save.rb +116 -0
  140. data/test/functional/eft_21_restore.rb +61 -0
  141. data/test/functional/eft_22_noop.rb +28 -0
  142. data/test/functional/eft_23_apply.rb +168 -0
  143. data/test/functional/eft_24_add_branches.rb +98 -0
  144. data/test/functional/eft_25_command.rb +28 -0
  145. data/test/functional/eft_26_error.rb +77 -0
  146. data/test/functional/eft_27_inc.rb +280 -0
  147. data/test/functional/eft_28_once.rb +135 -0
  148. data/test/functional/eft_29_cron.rb +64 -0
  149. data/test/functional/eft_2_sequence.rb +58 -0
  150. data/test/functional/eft_30_ref.rb +155 -0
  151. data/test/functional/eft_31_registerp.rb +130 -0
  152. data/test/functional/eft_32_lose.rb +93 -0
  153. data/test/functional/eft_33_let.rb +31 -0
  154. data/test/functional/eft_34_given.rb +123 -0
  155. data/test/functional/eft_35_filter.rb +375 -0
  156. data/test/functional/eft_36_read.rb +95 -0
  157. data/test/functional/eft_3_participant.rb +149 -0
  158. data/test/functional/eft_4_set.rb +296 -0
  159. data/test/functional/eft_5_subprocess.rb +163 -0
  160. data/test/functional/eft_6_concurrence.rb +304 -0
  161. data/test/functional/eft_7_forget.rb +61 -0
  162. data/test/functional/eft_8_undo.rb +114 -0
  163. data/test/functional/eft_9_redo.rb +138 -0
  164. data/test/functional/ft_0_worker.rb +65 -0
  165. data/test/functional/ft_10_dollar.rb +304 -0
  166. data/test/functional/ft_11_recursion.rb +109 -0
  167. data/test/functional/ft_12_launchitem.rb +43 -0
  168. data/test/functional/ft_13_variables.rb +151 -0
  169. data/test/functional/ft_14_re_apply.rb +324 -0
  170. data/test/functional/ft_15_timeout.rb +226 -0
  171. data/test/functional/ft_16_participant_params.rb +98 -0
  172. data/test/functional/ft_17_conditional.rb +102 -0
  173. data/test/functional/ft_18_kill.rb +138 -0
  174. data/test/functional/ft_19_participant_code.rb +67 -0
  175. data/test/functional/ft_1_process_status.rb +796 -0
  176. data/test/functional/ft_20_storage_participant.rb +543 -0
  177. data/test/functional/ft_21_forget.rb +153 -0
  178. data/test/functional/ft_22_process_definitions.rb +90 -0
  179. data/test/functional/ft_23_load_defs.rb +79 -0
  180. data/test/functional/ft_24_block_participant.rb +235 -0
  181. data/test/functional/ft_25_receiver.rb +207 -0
  182. data/test/functional/ft_26_participant_rtimeout.rb +179 -0
  183. data/test/functional/ft_27_var_indirection.rb +128 -0
  184. data/test/functional/ft_28_null_noop_participants.rb +51 -0
  185. data/test/functional/ft_29_part_template.rb +60 -0
  186. data/test/functional/ft_2_errors.rb +380 -0
  187. data/test/functional/ft_30_smtp_participant.rb +122 -0
  188. data/test/functional/ft_31_part_blocking.rb +72 -0
  189. data/test/functional/ft_33_participant_subprocess_priority.rb +32 -0
  190. data/test/functional/ft_34_cursor_rewind.rb +101 -0
  191. data/test/functional/ft_35_add_service.rb +56 -0
  192. data/test/functional/ft_36_storage_history.rb +150 -0
  193. data/test/functional/ft_37_default_history.rb +109 -0
  194. data/test/functional/ft_38_participant_more.rb +193 -0
  195. data/test/functional/ft_39_wait_for.rb +136 -0
  196. data/test/functional/ft_3_participant_registration.rb +574 -0
  197. data/test/functional/ft_40_wait_logger.rb +62 -0
  198. data/test/functional/ft_41_participants.rb +91 -0
  199. data/test/functional/ft_42_storage_copy.rb +71 -0
  200. data/test/functional/ft_43_participant_on_reply.rb +87 -0
  201. data/test/functional/ft_44_var_participant.rb +35 -0
  202. data/test/functional/ft_45_participant_accept.rb +64 -0
  203. data/test/functional/ft_46_launch_single.rb +83 -0
  204. data/test/functional/ft_47_wfid_generator.rb +54 -0
  205. data/test/functional/ft_48_lose.rb +112 -0
  206. data/test/functional/ft_49_engine_on_error.rb +201 -0
  207. data/test/functional/ft_4_cancel.rb +132 -0
  208. data/test/functional/ft_50_engine_config.rb +22 -0
  209. data/test/functional/ft_51_misc.rb +67 -0
  210. data/test/functional/ft_52_case.rb +134 -0
  211. data/test/functional/ft_53_engine_on_terminate.rb +95 -0
  212. data/test/functional/ft_54_patterns.rb +104 -0
  213. data/test/functional/ft_55_engine_participant.rb +303 -0
  214. data/test/functional/ft_56_filter_attribute.rb +259 -0
  215. data/test/functional/ft_57_rev_participant.rb +252 -0
  216. data/test/functional/ft_58_workitem.rb +69 -0
  217. data/test/functional/ft_59_pause.rb +343 -0
  218. data/test/functional/ft_5_on_error.rb +384 -0
  219. data/test/functional/ft_60_code_participant.rb +45 -0
  220. data/test/functional/ft_61_trailing_fields.rb +34 -0
  221. data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
  222. data/test/functional/ft_6_on_cancel.rb +221 -0
  223. data/test/functional/ft_7_tags.rb +177 -0
  224. data/test/functional/ft_8_participant_consumption.rb +124 -0
  225. data/test/functional/ft_9_subprocesses.rb +146 -0
  226. data/test/functional/restart_base.rb +34 -0
  227. data/test/functional/rt_0_wait.rb +55 -0
  228. data/test/functional/rt_1_listen.rb +56 -0
  229. data/test/functional/rt_2_errors.rb +56 -0
  230. data/test/functional/rt_3_once.rb +70 -0
  231. data/test/functional/rt_4_cron.rb +64 -0
  232. data/test/functional/rt_5_timeout.rb +60 -0
  233. data/test/functional/rtest.rb +8 -0
  234. data/test/functional/storage_helper.rb +93 -0
  235. data/test/functional/test.rb +44 -0
  236. data/test/functional/vertical.rb +46 -0
  237. data/test/path_helper.rb +15 -0
  238. data/test/test.rb +13 -0
  239. data/test/test_helper.rb +28 -0
  240. data/test/unit/storage.rb +428 -0
  241. data/test/unit/storages.rb +37 -0
  242. data/test/unit/test.rb +28 -0
  243. data/test/unit/ut_0_ruby_reader.rb +223 -0
  244. data/test/unit/ut_11_lookup.rb +122 -0
  245. data/test/unit/ut_13_serializer.rb +65 -0
  246. data/test/unit/ut_14_is_uri.rb +28 -0
  247. data/test/unit/ut_15_util.rb +57 -0
  248. data/test/unit/ut_16_reader.rb +225 -0
  249. data/test/unit/ut_18_engine.rb +47 -0
  250. data/test/unit/ut_19_part_template.rb +86 -0
  251. data/test/unit/ut_1_fei.rb +165 -0
  252. data/test/unit/ut_20_composite_storage.rb +74 -0
  253. data/test/unit/ut_21_svc_participant_list.rb +46 -0
  254. data/test/unit/ut_22_filter.rb +1094 -0
  255. data/test/unit/ut_23_svc_tracker.rb +48 -0
  256. data/test/unit/ut_24_radial_reader.rb +332 -0
  257. data/test/unit/ut_25_merge.rb +113 -0
  258. data/test/unit/ut_3_wait_logger.rb +39 -0
  259. data/test/unit/ut_4_expmap.rb +20 -0
  260. data/test/unit/ut_5_tree.rb +54 -0
  261. data/test/unit/ut_6_condition.rb +303 -0
  262. data/test/unit/ut_7_workitem.rb +99 -0
  263. data/test/unit/ut_8_tree_to_dot.rb +72 -0
  264. data/test/unit/ut_9_xml_reader.rb +61 -0
  265. metadata +504 -0
@@ -0,0 +1,122 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ module Ruote
27
+
28
+ #
29
+ # Encapsulating all the information about an error in a process instance.
30
+ #
31
+ class ProcessError
32
+
33
+ # When this instance was returned by Ruote::Engine#ps or
34
+ # Ruote::Engine#process, this attribute will point to the flow expression
35
+ # where the error occurred.
36
+ #
37
+ attr_accessor :flow_expression
38
+
39
+ def initialize(h)
40
+ @h = h
41
+ end
42
+
43
+ def message
44
+ @h['message']
45
+ end
46
+
47
+ def trace
48
+ @h['trace']
49
+ end
50
+
51
+ def msg
52
+ @h['msg']
53
+ end
54
+
55
+ def fei
56
+ Ruote::FlowExpressionId.new(msg['fei'])
57
+ end
58
+
59
+ def wfid
60
+ msg['fei']['wfid']
61
+ end
62
+
63
+ def tree
64
+ @h['msg']['tree']
65
+ end
66
+
67
+ def at
68
+ @h['msg']['put_at']
69
+ end
70
+
71
+ # A shortcut for modifying the tree of an expression when it has had
72
+ # an error upon being applied.
73
+ #
74
+ def tree=(t)
75
+ @h['msg']['tree'] = t
76
+ end
77
+
78
+ def to_h
79
+ @h
80
+ end
81
+
82
+ # 'apply', 'reply', 'receive', ... Indicates in which "direction" the
83
+ # error occured.
84
+ #
85
+ def action
86
+ @h['msg']['action']
87
+ end
88
+
89
+ # Exposes the workitem fields directly.
90
+ #
91
+ def fields
92
+ @h['msg']['workitem'] && @h['msg']['workitem']['fields']
93
+ end
94
+
95
+ # Returns an instance of Ruote::Workitem
96
+ #
97
+ def workitem
98
+ Ruote::Workitem.new(msg['workitem'])
99
+ end
100
+
101
+ # Returns an array of deviations (see the 'filter' expression) if the
102
+ # error is a Ruote::ValidationError.
103
+ #
104
+ def deviations
105
+ @h['deviations']
106
+ end
107
+
108
+ protected
109
+
110
+ def to_dot(opts)
111
+
112
+ i = fei.to_storage_id
113
+ label = "error : #{message.gsub(/"/, "'")}"
114
+
115
+ [
116
+ "\"err_#{i}\" [ label = \"#{label}\" ];",
117
+ "\"err_#{i}\" -> \"#{i}\" [ style = \"dotted\" ];"
118
+ ]
119
+ end
120
+ end
121
+ end
122
+
@@ -0,0 +1,448 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+ require 'ruote/engine/process_error'
26
+
27
+
28
+ module Ruote
29
+
30
+ #
31
+ # A 'view' on the status of a process instance.
32
+ #
33
+ # Returned by the #process and the #processes methods of the Engine.
34
+ #
35
+ class ProcessStatus
36
+
37
+ # The expressions that compose the process instance.
38
+ #
39
+ attr_reader :expressions
40
+
41
+ # Returns the expression at the root of the process instance.
42
+ #
43
+ attr_reader :root_expression
44
+
45
+ # An array of the workitems currently in the storage participant for this
46
+ # process instance.
47
+ #
48
+ # Do not confuse with #workitems
49
+ #
50
+ attr_reader :stored_workitems
51
+
52
+ # An array of errors currently plaguing the process instance. Hopefully,
53
+ # this array is empty.
54
+ #
55
+ attr_reader :errors
56
+
57
+ # An array of schedules (open structs yielding information about the
58
+ # schedules of this process)
59
+ #
60
+ attr_reader :schedules
61
+
62
+ # Called by Ruote::Engine#processes or Ruote::Engine#process.
63
+ #
64
+ def initialize(context, expressions, stored_workitems, errors, schedules)
65
+
66
+ #
67
+ # preparing data
68
+
69
+ @expressions = expressions.collect { |e|
70
+ Ruote::Exp::FlowExpression.from_h(context, e) }
71
+ @expressions.sort! { |a, b| a.fei.expid <=> b.fei.expid }
72
+
73
+ @stored_workitems = stored_workitems.collect { |h|
74
+ Ruote::Workitem.new(h)
75
+ }
76
+
77
+ @errors = errors.sort! { |a, b| a.fei.expid <=> b.fei.expid }
78
+ @schedules = schedules.sort! { |a, b| a['owner'].sid <=> b['owner'].sid }
79
+
80
+ @root_expression = root_expressions.first
81
+
82
+ #
83
+ # linking errors and expressions for easy navigation
84
+
85
+ @errors.each do |err|
86
+ err.flow_expression = @expressions.find { |fexp| fexp.fei == err.fei }
87
+ err.flow_expression.error = err if err.flow_expression
88
+ end
89
+ end
90
+
91
+ # Returns a list of all the expressions that have no parent expression.
92
+ # The list is sorted with the deeper (closer to the original root) first.
93
+ #
94
+ def root_expressions
95
+
96
+ roots = @expressions.select { |e| e.h.parent_id == nil }
97
+
98
+ roots = roots.inject({}) { |h, e|
99
+ h["#{e.h.fei['expid']}__#{e.h.fei['subid']}"] = e; h
100
+ }
101
+
102
+ roots.keys.sort.collect { |k| roots[k] }
103
+ end
104
+
105
+ # Given an expression id, returns the root (top ancestor) for its
106
+ # expression.
107
+ #
108
+ def root_expression_for(fei)
109
+
110
+ sfei = Ruote.sid(fei)
111
+
112
+ exp = @expressions.find { |fe| sfei == Ruote.sid(fe.fei) }
113
+
114
+ return nil unless exp
115
+ return exp if exp.parent_id.nil?
116
+
117
+ root_expression_for(exp.parent_id)
118
+ end
119
+
120
+ # Returns the process variables set for this process instance.
121
+ #
122
+ def variables
123
+
124
+ @root_expression && @root_expression.variables
125
+ end
126
+
127
+ # Returns a hash fei => variable_hash containing all the variable bindings
128
+ # (expression by expression) of the process instance.
129
+ #
130
+ def all_variables
131
+
132
+ @expressions.inject({}) do |h, exp|
133
+ h[exp.fei] = exp.variables if exp.variables
134
+ h
135
+ end
136
+ end
137
+
138
+ # Returns a hash tagname => fei of tags set at the root of the process
139
+ # instance.
140
+ #
141
+ def tags
142
+
143
+ Hash[variables.select { |k, v| FlowExpressionId.is_a_fei?(v) }]
144
+ end
145
+
146
+ # Returns a hash tagname => array of feis of all the tags set in the process
147
+ # instance.
148
+ #
149
+ def all_tags
150
+
151
+ all_variables.inject({}) do |h, (fei, vars)|
152
+ vars.each { |k, v| (h[k] ||= []) << v if FlowExpressionId.is_a_fei?(v) }
153
+ h
154
+ end
155
+ end
156
+
157
+ # Returns the unique identifier for this process instance.
158
+ #
159
+ def wfid
160
+
161
+ @expressions.any? ? @expressions.first.fei.wfid : @errors.first.fei.wfid
162
+ end
163
+
164
+ # For a process
165
+ #
166
+ # Ruote.process_definition :name => 'review', :revision => '0.1' do
167
+ # author
168
+ # reviewer
169
+ # end
170
+ #
171
+ # will yield 'review'.
172
+ #
173
+ def definition_name
174
+
175
+ @root_expression && (
176
+ @root_expression.attribute('name') ||
177
+ @root_expression.attribute_text)
178
+ end
179
+
180
+ # For a process
181
+ #
182
+ # Ruote.process_definition :name => 'review', :revision => '0.1' do
183
+ # author
184
+ # reviewer
185
+ # end
186
+ #
187
+ # will yield '0.1'.
188
+ #
189
+ def definition_revision
190
+
191
+ @root_expression && (
192
+ @root_expression.attribute('revision') ||
193
+ @root_expression.attribute('rev'))
194
+ end
195
+
196
+ # Returns the 'position' of the process.
197
+ #
198
+ # pdef = Ruote.process_definition do
199
+ # alpha :task => 'clean car'
200
+ # end
201
+ # wfid = engine.launch(pdef)
202
+ #
203
+ # sleep 0.500
204
+ #
205
+ # engine.process(wfid) # => [["0_0", "alpha", {"task"=>"clean car"}]]
206
+ #
207
+ # A process with concurrent branches will yield multiple 'positions'.
208
+ #
209
+ # It uses #workitems underneath.
210
+ #
211
+ # If you want to list all the expressions where the "flow currently is"
212
+ # regardless they are participant expressions or errors, look at the
213
+ # #leaves method.
214
+ #
215
+ def position
216
+
217
+ workitems.collect { |wi|
218
+
219
+ r = [ wi.fei.sid, wi.participant_name ]
220
+
221
+ params = (wi.fields['params'] || {}).dup
222
+ params.delete('ref')
223
+
224
+ if err = errors.find { |e| e.fei == wi.fei }
225
+ params['error'] = err.message
226
+ end
227
+
228
+ r << params
229
+ r
230
+ }
231
+ end
232
+
233
+ # Returns the expressions where the flow is currently, ak the leaves
234
+ # of the execution tree.
235
+ #
236
+ # Whereas #position only looks at participant expressions (and errors),
237
+ # #leaves looks at any expressions that is a leave (which has no
238
+ # child at this point).
239
+ #
240
+ # Returns an array of FlowExpression instances. (Note that they may
241
+ # have their attribute #error set).
242
+ #
243
+ def leaves
244
+
245
+ expressions.inject([]) { |a, exp|
246
+ a.select { |e| ! exp.ancestor?(e.fei) } + [ exp ]
247
+ }
248
+ end
249
+
250
+ # Returns the workitem as was applied at the root expression.
251
+ #
252
+ def root_workitem
253
+
254
+ Ruote::Workitem.new(root_expression.h.applied_workitem)
255
+ end
256
+
257
+ # Returns a list of the workitems currently 'out' to participants
258
+ #
259
+ # For example, with an instance of
260
+ #
261
+ # Ruote.process_definition do
262
+ # concurrence do
263
+ # alpha :task => 'clean car'
264
+ # bravo :task => 'sell car'
265
+ # end
266
+ # end
267
+ #
268
+ # calling engine.process(wfid).workitems will yield two workitems
269
+ # (alpha and bravo).
270
+ #
271
+ # Warning : do not confuse the workitems here with the workitems held
272
+ # in a storage participant or equivalent.
273
+ #
274
+ def workitems
275
+
276
+ @expressions.select { |fexp|
277
+ fexp.is_a?(Ruote::Exp::ParticipantExpression)
278
+ }.collect { |fexp|
279
+ Ruote::Workitem.new(fexp.h.applied_workitem)
280
+ }
281
+ end
282
+
283
+ # Returns a parseable UTC datetime string which indicates when the process
284
+ # was last active.
285
+ #
286
+ def last_active
287
+
288
+ @expressions.collect { |fexp| fexp.h.put_at }.max
289
+ end
290
+
291
+ # Returns the process definition tree as it was when this process instance
292
+ # was launched.
293
+ #
294
+ def original_tree
295
+
296
+ @root_expression && @root_expression.original_tree
297
+ end
298
+
299
+ # Returns a Time instance indicating when the process instance was launched.
300
+ #
301
+ def launched_time
302
+
303
+ @root_expression && @root_expression.created_time
304
+ end
305
+
306
+ def to_s
307
+
308
+ "(process_status wfid '#{wfid}', " +
309
+ "expressions #{@expressions.size}, " +
310
+ "stored_workitems #{@stored_workitems.size}, " +
311
+ "errors #{@errors.size}, " +
312
+ "schedules #{@schedules.size}, " +
313
+ ")"
314
+ end
315
+
316
+ def inspect
317
+
318
+ vars = variables rescue nil
319
+ avars = all_variables.inject({}) { |h, (k, v)| h[Ruote.sid(k)] = v; h }
320
+
321
+ s = [ "== #{self.class} ==" ]
322
+ s << " expressions : #{@expressions.size}"
323
+ @expressions.each do |e|
324
+ s << " #{e.fei.to_storage_id}"
325
+ s << " | #{e.name}"
326
+ s << " | * #{e.state} *" if e.state
327
+ s << " | #{e.attributes.inspect}"
328
+ s << " `-parent--> #{e.h.parent_id ? e.parent_id.to_storage_id : 'nil'}"
329
+ end
330
+ s << " schedules : #{@schedules.size}"
331
+ s << " stored workitems : #{@stored_workitems.size}"
332
+ s << " variables : #{vars.inspect}"
333
+ s << " all_variables : #{avars.inspect}"
334
+ s << " errors : #{@errors.size}"
335
+ @errors.each do |e|
336
+ s << " ***"
337
+ s << " #{e.fei.to_storage_id} :" if e.fei
338
+ s << " action : #{e.action}"
339
+ s << " message : #{e.message}"
340
+ s << " trace :"
341
+ e.trace.split("\n").each do |line|
342
+ s << " #{line}"
343
+ end
344
+ s << " fields : #{e.fields.inspect}"
345
+ end
346
+
347
+ s.join("\n") + "\n"
348
+ end
349
+
350
+ # Returns a 'dot' representation of the process. A graph describing
351
+ # the tree of flow expressions that compose the process.
352
+ #
353
+ def to_dot(opts={})
354
+
355
+ s = [ "digraph \"process wfid #{wfid}\" {" ]
356
+ @expressions.each { |e| s.push(*e.send(:to_dot, opts)) }
357
+ @errors.each { |e| s.push(*e.send(:to_dot, opts)) }
358
+ s << "}"
359
+
360
+ s.join("\n")
361
+ end
362
+
363
+ #--
364
+ #def to_h
365
+ # h = {}
366
+ # %w[
367
+ # wfid
368
+ # definition_name definition_revision
369
+ # original_tree current_tree
370
+ # variables tags
371
+ # ].each { |m| h[m] = self.send(m) }
372
+ # h['launched_time'] = launched_time
373
+ # h['last_active'] = last_active
374
+ # # all_variables and all_tags ?
375
+ # h['root_expression'] = nil
376
+ # h['expressions'] = @expressions.collect { |e| e.fei.to_h }
377
+ # h['errors'] = @errors.collect { |e| e.to_h }
378
+ # h
379
+ #end
380
+ #++
381
+
382
+ # Returns the current version of the process definition tree. If no
383
+ # manipulation (gardening) was performed on the tree, this method yields
384
+ # the same result as the #original_tree method.
385
+ #
386
+ def current_tree
387
+
388
+ h = Ruote.decompose_tree(original_tree)
389
+
390
+ @expressions.sort { |e0, e1|
391
+
392
+ e0.fei.expid <=> e1.fei.expid
393
+
394
+ }.each { |e|
395
+
396
+ trigger = e.tree[1]['_triggered']
397
+
398
+ tree = if trigger && trigger != 'on_re_apply'
399
+ t = original_tree_from_parent(e).dup
400
+ t[1]['_triggered'] = trigger
401
+ t
402
+ else
403
+ e.tree
404
+ end
405
+
406
+ h.merge!(Ruote.decompose_tree(tree, e.fei.expid))
407
+ }
408
+
409
+ Ruote.recompose_tree(h)
410
+ end
411
+
412
+ protected
413
+
414
+ def original_tree_from_parent(e)
415
+
416
+ parent = @expressions.find { |exp| exp.fei == e.parent_id }
417
+
418
+ parent ? parent.tree[2][e.fei.child_id] : e.tree
419
+ end
420
+ end
421
+
422
+ def self.decompose_tree(t, pos='0', h={})
423
+
424
+ h[pos] = t[0, 2]
425
+ t[2].each_with_index { |c, i| decompose_tree(c, "#{pos}_#{i}", h) }
426
+ h
427
+ end
428
+
429
+ def self.recompose_tree(h, pos='0')
430
+
431
+ t = h[pos]
432
+
433
+ return nil unless t
434
+
435
+ t << []
436
+ i = 0
437
+
438
+ loop do
439
+ tt = recompose_tree(h, "#{pos}_#{i}")
440
+ break unless tt
441
+ t.last << tt
442
+ i = i + 1
443
+ end
444
+
445
+ t
446
+ end
447
+ end
448
+