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,189 @@
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 Singapore.
23
+ #++
24
+
25
+ require 'ruote/util/subprocess'
26
+ require 'ruote/part/local_participant'
27
+
28
+
29
+ module Ruote
30
+
31
+ #
32
+ # A participant for pushing the execution of [segments of] processes to
33
+ # other engines.
34
+ #
35
+ # It works by giving the participant the connection information to the storage
36
+ # of the other engine.
37
+ #
38
+ # For instance :
39
+ #
40
+ # engine0 =
41
+ # Ruote::Engine.new(
42
+ # Ruote::Worker.new(
43
+ # Ruote::FsStorage.new('work0', 'engine_id' => 'engine0')))
44
+ # engine1 =
45
+ # Ruote::Engine.new(
46
+ # Ruote::Worker.new(
47
+ # Ruote::FsStorage.new('work1', 'engine_id' => 'engine1')))
48
+ #
49
+ # engine0.register_participant('engine1',
50
+ # Ruote::EngineParticipant,
51
+ # 'storage_class' => Ruote::FsStorage,
52
+ # 'storage_path' => 'ruote/storage/fs_storage',
53
+ # 'storage_args' => 'work1')
54
+ # engine1.register_participant('engine0',
55
+ # Ruote::EngineParticipant,
56
+ # 'storage_class' => Ruote::FsStorage,
57
+ # 'storage_path' => 'ruote/storage/fs_storage',
58
+ # 'storage_args' => 'work0')
59
+ #
60
+ # In this example, two engines are created (note that their 'engine_id' is
61
+ # explicitely set (else it would default to 'engine')). Each engine is then
62
+ # registered as participant in the other engine. The registration parameters
63
+ # detail the class and the arguments to the storage of the target engine.
64
+ #
65
+ # This example is a bit dry / flat. A real world example would perhaps detail
66
+ # a 'master' engine connected to 'departmental' engines, something more
67
+ # hierarchical.
68
+ #
69
+ # The example also binds reciprocally engines. If the delegated processes
70
+ # are always 'forgotten', one could imagine not binding the source engine
71
+ # as a participant in the target engine (not need to answer back).
72
+ #
73
+ # There are then two variants for calling a subprocess
74
+ #
75
+ # subprocess :ref => 'subprocess_name', :engine => 'engine1'
76
+ # # or
77
+ # participant :ref => 'engine1', :pdef => 'subprocess_name'
78
+ #
79
+ # It's OK to go for the shorter versions :
80
+ #
81
+ # subprocess_name :engine => 'engine1'
82
+ # # or
83
+ # participant 'engine1', :pdef => 'subprocess_name'
84
+ # engine1 :pdef => 'subprocess_name'
85
+ #
86
+ # The subprocess is defined in the current process, or it's given via its
87
+ # URL. The third variant is a subprocess bound as an engine variable.
88
+ #
89
+ # engine.variables['variant_3'] = Ruote.process_definition do
90
+ # participant 'hello_world_3'
91
+ # end
92
+ #
93
+ # pdef = Ruote.process_definition do
94
+ # sequence do
95
+ # engine1 :pdef => 'variant_1'
96
+ # engine1 :pdef => 'http://pdefs.example.com/variant_2.rb'
97
+ # engine1 :pdef => 'variant_3'
98
+ # end
99
+ # define 'variant_1' do
100
+ # participant 'hello_world_1'
101
+ # end
102
+ # end
103
+ #
104
+ class EngineParticipant
105
+
106
+ include LocalParticipant
107
+
108
+ def initialize(opts)
109
+
110
+ if pa = opts['storage_path']
111
+ require pa
112
+ end
113
+
114
+ kl = opts['storage_class']
115
+
116
+ raise(ArgumentError.new("missing 'storage_class' parameter")) unless kl
117
+
118
+ args = opts['storage_args']
119
+ args = args.is_a?(Hash) ? [ args ] : Array(args)
120
+ args << {} unless args.last.is_a?(Hash)
121
+ args.last['preserve_configuration'] = true
122
+
123
+ @storage = Ruote.constantize(kl).new(*args)
124
+ end
125
+
126
+ def consume(workitem)
127
+
128
+ wi = workitem.to_h
129
+ fexp = Ruote::Exp::FlowExpression.fetch(@context, wi['fei'])
130
+ params = wi['fields'].delete('params')
131
+
132
+ forget = (fexp.attribute(:forget).to_s == 'true')
133
+
134
+ @storage.put_msg(
135
+ 'launch',
136
+ 'wfid' => wi['fei']['wfid'],
137
+ 'parent_id' => forget ? nil : wi['fei'],
138
+ 'tree' => determine_tree(fexp, params),
139
+ 'workitem' => wi,
140
+ 'variables' => fexp.compile_variables)
141
+
142
+ fexp.unpersist if forget
143
+ #
144
+ # special behaviour here in case of :forget => true :
145
+ # parent_id of remote expression is set to nil and local expression
146
+ # is unpersisted immediately
147
+ end
148
+
149
+ def cancel(fei, flavour)
150
+
151
+ exps = @storage.get_many('expressions', /^0![^!]+!#{fei.wfid}$/)
152
+
153
+ return true if exps.size < 1
154
+ # participant expression will reply to its parent
155
+
156
+ @storage.put_msg(
157
+ 'cancel',
158
+ 'fei' => exps.first['fei'],
159
+ 'flavour' => flavour)
160
+
161
+ false
162
+ # participant expression will NOT reply to its parent
163
+ end
164
+
165
+ def reply(fei, workitem)
166
+
167
+ @storage.put_msg(
168
+ 'reply',
169
+ 'fei' => fei,
170
+ 'workitem' => workitem)
171
+ end
172
+
173
+ protected
174
+
175
+ def determine_tree(fexp, params)
176
+
177
+ pdef = params['def'] || params['pdef'] || params['tree']
178
+
179
+ tree = Ruote.lookup_subprocess(fexp, pdef)
180
+
181
+ raise(
182
+ "couldn't find process definition behind '#{pdef}'"
183
+ ) unless tree
184
+
185
+ tree.last
186
+ end
187
+ end
188
+ end
189
+
@@ -0,0 +1,138 @@
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/receiver/base'
26
+
27
+
28
+ module Ruote
29
+
30
+ #
31
+ # Provides methods for 'local' participants.
32
+ #
33
+ # Assumes the class that includes this module has a #context method
34
+ # that points to the worker or engine ruote context.
35
+ #
36
+ # It's "local" because it has access to the ruote storage.
37
+ #
38
+ module LocalParticipant
39
+
40
+ include ReceiverMixin
41
+ # the reply_to_engine method is there
42
+
43
+ attr_accessor :context
44
+
45
+ # Use this method to re_dispatch the workitem.
46
+ #
47
+ # It takes two options :in and :at for "later re_dispatch".
48
+ #
49
+ # Look at the unschedule_re_dispatch method for an example of
50
+ # participant implementation that uses re_dispatch.
51
+ #
52
+ # Without one of those options, the method is a "reject".
53
+ #
54
+ def re_dispatch(workitem, opts={})
55
+
56
+ msg = {
57
+ 'action' => 'dispatch',
58
+ 'fei' => workitem.h.fei,
59
+ 'workitem' => workitem.h,
60
+ 'participant_name' => workitem.participant_name,
61
+ 'rejected' => true
62
+ }
63
+
64
+ if t = opts[:in] || opts[:at]
65
+
66
+ sched_id = @context.storage.put_schedule('at', workitem.h.fei, t, msg)
67
+
68
+ fexp = fetch_flow_expression(workitem)
69
+ fexp.h['re_dispatch_sched_id'] = sched_id
70
+ fexp.try_persist
71
+
72
+ else
73
+
74
+ @context.storage.put_msg('dispatch', msg)
75
+ end
76
+ end
77
+
78
+ # Cancels the scheduled re_dispatch, if any.
79
+ #
80
+ # An example or 'retrying participant' :
81
+ #
82
+ # class RetryParticipant
83
+ # include Ruote::LocalParticipant
84
+ #
85
+ # def initialize(opts)
86
+ # @opts = opts
87
+ # end
88
+ #
89
+ # def consume(workitem)
90
+ # begin
91
+ # do_the_job
92
+ # reply(workitem)
93
+ # rescue
94
+ # re_dispatch(workitem, :in => @opts['delay'] || '1s')
95
+ # end
96
+ # end
97
+ #
98
+ # def cancel(fei, flavour)
99
+ # unschedule_re_dispatch(fei)
100
+ # end
101
+ # end
102
+ #
103
+ # Note how unschedule_re_dispatch is used in the cancel method. Warning,
104
+ # this example could loop forever...
105
+ #
106
+ def unschedule_re_dispatch(fei)
107
+
108
+ fexp = Ruote::Exp::FlowExpression.fetch(
109
+ @context, Ruote::FlowExpressionId.extract_h(fei))
110
+
111
+ if s = fexp.h['re_dispatch_sched_id']
112
+ @context.storage.delete_schedule(s)
113
+ end
114
+ end
115
+
116
+ # This reject method replaces the workitem in the [internal] message queue
117
+ # of the ruote engine (since it's a local participant, it has access to
118
+ # the storage and it's thus easy).
119
+ # The idea is that another worker will pick up the workitem and
120
+ # do the participant dispatching.
121
+ #
122
+ # This is an advanced technique. It was requested by people who
123
+ # want to have multiple workers and have only certain worker/participants
124
+ # do the handling.
125
+ # Using reject is not the best method, it's probably better to implement
126
+ # this by re-opening the Ruote::Worker class and changing the
127
+ # cannot_handle(msg) method.
128
+ #
129
+ # reject could be useful anyway, not sure now, but one could imagine
130
+ # scenarii where some participants reject workitems temporarily (while
131
+ # the same participant on another worker would accept it).
132
+ #
133
+ # Well, here it is, use with care.
134
+ #
135
+ alias :reject :re_dispatch
136
+ end
137
+ end
138
+
@@ -0,0 +1,60 @@
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/part/local_participant'
27
+
28
+
29
+ module Ruote
30
+
31
+ #
32
+ # A participant that simply replies immediately to the engine.
33
+ #
34
+ # For testing purposes, but could be useful when used in conjunction with
35
+ # 'listen'.
36
+ #
37
+ class NoOpParticipant
38
+
39
+ include LocalParticipant
40
+
41
+ def initialize(opts=nil)
42
+
43
+ @items = {}
44
+ end
45
+
46
+ #
47
+ # No operation : simply replies immediately to the engine.
48
+ #
49
+ def consume(workitem)
50
+
51
+ reply_to_engine(workitem)
52
+ end
53
+
54
+ def cancel(fei, flavour)
55
+
56
+ # nothing to do
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,54 @@
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/part/local_participant'
26
+
27
+
28
+ module Ruote
29
+
30
+ #
31
+ # A /dev/null participant, simply discards the workitems it receives,
32
+ # without doing anything.
33
+ #
34
+ # For testing purposes only.
35
+ #
36
+ class NullParticipant
37
+
38
+ include LocalParticipant
39
+
40
+ def initialize(opts=nil)
41
+ end
42
+
43
+ # Does nothing, discards the workitem it receives.
44
+ #
45
+ def consume(workitem)
46
+ end
47
+
48
+ # Does nothing.
49
+ #
50
+ def cancel(fei, flavour)
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,169 @@
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 'open-uri'
27
+
28
+ require 'ruote/part/local_participant'
29
+
30
+
31
+ module Ruote
32
+
33
+ #
34
+ # This participant was born out of a suggestion from Jan Topiński in
35
+ # http://groups.google.com/group/openwferu-users/browse_thread/thread/be20a5d861556fd8
36
+ #
37
+ # This participant is a gateway to code placed in a directory.
38
+ #
39
+ # engine.register do
40
+ # toto, Ruote::RevParticipant, :dir => 'participants/toto/'
41
+ # end
42
+ #
43
+ # Then in the participants/toto/ dir :
44
+ #
45
+ # /my_workflow__0.1__toto_0.6.rb
46
+ # # participant toto, workflow 'my_workflow' with revision '0.1'
47
+ # /my_workflow__toto.rb
48
+ # # participant toto, workflow 'my_workflow' any revision
49
+ # /toto_0.6.rb
50
+ # # participant toto with rev '0.6', any workflow
51
+ # /toto.rb
52
+ # # participant toto, any rev, any workflow
53
+ # # ...
54
+ #
55
+ # The scheme goes like :
56
+ #
57
+ # /wf-name__wf-revision__participant-name__p-revision.rb
58
+ #
59
+ # The files themselves look like :
60
+ #
61
+ # def consume(workitem)
62
+ # workitem.fields['kilroy'] = 'was here'
63
+ # reply_to_engine(workitem)
64
+ # end
65
+ #
66
+ # The file directly contains the classical participant methods defined at the
67
+ # top level. #cancel, #accept?, #on_reply and of course #consume are OK.
68
+ #
69
+ #
70
+ # Maybe, look at the tests for more clues :
71
+ #
72
+ # https://github.com/jmettraux/ruote/blob/master/test/functional/ft_57_rev_participant.rb
73
+ #
74
+ # *Note* : It's probably not the best participant in a distributed context, it
75
+ # grabs the code to execute from a directory. If you use it in a distributed
76
+ # context, you'll have to make sure to synchronize the directory to each host
77
+ # running a worker.
78
+ #
79
+ # *Warning* : this participant trusts the code it deals with, there is no
80
+ # security check.
81
+ #
82
+ class RevParticipant
83
+
84
+ include LocalParticipant
85
+
86
+ # TODO : how to deal with >= and ~> ?
87
+
88
+ def initialize(opts=nil)
89
+
90
+ @dir = opts['dir']
91
+
92
+ raise ArgumentError.new(
93
+ "missing option :dir for #{self.class}"
94
+ ) unless @dir
95
+ end
96
+
97
+ def consume(workitem)
98
+
99
+ lookup_code(workitem).consume(workitem)
100
+ end
101
+
102
+ def cancel(fei, flavour)
103
+
104
+ lookup_code(fei).cancel(fei, flavour)
105
+ end
106
+
107
+ #--
108
+ #def accept?(workitem)
109
+ # part = lookup_code(workitem)
110
+ # part.respond_to?(:accept?) ? part.accept?(workitem) : true
111
+ #end
112
+ #
113
+ # Can't do this at this level, since it isn't the rev_participant's
114
+ # own accept?, it has to go in lookup_code
115
+ #++
116
+
117
+ def on_reply(workitem)
118
+
119
+ part = lookup_code(workitem)
120
+ part.on_reply(workitem) if part.respond_to?(:on_reply)
121
+ end
122
+
123
+ def rtimeout(workitem)
124
+
125
+ part = lookup_code(workitem)
126
+
127
+ part.respond_to?(:rtimeout) ? part.rtimeout(workitem) : nil
128
+ end
129
+
130
+ protected
131
+
132
+ # Maybe "lookup_real_participant_code" would be a better name...
133
+ #
134
+ def lookup_code(wi_or_fei)
135
+
136
+ wi = wi_or_fei.is_a?(Ruote::Workitem) ? wi_or_fei : workitem(wi_or_fei)
137
+
138
+ rev = wi.params['revision'] || wi.params['rev']
139
+
140
+ [
141
+ [ wi.wf_name, wi.wf_revision, wi.participant_name, rev ],
142
+ [ wi.wf_name, wi.wf_revision, wi.participant_name ],
143
+ [ wi.wf_name, '', wi.participant_name ],
144
+ [ wi.participant_name, rev ],
145
+ [ wi.participant_name ],
146
+ ].each do |fname|
147
+
148
+ fname = File.join(@dir, "#{fname.compact.join('__')}.rb")
149
+ next unless File.exist?(fname)
150
+
151
+ cpart = Class.new
152
+ cpart.send(:include, Ruote::LocalParticipant)
153
+ cpart.module_eval(File.read(fname))
154
+ part = cpart.new
155
+ part.context = @context
156
+
157
+ next if part.respond_to?(:accept?) and (not part.accept?(wi))
158
+
159
+ return part
160
+ end
161
+
162
+ raise ArgumentError.new(
163
+ "couldn't find code for participant #{wi.participant_name} " +
164
+ "in dir #{@dir}"
165
+ )
166
+ end
167
+ end
168
+ end
169
+