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,154 @@
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::Exp
27
+
28
+ #
29
+ # The 'apply' expression is an advanced expression.
30
+ #
31
+ # It takes as input an AST and applies it. The AST may be placed in a field
32
+ # or a variable or passed directly to the apply.
33
+ #
34
+ # These apply examples :
35
+ #
36
+ # apply :tree => [ 'echo', { 'nada' => nil }, [] ]
37
+ #
38
+ # sequence do
39
+ # set :var => 'tree', :val => [ 'echo', { 'nada' => nil }, [] ]
40
+ # apply # looks by default in variable 'tree'
41
+ # end
42
+ #
43
+ # sequence do
44
+ # set :var => 't', :val => [ 'echo', { 'nada' => nil }, [] ]
45
+ # apply :tree_var => 't'
46
+ # end
47
+ #
48
+ # sequence do
49
+ # set :field => 't', :val => [ 'echo', { 'nada' => nil }, [] ]
50
+ # apply :tree_field => 't'
51
+ # end
52
+ #
53
+ # All are equivalent to
54
+ #
55
+ # echo 'nada'
56
+ #
57
+ #
58
+ # == apply and subprocesses
59
+ #
60
+ # There is an interesting way of using 'apply', it's close to the way of
61
+ # the Ruby "yield" expression.
62
+ #
63
+ # pdef = Ruote.process_definition 'test' do
64
+ # sequence do
65
+ # handle do
66
+ # participant 'alpha'
67
+ # end
68
+ # handle do
69
+ # participant 'bravo'
70
+ # end
71
+ # end
72
+ # define 'handle' do
73
+ # sequence do
74
+ # participant 'prepare_data'
75
+ # apply
76
+ # participant 'rearrange_data'
77
+ # end
78
+ # end
79
+ # end
80
+ #
81
+ # With this process definition, the particpant alpha and bravo are handed
82
+ # a workitem in sequence, but each time, the data gets prepared and
83
+ # re-arranged.
84
+ #
85
+ # 'apply' simply picks the value of the tree to apply in the local variable
86
+ # 'tree'.
87
+ #
88
+ # Passing variables to applied trees is possible :
89
+ #
90
+ # pdef = Ruote.process_definition do
91
+ # handle do
92
+ # participant '${v:target}', :message => 'x'
93
+ # end
94
+ # define 'handle' do
95
+ # sequence do
96
+ # participant 'prepare_data'
97
+ # apply :v => 'alpha'
98
+ # apply :v => 'bravo'
99
+ # participant 'rearrange_data'
100
+ # end
101
+ # end
102
+ # end
103
+ #
104
+ #
105
+ # == on_error
106
+ #
107
+ # It's OK, to place an on_error on the apply
108
+ #
109
+ # pdef = Ruote.process_definition do
110
+ # handle do
111
+ # sequence do
112
+ # echo 'in'
113
+ # nemo
114
+ # end
115
+ # end
116
+ # define 'handle' do
117
+ # apply :on_error => 'notify' # <==
118
+ # echo 'over.'
119
+ # end
120
+ # define 'notify' do
121
+ # echo 'error'
122
+ # end
123
+ # end
124
+ #
125
+ class ApplyExpression < FlowExpression
126
+
127
+ names :apply
128
+
129
+ # TODO : maybe accept directly ruby and xml (and json)
130
+ # TODO : _yield ?
131
+
132
+ # TODO : apply [ 'echo', { 'nada' => nil }, [] ]
133
+
134
+ def apply
135
+
136
+ #
137
+ # find 'tree'
138
+
139
+ tree =
140
+ lookup_val_prefix('tree', :escape => true) ||
141
+ lookup_variable('tree')
142
+
143
+ return reply_to_parent(h.applied_workitem) unless tree
144
+
145
+ #
146
+ # apply 'tree'
147
+
148
+ launch_sub(
149
+ "#{h.fei['expid']}_0", tree,
150
+ :variables => compile_atts(:escape => true))
151
+ end
152
+ end
153
+ end
154
+
@@ -0,0 +1,78 @@
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::Exp
27
+
28
+ #
29
+ # Cancels a whole process instance.
30
+ #
31
+ # pdef = Ruote.process_definition :name => 'test' do
32
+ # sequence do
33
+ # participant :ref => 'editor'
34
+ # concurrence do
35
+ # participant :ref => 'reviewer1'
36
+ # participant :ref => 'reviewer2'
37
+ # sequence do
38
+ # participant :ref => 'main_reviewer'
39
+ # cancel_process :if => '${f:over} == true'
40
+ # end
41
+ # end
42
+ # participant :ref => 'editor'
43
+ # end
44
+ # end
45
+ #
46
+ # This example has a 'main_reviewer' with the ability to cancel the whole
47
+ # process, if he sets the workitem field 'over' to 'true'.
48
+ #
49
+ # If the goal is to cancel only a segment of a process instance, the
50
+ # expression 'undo' (Ruote::Exp::UndoExpression) is better suited.
51
+ #
52
+ # == 'terminate'
53
+ #
54
+ # Sometimes 'terminate' reads better than 'cancel_process'
55
+ #
56
+ # Ruote.process_definition do
57
+ # alice :task => 'do this'
58
+ # terminate :if => '${no_need_for_bob}'
59
+ # bob :task => 'do that'
60
+ # charly :task => 'just do it'
61
+ # end
62
+ #
63
+ class CancelProcessExpression < FlowExpression
64
+
65
+ names :cancel_process, :terminate
66
+
67
+ def apply
68
+
69
+ @context.storage.put_msg('cancel_process', 'wfid' => h.fei['wfid'])
70
+ end
71
+
72
+ def reply(workitem)
73
+
74
+ # never called
75
+ end
76
+ end
77
+ end
78
+
@@ -0,0 +1,156 @@
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
+ require 'ruote/exp/command'
27
+
28
+
29
+ module Ruote::Exp
30
+
31
+ #
32
+ # This class gathers the 'skip', 'back', 'jump', 'rewind', 'continue', 'reset'
33
+ # and 'break' expressions which are used inside of the 'cursor' and 'repeat'
34
+ # (loop) expressions.
35
+ #
36
+ # Look at the 'cursor' expression Ruote::Exp::Cursor for a discussion of
37
+ # each of those [sub]expressions.
38
+ #
39
+ # The expression that understand commands are 'cursor', 'repeat' ('loop') and
40
+ # 'iterator'.
41
+ # 'concurrent_iterator' does not understand commands since it fires all its
42
+ # branches when applied.
43
+ #
44
+ # == :ref => 'tag'
45
+ #
46
+ # It's OK to tag a cursor/loop/iterator with the :tag attribute and then
47
+ # point a command to it via :ref :
48
+ #
49
+ # concurrence do
50
+ #
51
+ # cursor :tag => 'main' do
52
+ # author
53
+ # editor
54
+ # publisher
55
+ # end
56
+ #
57
+ # # meanwhile ...
58
+ #
59
+ # sequence do
60
+ # sponsor
61
+ # rewind :ref => 'main', :if => '${f:stop}'
62
+ # end
63
+ # end
64
+ #
65
+ # This :ref technique may also be used with nested cursor/loop/iterator
66
+ # constructs :
67
+ #
68
+ # cursor :tag => 'main' do
69
+ # cursor do
70
+ # author
71
+ # editor
72
+ # rewind :if => '${f:not_ok}'
73
+ # _break :ref => 'main', :if => '${f:abort_everything}'
74
+ # end
75
+ # head_of_edition
76
+ # rewind :if => '${f:not_ok}'
77
+ # publisher
78
+ # end
79
+ #
80
+ # this example features two nested cursors. There is a "_break" in the inner
81
+ # cursor, but it will break the main 'cursor' (and thus break the whole
82
+ # review process).
83
+ #
84
+ # :ref works with the 'iterator' expression as well.
85
+ #
86
+ class CommandExpression < FlowExpression
87
+
88
+ include CommandMixin
89
+
90
+ names :skip, :back, :jump, :rewind, :continue, :break, :stop, :over, :reset
91
+
92
+ def apply
93
+
94
+ param = case name
95
+ when 'skip', 'back' then attribute(:step) || attribute_text
96
+ when 'jump' then attribute(:to) || attribute_text
97
+ else nil
98
+ end
99
+
100
+ param = Integer(param) rescue param
101
+
102
+ command_workitem = Ruote.fulldup(h.applied_workitem)
103
+
104
+ set_command(command_workitem, name, param)
105
+
106
+ target = parent
107
+ ancestor = true
108
+
109
+ if ref = attribute(:ref)
110
+
111
+ fei = lookup_variable(ref)
112
+
113
+ target = Ruote::FlowExpressionId.is_a_fei?(fei) ?
114
+ Ruote::Exp::FlowExpression.fetch(@context, fei) : nil
115
+
116
+ target = target.is_a?(Ruote::Exp::CommandedExpression) ?
117
+ target : nil
118
+
119
+ ancestor = target ? ancestor?(target.h.fei) : false
120
+
121
+ else
122
+
123
+ target = fetch_command_target
124
+ end
125
+
126
+ return reply_to_parent(h.applied_workitem) if target.nil?
127
+ return reply_to_parent(command_workitem) if target.h.fei == h.parent_id
128
+
129
+ @context.storage.put_msg(
130
+ 'reply',
131
+ 'fei' => target.h.fei,
132
+ 'workitem' => command_workitem,
133
+ 'command' => [ name, param ]) # purely indicative for now
134
+
135
+ reply_to_parent(h.applied_workitem) unless ancestor
136
+ end
137
+
138
+ protected
139
+
140
+ # Walks up the expression tree (process instance and returns the first
141
+ # expression that includes the CommandMixin
142
+ #
143
+ # (CommandExpression includes CommandMixin, but since it doesn't have
144
+ # children, no need to 'evince' it)
145
+ #
146
+ def fetch_command_target(exp=parent)
147
+
148
+ case exp
149
+ when nil then nil
150
+ when Ruote::Exp::CommandedExpression then exp
151
+ else fetch_command_target(exp.parent)
152
+ end
153
+ end
154
+ end
155
+ end
156
+
@@ -0,0 +1,321 @@
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
+ require 'ruote/exp/merge'
27
+
28
+
29
+ module Ruote::Exp
30
+
31
+ #
32
+ # The 'concurrence' expression applies its child branches in parallel
33
+ # (well it makes a best effort to make them run in parallel).
34
+ #
35
+ # concurrence do
36
+ # alpha
37
+ # bravo
38
+ # end
39
+ #
40
+ # == attributes
41
+ #
42
+ # The concurrence expression takes a number of attributes that allow for
43
+ # sophisticated control (especially at merge time).
44
+ #
45
+ # === :count
46
+ #
47
+ # concurrence :count => 1 do
48
+ # alpha
49
+ # bravo
50
+ # end
51
+ #
52
+ # in that example, the concurrence will terminate as soon as 1 (count) of
53
+ # the branches replies. The other branch will get cancelled.
54
+ #
55
+ # === :remaining
56
+ #
57
+ # As said for :count, the remaining branches get cancelled. By setting
58
+ # :remaining to :forget (or 'forget'), the remaining branches will continue
59
+ # their execution, forgotten.
60
+ #
61
+ # concurrence :count => 1, :remaining => :forget do
62
+ # alpha
63
+ # bravo
64
+ # end
65
+ #
66
+ # === :merge
67
+ #
68
+ # By default, the workitems override each others. By default, the first
69
+ # workitem to reply will win.
70
+ #
71
+ # sequence do
72
+ # concurrence do
73
+ # alpha
74
+ # bravo
75
+ # end
76
+ # charly
77
+ # end
78
+ #
79
+ # In that example, if 'alpha' replied first, the workitem that reaches
80
+ # 'charly' once 'bravo' replied will have the payload as seen/modified by
81
+ # 'alpha'.
82
+ #
83
+ # The :merge attribute determines which branch wins the merge.
84
+ #
85
+ # * first (default)
86
+ # * last
87
+ # * highest
88
+ # * lowest
89
+ #
90
+ # highest and lowest refer to the position in the list of branch. It's useful
91
+ # to set a fixed winner.
92
+ #
93
+ # concurrence :merge => :highest do
94
+ # alpha
95
+ # bravo
96
+ # end
97
+ #
98
+ # makes sure that alpha's version of the workitem wins.
99
+ #
100
+ # === :merge_type
101
+ #
102
+ # ==== :override
103
+ #
104
+ # By default, the merge type is set to 'override', which means that the
105
+ # 'winning' workitem's payload supplants all other workitems' payloads.
106
+ #
107
+ # ==== :mix
108
+ #
109
+ # Setting :merge_type to :mix, will actually attempt to merge field by field,
110
+ # making sure that the field value of the winner(s) are used.
111
+ #
112
+ # ==== :isolate
113
+ #
114
+ # :isolate will rearrange the resulting workitem payload so that there is
115
+ # a new field for each branch. The name of each field is the index of the
116
+ # branch from '0' to ...
117
+ #
118
+ # ==== :stack
119
+ #
120
+ # :stack will stack the workitems coming back from the concurrence branches
121
+ # in an array whose order is determined by the :merge attributes. The array
122
+ # is placed in the 'stack' field of the resulting workitem.
123
+ # Note that the :stack merge_type also creates a 'stack_attributes' field
124
+ # and populates it with the expanded attributes of the concurrence.
125
+ #
126
+ # Thus
127
+ #
128
+ # sequence do
129
+ # concurrence :merge => :highest, :merge_type => :stack do
130
+ # reviewer1
131
+ # reviewer2
132
+ # end
133
+ # editor
134
+ # end
135
+ #
136
+ # will see the 'editor' receive a workitem whose fields look like :
137
+ #
138
+ # { 'stack' => [{ ... reviewer1 fields ... }, { ... reviewer2 fields ... }],
139
+ # 'stack_attributes' => { 'merge'=> 'highest', 'merge_type' => 'stack' } }
140
+ #
141
+ # This could prove useful for participant having to deal with multiple merge
142
+ # strategy results.
143
+ #
144
+ # ==== :union
145
+ #
146
+ # Will override atomic fields, concat arrays and merge hashes...
147
+ #
148
+ # The union of those two workitems
149
+ #
150
+ # { 'a' => 0, 'b' => [ 'x' ], 'c' => { 'aa' => 'bb' }
151
+ # { 'a' => 1, 'b' => [ 'y' ], 'c' => { 'cc' => 'dd' }
152
+ #
153
+ # will be
154
+ #
155
+ # { 'a' => 1, 'b' => [ 'x', 'y' ], 'c' => { 'aa' => 'bb', 'cc' => 'dd' } }
156
+ #
157
+ #
158
+ # === :over_if (and :over_unless)
159
+ #
160
+ # Like the :count attribute controls how many branches have to reply before
161
+ # a concurrence ends, the :over attribute is used to specify a condition
162
+ # upon which the concurrence will [prematurely] end.
163
+ #
164
+ # concurrence :over_if => '${f:over}'
165
+ # alpha
166
+ # bravo
167
+ # charly
168
+ # end
169
+ #
170
+ # will end the concurrence as soon as one of the branches replies with a
171
+ # workitem whose field 'over' is set to true. (the remaining branches will
172
+ # get cancelled unless :remaining => :forget is set).
173
+ #
174
+ # :over_unless needs no explanation.
175
+ #
176
+ class ConcurrenceExpression < FlowExpression
177
+
178
+ include MergeMixin
179
+
180
+ names :concurrence
181
+
182
+ def apply
183
+
184
+ h.ccount = attribute(:count).to_i rescue 0
185
+ h.ccount = nil if h.ccount < 1
186
+
187
+ h.cmerge = att(:merge, %w[ first last highest lowest ])
188
+ h.cmerge_type = att(:merge_type, %w[ override mix isolate stack union ])
189
+ h.remaining = att(:remaining, %w[ cancel forget ])
190
+
191
+ h.workitems = (h.cmerge == 'first' || h.cmerge == 'last') ? [] : {}
192
+
193
+ h.over = false
194
+
195
+ apply_children
196
+ end
197
+
198
+ def reply(workitem)
199
+
200
+ workitem = Ruote.fulldup(workitem)
201
+ #
202
+ # since workitem field merging might happen, better to work on
203
+ # a copy of the workitem (so that history, coming afterwards,
204
+ # doesn't see a modified version of the workitem)
205
+
206
+ if h.cmerge == 'first' || h.cmerge == 'last'
207
+ h.workitems << workitem
208
+ else
209
+ h.workitems[workitem['fei']['expid']] = workitem
210
+ end
211
+
212
+ over = h.over
213
+ h.over = over || over?(workitem)
214
+
215
+ if (not over) && h.over
216
+ # just became 'over'
217
+
218
+ reply_to_parent(nil)
219
+
220
+ elsif h.children.empty?
221
+
222
+ do_unpersist || return
223
+
224
+ @context.storage.put_msg(
225
+ 'ceased',
226
+ 'wfid' => h.fei['wfid'], 'fei' => h.fei, 'workitem' => workitem)
227
+ else
228
+
229
+ do_persist
230
+ end
231
+ end
232
+
233
+ protected
234
+
235
+ def apply_children
236
+
237
+ # a) register children
238
+ # b) persist
239
+ # c) trigger children applies
240
+
241
+ msgs = []
242
+
243
+ tree_children.each_with_index do |c, i|
244
+ msgs << pre_apply_child(i, h.applied_workitem.dup, false)
245
+ end
246
+
247
+ persist_or_raise
248
+
249
+ msgs.each { |m| @context.storage.put_msg('apply', m) }
250
+ end
251
+
252
+ def over?(workitem)
253
+
254
+ over_if = attribute(:over_if, workitem)
255
+ over_unless = attribute(:over_unless, workitem)
256
+
257
+ if over_if && Condition.true?(over_if)
258
+ true
259
+ elsif over_unless && (not Condition.true?(over_unless))
260
+ true
261
+ else
262
+ (h.workitems.size >= expected_count)
263
+ end
264
+ end
265
+
266
+ # How many branch replies are expected before the concurrence is over ?
267
+ #
268
+ # (note : concurrent_iterator overrides it)
269
+ #
270
+ def expected_count
271
+
272
+ h.ccount ? [ h.ccount, tree_children.size ].min : tree_children.size
273
+ end
274
+
275
+ def reply_to_parent(_workitem)
276
+
277
+ workitem = merge_all_workitems
278
+
279
+ if h.ccount == nil || h.children.empty?
280
+
281
+ do_unpersist && super(workitem, false)
282
+
283
+ elsif h.remaining == 'cancel'
284
+
285
+ if r = do_unpersist
286
+
287
+ super(workitem, false)
288
+
289
+ h.children.each do |i|
290
+ @context.storage.put_msg('cancel', 'fei' => i) #unless replied?(i)
291
+ end
292
+ end
293
+
294
+ else # h.remaining == 'forget'
295
+
296
+ h.variables = compile_variables
297
+ h.forgotten = true
298
+
299
+ do_persist && super(workitem, false)
300
+ end
301
+ end
302
+
303
+ def merge_all_workitems
304
+
305
+ return h.applied_workitem if h.workitems.size < 1
306
+
307
+ wis = case h.cmerge
308
+ when 'first'
309
+ h.workitems.reverse
310
+ when 'last'
311
+ h.workitems
312
+ when 'highest', 'lowest'
313
+ is = h.workitems.keys.sort.collect { |k| h.workitems[k] }
314
+ h.cmerge == 'highest' ? is.reverse : is
315
+ end
316
+
317
+ merge_workitems(wis, h.cmerge_type)
318
+ end
319
+ end
320
+ end
321
+