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,110 @@
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
+ # Never replies to its parent expression. Simply applies its first child,
30
+ # if any, and just sits there.
31
+ #
32
+ # When cancelled, cancels its child (if any).
33
+ #
34
+ # In this example, the reminding sequence never replies to the concurrence.
35
+ # The concurrence is only over when "alfred" replies.
36
+ #
37
+ # Ruote.process_definition do
38
+ # concurrence :count => 1 do
39
+ # alfred
40
+ # lose do
41
+ # sequence do
42
+ # wait '2d'
43
+ # send_reminder_to_alfred
44
+ # wait '2h'
45
+ # send_alarm_to_boss
46
+ # end
47
+ # end
48
+ # end
49
+ # end
50
+ #
51
+ # Maybe shorter :
52
+ #
53
+ # Ruote.process_definition do
54
+ # concurrence :count => 1 do
55
+ # alfred
56
+ # sequence do
57
+ # wait '2d'
58
+ # send_reminder_to_alfred
59
+ # wait '2h'
60
+ # send_alarm_to_boss
61
+ # lose
62
+ # end
63
+ # end
64
+ # end
65
+ #
66
+ # 'lose' on its own acts like a dead-end.
67
+ #
68
+ #
69
+ # == the :lose attribute
70
+ #
71
+ # Every expression understands the 'lose' attribute :
72
+ #
73
+ # Ruote.process_definition do
74
+ # concurrence :count => 1 do
75
+ # alfred
76
+ # sequence :lose => true do
77
+ # wait '2d'
78
+ # send_reminder_to_alfred
79
+ # wait '2h'
80
+ # send_alarm_to_boss
81
+ # end
82
+ # end
83
+ # end
84
+ #
85
+ # Probably produces definitions more compact than when using the 'lose'
86
+ # expression.
87
+ #
88
+ # == forget vs lose
89
+ #
90
+ # forget : replies to parent expression immediately, is not cancellable
91
+ # (not reachable).
92
+ #
93
+ # lose : never replies to parent expression, is cancellable.
94
+ #
95
+ class LoseExpression < FlowExpression
96
+
97
+ names :lose
98
+
99
+ def apply
100
+
101
+ apply_child(0, h.applied_workitem)
102
+ end
103
+
104
+ def reply(workitem)
105
+
106
+ # never gets called
107
+ end
108
+ end
109
+ end
110
+
@@ -0,0 +1,45 @@
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
+ # 'No Operation' expression. Does nothing, immediately replies to
30
+ # its parent expression.
31
+ #
32
+ # Could be useful within a cursor expression with a :tag attribute
33
+ # as a jump expression target.
34
+ #
35
+ class NoOpExpression < FlowExpression
36
+
37
+ names :noop
38
+
39
+ def apply
40
+
41
+ reply_to_parent(h.applied_workitem)
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,215 @@
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 'once' / 'when' expression verifies if a condition is true,
30
+ # if not it will block and after 10 seconds it will check again.
31
+ # If true, it will resume or it will execute its child expression (before
32
+ # resuming).
33
+ #
34
+ # concurrence do
35
+ #
36
+ # once '${v:/invoice_status} == emitted' do
37
+ # open_customer_support_account
38
+ # end
39
+ #
40
+ # sequence do
41
+ # participant 'accounting'
42
+ # set 'v:/invoice_status' => 'emitted'
43
+ # participant 'accounting 2'
44
+ # end
45
+ # end
46
+ #
47
+ # The condition is usually something about variables, since the workitem that
48
+ # this expression has access to is always the one that reached it, at apply
49
+ # time.
50
+ #
51
+ # Without a child expression, this expression behaves in a 'blocking way', and
52
+ # it makes most sense in a 'sequence' or in a 'cursor'.
53
+ #
54
+ # sequence do
55
+ # first_stage
56
+ # once '${v:ready_for_second_stage}'
57
+ # second_stage
58
+ # end
59
+ #
60
+ # When there is a child expression, it will get triggered when the condition
61
+ # realizes. Only 1 child expression is accepted, there is no implicit
62
+ # 'sequence'.
63
+ #
64
+ # concurrence do
65
+ # once :test => '${v:go_on} == yes' do
66
+ # subprocess :ref => 'final_stage'
67
+ # end
68
+ # sequence do
69
+ # participant :ref => 'controller'
70
+ # set 'v:go_on' => 'yes'
71
+ # end
72
+ # end
73
+ #
74
+ # == :test
75
+ #
76
+ # Most of the example process definitions until now were placing the condition
77
+ # directly after the expression name itself. In an XML process definition or
78
+ # if you prefer it this way, you can use the :test attribute to formulate the
79
+ # condition :
80
+ #
81
+ # <once test="${v:ready}">
82
+ # <participant ref="role_publisher" />
83
+ # </once>
84
+ #
85
+ # In a Ruby process definition :
86
+ #
87
+ # once :test => '${v:ready}' do
88
+ # participant :ref => 'role_publisher'
89
+ # end
90
+ #
91
+ #
92
+ # == :frequency
93
+ #
94
+ # As said, the default 'check' frequency is 10 seconds. This can be changed
95
+ # by using the :frequency (or :freq) attribute.
96
+ #
97
+ # sequence do
98
+ # participant 'logistic_unit'
99
+ # once '${v:/delivery_ok}', :frequency => '2d'
100
+ # # block until delivery is OK (another branch of the process probably)
101
+ # # check every two days
102
+ # participant 'accounting_unit'
103
+ # end
104
+ #
105
+ #
106
+ # == :frequency and cron notation
107
+ #
108
+ # It's OK to pass a 'cron string' to the :frequency attribute.
109
+ #
110
+ # once '${v:delivery_complete}', :freq => '5 0 * * *'
111
+ # # this 'once' will check its condition once per day, five minutes
112
+ # # after midnight
113
+ #
114
+ # See "man 5 crontab" on your favourite unix system for the details of
115
+ # the 'cron string', but please note that ruote (thanks to the
116
+ # rufus-scheduler (http://rufus.rubyforge.org/rufus-scheduler) accepts
117
+ # seconds as well.
118
+ #
119
+ #
120
+ # == the :timeout attribute common to all expressions
121
+ #
122
+ # Don't forget that this expression, like all the other expressions accepts
123
+ # the :timeout attribute. It's perhaps better to use :timeout when there is
124
+ # a child expression, so that the child won't get 'triggered' in case of
125
+ # timeout. When there is no child expression and the 'once' behaves in a
126
+ # 'blocking way', a timeout will unblock, as if the condition became true.
127
+ #
128
+ #
129
+ # == ${ruby:'hello'}
130
+ #
131
+ # Remember that, if the engine's 'ruby_eval_allowed' is set to true, the
132
+ # condition may contain Ruby code.
133
+ #
134
+ # once '${r:"hell" + "o"} == hello'
135
+ #
136
+ # This Ruby code is checked before hand against malicious code, but beware...
137
+ #
138
+ #
139
+ # == aliases
140
+ #
141
+ # 'once', '_when' and 'as_soon_as' are three different names for this
142
+ # expression.
143
+ #
144
+ class OnceExpression < FlowExpression
145
+
146
+ names :once, :when, :as_soon_as
147
+
148
+ def apply
149
+
150
+ h.frequency = attribute(:frequency) || attribute(:freq) || '10s'
151
+ h.triggered = false
152
+ h.job_id = nil
153
+
154
+ reply(h.applied_workitem)
155
+ end
156
+
157
+ def reply(workitem)
158
+
159
+ return reply_to_parent(workitem) if h.triggered
160
+
161
+ t = attribute(:test) || attribute_text
162
+
163
+ if Condition.true?(t)
164
+
165
+ h.triggered = true
166
+
167
+ @context.storage.delete_schedule(h.job_id)
168
+ # especially for a cron...
169
+
170
+ if tree_children[0]
171
+ #
172
+ # trigger first child
173
+ #
174
+ apply_child(0, workitem)
175
+ else
176
+ #
177
+ # blocking case
178
+ #
179
+ reply_to_parent(workitem)
180
+ end
181
+ else
182
+
183
+ reschedule
184
+ end
185
+ end
186
+
187
+ def cancel(flavour)
188
+
189
+ @context.storage.delete_schedule(h.job_id)
190
+ super
191
+ end
192
+
193
+ protected
194
+
195
+ def reschedule
196
+
197
+ h.job_id = @context.storage.put_schedule(
198
+ 'cron',
199
+ h.fei,
200
+ h.frequency,
201
+ 'action' => 'reply',
202
+ 'fei' => h.fei,
203
+ 'workitem' => h.applied_workitem)
204
+
205
+ @context.storage.delete_schedule(h.job_id) if try_persist
206
+ #
207
+ # if the persist failed, immediately unschedule
208
+ # the just scheduled job
209
+ #
210
+ # this is meant to cope with cases where one worker reschedules
211
+ # while another just cancelled
212
+ end
213
+ end
214
+ end
215
+
@@ -0,0 +1,287 @@
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/condition'
27
+
28
+
29
+ module Ruote::Exp
30
+
31
+ #
32
+ # The 'participant' expression is very special. It sits on the fence between
33
+ # the engine and the external world.
34
+ #
35
+ # The participant expression is used to pass workitems to participants
36
+ # from the engine. Those participants are bound at start time (usually) in
37
+ # the engine via its register_participant method.
38
+ #
39
+ # Here's an example of two concurrent participant expressions in use :
40
+ #
41
+ # concurrence do
42
+ # participant :ref => 'alice'
43
+ # participant :ref => 'bob'
44
+ # end
45
+ #
46
+ # Upon encountering the two expressions, the engine will lookup their name
47
+ # in the participant map and hand the workitems to the participant instances
48
+ # registered for those names.
49
+ #
50
+ #
51
+ # == attributes passed as arguments
52
+ #
53
+ # All the attributes passed to a participant will be fed to the outgoing
54
+ # workitem under a new 'params' field.
55
+ #
56
+ # Thus, with
57
+ #
58
+ # participant :ref => 'alice', :task => 'maw the lawn', :timeout => '2d'
59
+ #
60
+ # Alice will receive a workitem with a field params set to
61
+ #
62
+ # { :ref => 'alice', :task => 'maw the lawn', :timeout => '2d' }
63
+ #
64
+ # The fields named 'params' will be deleted before the workitems resumes
65
+ # in the flow (with the engine replying to the parent expression of this
66
+ # participant expression).
67
+ #
68
+ #
69
+ # == simplified participant notation
70
+ #
71
+ # This process definition is equivalent to the one above. Less to write.
72
+ #
73
+ # concurrence do
74
+ # participant 'alice'
75
+ # bob
76
+ # end
77
+ #
78
+ # Please note that 'bob' alone could stand for the participant 'bob' or
79
+ # the subprocess named 'bob'. Subprocesses do take precedence over
80
+ # participants (if there is a subprocess named 'bob' and a participant
81
+ # named 'bob'.
82
+ #
83
+ #
84
+ # == participant defined timeout
85
+ #
86
+ # Usually, timeouts are given for an expression in the process definition.
87
+ #
88
+ # participant 'alice', :timeout => '2d'
89
+ #
90
+ # where alice as two days to complete her task (send back the workitem).
91
+ #
92
+ # But it's OK for participant classes registered in the engine to provide
93
+ # their own timeout value. The participant instance simply has to reply to
94
+ # the #rtimeout method and provide a meaningful timeout value (like a
95
+ # number of seconds, or a string like "2d" or "1M2w".
96
+ #
97
+ # Note however, that the process definition timeout (if any) will take
98
+ # precedence over the participant specified one.
99
+ #
100
+ #
101
+ # == asynchronous
102
+ #
103
+ # The expression will make sure to dispatch to the participant in an
104
+ # asynchronous way. This means that the dispatch will occur in a dedicated
105
+ # thread.
106
+ #
107
+ # Since the dispatching to the participant could take a long time and block
108
+ # the engine for too long, this 'do thread' policy is used by default.
109
+ #
110
+ # If the participant itself replies to the method #do_not_thread and replies
111
+ # positively to it, a new thread (or a next_tick) won't get used. This is
112
+ # practical for tiny participants that don't do IO and reply immediately
113
+ # (after a few operations). By default, BlockParticipant instances do not
114
+ # thread.
115
+ #
116
+ class ParticipantExpression < FlowExpression
117
+
118
+ names :participant
119
+
120
+ # Should yield true when the dispatch was successful.
121
+ #
122
+ h_reader :dispatched
123
+
124
+ h_reader :participant
125
+
126
+ def apply
127
+
128
+ #
129
+ # determine participant
130
+
131
+ h.participant_name = (attribute(:ref) || attribute_text).to_s
132
+
133
+ raise ArgumentError.new(
134
+ "no participant name specified"
135
+ ) if h.participant_name == ''
136
+
137
+ h.participant ||=
138
+ @context.plist.lookup_info(h.participant_name, h.applied_workitem)
139
+
140
+ raise(ArgumentError.new(
141
+ "no participant named #{h.participant_name.inspect}")
142
+ ) if h.participant.nil?
143
+
144
+ #
145
+ # dispatch to participant
146
+
147
+ h.applied_workitem['participant_name'] = h.participant_name
148
+
149
+ h.applied_workitem['fields']['params'] = compile_atts
150
+ h.applied_workitem['fields'].delete('t')
151
+
152
+ schedule_timeout(h.participant)
153
+
154
+ persist_or_raise
155
+
156
+ @context.storage.put_msg(
157
+ 'dispatch',
158
+ 'fei' => h.fei,
159
+ 'participant_name' => h.participant_name,
160
+ 'participant' => h.participant,
161
+ 'workitem' => h.applied_workitem)
162
+ end
163
+
164
+ def cancel(flavour)
165
+
166
+ return reply_to_parent(h.applied_workitem) unless h.participant_name
167
+ # no participant, reply immediately
168
+
169
+ do_persist || return
170
+ #
171
+ # if do_persist returns false, it means we're operating on stale
172
+ # data and cannot continue
173
+
174
+ @context.storage.put_msg(
175
+ 'dispatch_cancel',
176
+ 'fei' => h.fei,
177
+ 'participant_name' => h.participant_name,
178
+ 'participant' => h.participant,
179
+ 'flavour' => flavour,
180
+ 'workitem' => h.applied_workitem)
181
+ end
182
+
183
+ def reply(workitem)
184
+
185
+ pinfo =
186
+ h.participant ||
187
+ @context.plist.lookup_info(h.participant_name, workitem)
188
+
189
+ pa = @context.plist.instantiate(pinfo, :if_respond_to? => :on_reply)
190
+
191
+ pa.on_reply(Ruote::Workitem.new(workitem)) if pa
192
+
193
+ super(workitem)
194
+ end
195
+
196
+ def reply_to_parent(workitem)
197
+
198
+ workitem['fields'].delete('params')
199
+ workitem['fields'].delete('dispatched_at')
200
+ super(workitem)
201
+ end
202
+
203
+ protected
204
+
205
+ # Once the dispatching work (done by the dispatch pool) is done, a
206
+ # 'dispatched' msg is sent, we have to flag the participant expression
207
+ # as 'dispatched' => true
208
+ #
209
+ # See http://groups.google.com/group/openwferu-users/browse_thread/thread/ff29f26d6b5fd135
210
+ # for the motivation.
211
+ #
212
+ def do_dispatched(msg)
213
+
214
+ h.dispatched = true
215
+ do_persist
216
+ # let's not care if it fails...
217
+ end
218
+
219
+ # Overriden with an empty behaviour. The work is now done a bit later
220
+ # via the #schedule_timeout method.
221
+ #
222
+ def consider_timeout
223
+ end
224
+
225
+ # Determines and schedules timeout if any.
226
+ #
227
+ # Note that process definition timeout has priority over participant
228
+ # specified timeout.
229
+ #
230
+ def schedule_timeout(p_info)
231
+
232
+ timeout = attribute(:timeout)
233
+
234
+ unless timeout
235
+
236
+ pa = @context.plist.instantiate(p_info, :if_respond_to? => :rtimeout)
237
+
238
+ timeout = (pa.method(:rtimeout).arity == 0 ?
239
+ pa.rtimeout :
240
+ pa.rtimeout(Ruote::Workitem.new(h.applied_workitem))
241
+ ) if pa
242
+ end
243
+
244
+ do_schedule_timeout(timeout)
245
+ end
246
+
247
+ def do_pause(msg)
248
+
249
+ return if h.state != nil
250
+
251
+ h['state'] = 'paused'
252
+ h['breakpoint'] = true if msg['breakpoint']
253
+
254
+ do_persist || return
255
+
256
+ @context.storage.put_msg(
257
+ 'dispatch_pause',
258
+ 'fei' => h.fei,
259
+ 'participant_name' => h.participant_name,
260
+ 'participant' => h.participant
261
+ ) unless msg['breakpoint']
262
+ end
263
+
264
+ def do_resume(msg)
265
+
266
+ return if h.state != 'paused'
267
+
268
+ h['state'] = nil
269
+ replies = h.delete('paused_replies') || []
270
+
271
+ do_persist || return
272
+
273
+ if replies.empty?
274
+ @context.storage.put_msg(
275
+ 'dispatch_resume',
276
+ 'fei' => h.fei,
277
+ 'participant_name' => h.participant_name,
278
+ 'participant' => h.participant
279
+ ) unless h['breakpoint']
280
+ else
281
+ replies.each { |m| @context.storage.put_msg(m.delete('action'), m) }
282
+ # trigger replies
283
+ end
284
+ end
285
+ end
286
+ end
287
+