ruote 2.1.11 → 2.2.0

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 (217) hide show
  1. data/CHANGELOG.txt +60 -0
  2. data/CREDITS.txt +22 -4
  3. data/LICENSE.txt +1 -1
  4. data/README.rdoc +6 -7
  5. data/Rakefile +58 -59
  6. data/TODO.txt +137 -65
  7. data/couch_url.txt +1 -0
  8. data/jruby_issue.txt +32 -0
  9. data/lib/ruote.rb +1 -1
  10. data/lib/ruote/context.rb +12 -10
  11. data/lib/ruote/engine.rb +280 -145
  12. data/lib/ruote/engine/process_error.rb +5 -5
  13. data/lib/ruote/engine/process_status.rb +47 -28
  14. data/lib/ruote/exp/command.rb +7 -10
  15. data/lib/ruote/exp/commanded.rb +2 -2
  16. data/lib/ruote/exp/condition.rb +130 -43
  17. data/lib/ruote/exp/fe_add_branches.rb +2 -2
  18. data/lib/ruote/exp/fe_apply.rb +1 -1
  19. data/lib/ruote/exp/fe_cancel_process.rb +3 -3
  20. data/lib/ruote/exp/fe_command.rb +3 -3
  21. data/lib/ruote/exp/fe_concurrence.rb +4 -4
  22. data/lib/ruote/exp/fe_concurrent_iterator.rb +17 -5
  23. data/lib/ruote/exp/fe_cron.rb +3 -3
  24. data/lib/ruote/exp/fe_cursor.rb +5 -5
  25. data/lib/ruote/exp/fe_define.rb +3 -3
  26. data/lib/ruote/exp/fe_echo.rb +3 -3
  27. data/lib/ruote/exp/fe_equals.rb +2 -2
  28. data/lib/ruote/exp/fe_error.rb +2 -2
  29. data/lib/ruote/exp/fe_filter.rb +519 -0
  30. data/lib/ruote/exp/fe_forget.rb +9 -2
  31. data/lib/ruote/exp/fe_given.rb +154 -0
  32. data/lib/ruote/exp/fe_if.rb +16 -13
  33. data/lib/ruote/exp/fe_inc.rb +3 -3
  34. data/lib/ruote/exp/fe_iterator.rb +4 -4
  35. data/lib/ruote/exp/fe_let.rb +75 -0
  36. data/lib/ruote/exp/fe_listen.rb +68 -12
  37. data/lib/ruote/exp/fe_lose.rb +110 -0
  38. data/lib/ruote/exp/fe_noop.rb +1 -1
  39. data/lib/ruote/exp/{fe_when.rb → fe_once.rb} +25 -21
  40. data/lib/ruote/exp/fe_participant.rb +14 -17
  41. data/lib/ruote/exp/fe_redo.rb +10 -6
  42. data/lib/ruote/exp/fe_ref.rb +1 -1
  43. data/lib/ruote/exp/fe_registerp.rb +112 -0
  44. data/lib/ruote/exp/fe_reserve.rb +3 -3
  45. data/lib/ruote/exp/fe_restore.rb +2 -2
  46. data/lib/ruote/exp/fe_save.rb +2 -2
  47. data/lib/ruote/exp/fe_sequence.rb +3 -4
  48. data/lib/ruote/exp/fe_set.rb +16 -7
  49. data/lib/ruote/exp/fe_subprocess.rb +23 -1
  50. data/lib/ruote/exp/fe_that.rb +92 -0
  51. data/lib/ruote/exp/fe_undo.rb +3 -3
  52. data/lib/ruote/exp/fe_unregisterp.rb +71 -0
  53. data/lib/ruote/exp/fe_wait.rb +2 -2
  54. data/lib/ruote/exp/flowexpression.rb +153 -78
  55. data/lib/ruote/exp/iterator.rb +2 -2
  56. data/lib/ruote/exp/merge.rb +2 -2
  57. data/lib/ruote/exp/ro_attributes.rb +14 -12
  58. data/lib/ruote/exp/ro_filters.rb +136 -0
  59. data/lib/ruote/exp/ro_persist.rb +51 -35
  60. data/lib/ruote/exp/ro_variables.rb +18 -27
  61. data/lib/ruote/fei.rb +73 -33
  62. data/lib/ruote/id/mnemo_wfid_generator.rb +1 -1
  63. data/lib/ruote/id/wfid_generator.rb +11 -4
  64. data/lib/ruote/log/default_history.rb +122 -0
  65. data/lib/ruote/log/pretty.rb +36 -8
  66. data/lib/ruote/log/storage_history.rb +37 -5
  67. data/lib/ruote/log/test_logger.rb +26 -24
  68. data/lib/ruote/log/wait_logger.rb +5 -3
  69. data/lib/ruote/part/block_participant.rb +22 -11
  70. data/lib/ruote/part/engine_participant.rb +6 -7
  71. data/lib/ruote/part/local_participant.rb +6 -12
  72. data/lib/ruote/part/no_op_participant.rb +4 -4
  73. data/lib/ruote/part/null_participant.rb +4 -4
  74. data/lib/ruote/part/smtp_participant.rb +4 -4
  75. data/lib/ruote/part/storage_participant.rb +40 -20
  76. data/lib/ruote/part/template.rb +4 -4
  77. data/lib/ruote/participant.rb +0 -1
  78. data/lib/ruote/{parser.rb → reader.rb} +30 -25
  79. data/lib/ruote/{parser → reader}/ruby_dsl.rb +28 -11
  80. data/lib/ruote/{parser → reader}/xml.rb +6 -5
  81. data/lib/ruote/receiver/base.rb +35 -13
  82. data/lib/ruote/storage/base.rb +20 -18
  83. data/lib/ruote/storage/composite_storage.rb +10 -10
  84. data/lib/ruote/storage/fs_storage.rb +17 -10
  85. data/lib/ruote/storage/hash_storage.rb +29 -18
  86. data/lib/ruote/svc/dispatch_pool.rb +41 -14
  87. data/lib/ruote/svc/dollar_sub.rb +50 -17
  88. data/lib/ruote/svc/error_handler.rb +19 -11
  89. data/lib/ruote/svc/expression_map.rb +4 -4
  90. data/lib/ruote/svc/participant_list.rb +105 -100
  91. data/lib/ruote/svc/tracker.rb +58 -18
  92. data/lib/ruote/svc/treechecker.rb +51 -24
  93. data/lib/ruote/tree_dot.rb +4 -4
  94. data/lib/ruote/util/filter.rb +440 -0
  95. data/lib/ruote/util/hashdot.rb +4 -4
  96. data/lib/ruote/util/look.rb +2 -6
  97. data/lib/ruote/util/lookup.rb +9 -7
  98. data/lib/ruote/util/misc.rb +40 -8
  99. data/lib/ruote/util/ometa.rb +1 -1
  100. data/lib/ruote/util/serializer.rb +4 -4
  101. data/lib/ruote/util/subprocess.rb +29 -9
  102. data/lib/ruote/util/time.rb +4 -4
  103. data/lib/ruote/util/tree.rb +3 -3
  104. data/lib/ruote/version.rb +2 -2
  105. data/lib/ruote/worker.rb +55 -32
  106. data/lib/ruote/workitem.rb +64 -11
  107. data/ruote.gemspec +31 -302
  108. data/test/bm/launch_bench.rb +37 -0
  109. data/test/functional/base.rb +60 -18
  110. data/test/functional/concurrent_base.rb +2 -2
  111. data/test/functional/ct_0_concurrence.rb +1 -1
  112. data/test/functional/ct_1_iterator.rb +1 -1
  113. data/test/functional/ct_2_cancel.rb +1 -1
  114. data/test/functional/eft_0_process_definition.rb +2 -2
  115. data/test/functional/eft_10_cancel_process.rb +1 -1
  116. data/test/functional/eft_11_wait.rb +19 -11
  117. data/test/functional/eft_12_listen.rb +79 -13
  118. data/test/functional/eft_13_iterator.rb +13 -10
  119. data/test/functional/eft_14_cursor.rb +98 -9
  120. data/test/functional/eft_15_loop.rb +6 -4
  121. data/test/functional/eft_16_if.rb +12 -0
  122. data/test/functional/eft_18_concurrent_iterator.rb +31 -32
  123. data/test/functional/eft_19_reserve.rb +4 -4
  124. data/test/functional/eft_1_echo.rb +9 -0
  125. data/test/functional/eft_20_save.rb +4 -4
  126. data/test/functional/{eft_28_when.rb → eft_28_once.rb} +33 -7
  127. data/test/functional/eft_30_ref.rb +17 -2
  128. data/test/functional/eft_31_registerp.rb +130 -0
  129. data/test/functional/eft_32_lose.rb +93 -0
  130. data/test/functional/eft_33_let.rb +31 -0
  131. data/test/functional/eft_34_given.rb +123 -0
  132. data/test/functional/eft_35_filter.rb +269 -0
  133. data/test/functional/eft_3_participant.rb +4 -6
  134. data/test/functional/eft_4_set.rb +16 -2
  135. data/test/functional/eft_5_subprocess.rb +2 -4
  136. data/test/functional/eft_6_concurrence.rb +29 -29
  137. data/test/functional/eft_8_undo.rb +39 -3
  138. data/test/functional/eft_9_redo.rb +94 -2
  139. data/test/functional/ft_10_dollar.rb +81 -2
  140. data/test/functional/ft_11_recursion.rb +13 -17
  141. data/test/functional/ft_12_launchitem.rb +9 -5
  142. data/test/functional/ft_13_variables.rb +7 -9
  143. data/test/functional/ft_14_re_apply.rb +6 -9
  144. data/test/functional/ft_15_timeout.rb +18 -18
  145. data/test/functional/ft_16_participant_params.rb +1 -3
  146. data/test/functional/ft_17_conditional.rb +25 -2
  147. data/test/functional/ft_18_kill.rb +65 -12
  148. data/test/functional/ft_1_process_status.rb +147 -71
  149. data/test/functional/ft_20_storage_participant.rb +0 -1
  150. data/test/functional/ft_21_forget.rb +82 -1
  151. data/test/functional/{ft_24_block_participants.rb → ft_24_block_participant.rb} +42 -11
  152. data/test/functional/ft_25_receiver.rb +47 -17
  153. data/test/functional/{ft_26_participant_timeout.rb → ft_26_participant_rtimeout.rb} +56 -19
  154. data/test/functional/ft_29_part_template.rb +6 -5
  155. data/test/functional/ft_2_errors.rb +21 -37
  156. data/test/functional/ft_30_smtp_participant.rb +1 -1
  157. data/test/functional/ft_31_part_blocking.rb +8 -6
  158. data/test/functional/ft_34_cursor_rewind.rb +13 -10
  159. data/test/functional/ft_35_add_service.rb +1 -1
  160. data/test/functional/ft_36_storage_history.rb +24 -1
  161. data/test/functional/ft_37_default_history.rb +109 -0
  162. data/test/functional/ft_38_participant_more.rb +10 -10
  163. data/test/functional/ft_39_wait_for.rb +12 -9
  164. data/test/functional/ft_3_participant_registration.rb +111 -32
  165. data/test/functional/ft_40_wait_logger.rb +2 -1
  166. data/test/functional/ft_41_participants.rb +30 -4
  167. data/test/functional/ft_43_participant_on_reply.rb +6 -23
  168. data/test/functional/ft_45_participant_accept.rb +4 -4
  169. data/test/functional/ft_46_launch_single.rb +36 -2
  170. data/test/functional/ft_47_wfid_generator.rb +54 -0
  171. data/test/functional/ft_48_lose.rb +112 -0
  172. data/test/functional/ft_49_engine_on_error.rb +201 -0
  173. data/test/functional/ft_4_cancel.rb +66 -6
  174. data/test/functional/ft_50_engine_config.rb +22 -0
  175. data/test/functional/ft_51_misc.rb +67 -0
  176. data/test/functional/ft_52_case.rb +134 -0
  177. data/test/functional/ft_53_engine_on_terminate.rb +95 -0
  178. data/test/functional/ft_54_patterns.rb +104 -0
  179. data/test/functional/{ft_37_engine_participant.rb → ft_55_engine_participant.rb} +4 -5
  180. data/test/functional/ft_56_filter_attribute.rb +259 -0
  181. data/test/functional/ft_5_on_error.rb +77 -30
  182. data/test/functional/ft_6_on_cancel.rb +66 -11
  183. data/test/functional/ft_7_tags.rb +94 -5
  184. data/test/functional/ft_8_participant_consumption.rb +36 -5
  185. data/test/functional/ft_9_subprocesses.rb +10 -10
  186. data/test/functional/rt_1_listen.rb +3 -3
  187. data/test/functional/{rt_3_when.rb → rt_3_once.rb} +4 -4
  188. data/test/functional/storage_helper.rb +15 -13
  189. data/test/functional/test.rb +1 -3
  190. data/test/test_helper.rb +0 -8
  191. data/test/unit/storage.rb +154 -10
  192. data/test/unit/{ut_0_ruby_parser.rb → ut_0_ruby_reader.rb} +61 -11
  193. data/test/unit/ut_11_lookup.rb +7 -0
  194. data/test/unit/ut_13_serializer.rb +1 -1
  195. data/test/unit/ut_15_util.rb +23 -0
  196. data/test/unit/{ut_16_parser.rb → ut_16_reader.rb} +11 -13
  197. data/test/unit/ut_1_fei.rb +57 -10
  198. data/test/unit/ut_20_composite_storage.rb +25 -11
  199. data/test/unit/ut_21_participant_list.rb +47 -0
  200. data/test/unit/ut_22_filter.rb +903 -0
  201. data/test/unit/ut_3_wait_logger.rb +2 -6
  202. data/test/unit/ut_6_condition.rb +164 -17
  203. data/test/unit/ut_7_workitem.rb +28 -0
  204. data/test/unit/ut_8_tree_to_dot.rb +1 -1
  205. data/test/unit/{ut_9_xml_parser.rb → ut_9_xml_reader.rb} +5 -5
  206. metadata +108 -84
  207. data/.gitignore +0 -4
  208. data/examples/barley.rb +0 -391
  209. data/examples/flickr_report.rb +0 -107
  210. data/examples/pong.rb +0 -37
  211. data/examples/ruote_quickstart.rb +0 -43
  212. data/examples/web_first_page.rb +0 -68
  213. data/lib/ruote/part/hash_participant.rb +0 -91
  214. data/test/README.rdoc +0 -15
  215. data/test/functional/crunner.sh +0 -19
  216. data/test/pdef.xml +0 -7
  217. data/test/unit/ut_2_wfidgen.rb +0 -21
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -59,14 +59,14 @@ module Ruote::Exp
59
59
  set_mutex
60
60
  end
61
61
 
62
- def reply (workitem)
62
+ def reply(workitem)
63
63
 
64
64
  release_mutex
65
65
 
66
66
  reply_to_parent(workitem)
67
67
  end
68
68
 
69
- def cancel (flavour)
69
+ def cancel(flavour)
70
70
 
71
71
  super
72
72
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -93,7 +93,7 @@ module Ruote::Exp
93
93
  reply_to_parent(h.applied_workitem)
94
94
  end
95
95
 
96
- def reply (workitem)
96
+ def reply(workitem)
97
97
 
98
98
  # empty, never called
99
99
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -70,7 +70,7 @@ module Ruote::Exp
70
70
  reply_to_parent(h.applied_workitem)
71
71
  end
72
72
 
73
- def reply (workitem)
73
+ def reply(workitem)
74
74
 
75
75
  # empty, never called
76
76
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -43,11 +43,10 @@ module Ruote::Exp
43
43
  reply(h.applied_workitem)
44
44
  end
45
45
 
46
- def reply (workitem)
46
+ def reply(workitem)
47
47
 
48
48
  position = workitem['fei'] == h.fei ?
49
- 0 :
50
- Ruote::FlowExpressionId.new(workitem['fei']).child_id + 1
49
+ 0 : Ruote::FlowExpressionId.new(workitem['fei']).child_id + 1
51
50
 
52
51
  if position < tree_children.size
53
52
  apply_child(position, workitem)
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -85,9 +85,18 @@ module Ruote::Exp
85
85
  # set 'f_${v:v}' => 'val2'
86
86
  # end
87
87
  #
88
+ # == set and rset
89
+ #
90
+ # Some gems (Sinatra) for example may provide a set method that hides calls
91
+ # to set when building process definitions (see http://groups.google.com/group/openwferu-users/browse_thread/thread/9ac606e30ada686e)
92
+ #
93
+ # A workaround is to write 'rset' instead of 'set'.
94
+ #
95
+ # rset 'customer' => 'Jeff'
96
+ #
88
97
  class SetExpression < FlowExpression
89
98
 
90
- names :set, :unset
99
+ names :rset, :set, :unset
91
100
 
92
101
  def apply
93
102
 
@@ -117,14 +126,14 @@ module Ruote::Exp
117
126
  reply_to_parent(h.applied_workitem)
118
127
  end
119
128
 
120
- def reply (workitem)
129
+ def reply(workitem)
121
130
 
122
131
  # never called
123
132
  end
124
133
 
125
134
  protected
126
135
 
127
- def set_v (key, value)
136
+ def set_v(key, value)
128
137
 
129
138
  if name == 'unset'
130
139
  unset_variable(key)
@@ -133,7 +142,7 @@ module Ruote::Exp
133
142
  end
134
143
  end
135
144
 
136
- def set_f (key, value)
145
+ def set_f(key, value)
137
146
 
138
147
  if name == 'unset'
139
148
  h.applied_workitem['fields'].delete(key)
@@ -142,9 +151,9 @@ module Ruote::Exp
142
151
  end
143
152
  end
144
153
 
145
- PREFIX_REGEX = /^([^:]+):(.+)$/ unless defined?(PREFIX_REGEX)
154
+ PREFIX_REGEX = /^([^:]+):(.+)$/ #unless defined?(PREFIX_REGEX)
146
155
 
147
- def set_vf (key, value)
156
+ def set_vf(key, value)
148
157
 
149
158
  field = true
150
159
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -147,6 +147,28 @@ module Ruote::Exp
147
147
  # The latter may make process definitions quite readable (but blur the
148
148
  # distinction between expressions, call to participants or to subprocesses).
149
149
  #
150
+ #
151
+ # == subprocess trees bound at engine level
152
+ #
153
+ # It's OK to place a process tree directly in an engine variable :
154
+ #
155
+ # engine.variables['inventory_check'] = Ruote.process_definition do
156
+ # cursor do
157
+ # manager :task => 'hire inventory team'
158
+ # floor_manager :task => 'lead inventory'
159
+ # manager :task => 'check results'
160
+ # rewind :unless => '${inventory_successful}'
161
+ # end
162
+ # end
163
+ #
164
+ # Then, from the main process :
165
+ #
166
+ # sequence do
167
+ # # ...
168
+ # inventory_check
169
+ # # ...
170
+ # end
171
+ #
150
172
  class SubprocessExpression < FlowExpression
151
173
 
152
174
  names :subprocess
@@ -0,0 +1,92 @@
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/exp/fe_sequence'
26
+
27
+
28
+ module Ruote::Exp
29
+
30
+ #
31
+ # The 'that' and the 'of' expressions are used in conjuction with
32
+ # the 'given' expression (GivenExpression).
33
+ #
34
+ # In can be used 'standalone', it thus becomes then merely an 'if'.
35
+ #
36
+ # The children of the that/of are executed if the condition evaluates to
37
+ # true. The children are executed one by one, as if the that/of were
38
+ # a sequence.
39
+ #
40
+ # given '${status}' do
41
+ # that '${location} == CH' do
42
+ # set 'f:bank' => 'UBS'
43
+ # subprocess 'buy_chocolate'
44
+ # end
45
+ # of 'ready' do
46
+ # participant 'saleshead', :msg => 'customer ready'
47
+ # participant 'salesman', :task => 'visiter customer'
48
+ # end
49
+ # of 'over' do
50
+ # participant 'manager', :msg => 'process over'
51
+ # end
52
+ # end
53
+ #
54
+ # (Yes, I know, it's a poor example).
55
+ #
56
+ class ThatExpression < SequenceExpression
57
+
58
+ names :that, :of
59
+
60
+ def reply(workitem)
61
+
62
+ if workitem['fei'] == h.fei # apply --> reply
63
+
64
+ cond = attribute(:t) || attribute(:test) || attribute_text
65
+
66
+ if name == 'of'
67
+ comparator = cond.match(/^\s*\/.*\/\s*$/) ? '=~' : '=='
68
+ cond = "#{workitem['fields']['__given__']} #{comparator} #{cond}"
69
+ end
70
+
71
+ h.result = Condition.true?(cond)
72
+
73
+ if h.result
74
+ apply_child(0, workitem)
75
+ else
76
+ reply_to_parent(workitem)
77
+ end
78
+
79
+ else # reply from child
80
+
81
+ super
82
+ end
83
+ end
84
+
85
+ def reply_to_parent(workitem)
86
+
87
+ workitem['fields']['__result__'] = h.result
88
+ super
89
+ end
90
+ end
91
+ end
92
+
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -53,12 +53,12 @@ module Ruote::Exp
53
53
  ref = attribute(:ref) || attribute_text
54
54
  tag = ref ? lookup_variable(ref) : nil
55
55
 
56
- @context.storage.put_msg('cancel', 'fei' => tag)
56
+ @context.storage.put_msg('cancel', 'fei' => tag) if Ruote.is_a_fei?(tag)
57
57
 
58
58
  reply_to_parent(h.applied_workitem)
59
59
  end
60
60
 
61
- def reply (workitem)
61
+ def reply(workitem)
62
62
 
63
63
  # never called
64
64
  end
@@ -0,0 +1,71 @@
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/exp/fe_registerp'
26
+
27
+
28
+ module Ruote::Exp
29
+
30
+ #
31
+ # (Since ruote 2.1.12)
32
+ #
33
+ # Unregisters a participant.
34
+ #
35
+ # Ruote.process_definition do
36
+ # unregisterp 'alfred'
37
+ # unregisterp :name => 'bob'
38
+ # end
39
+ #
40
+ # Shows the same behaviour as
41
+ #
42
+ # engine.unregister_participant 'alfred'
43
+ # engine.unregister_participant 'bob'
44
+ #
45
+ # The expression 'registerp' can be used to register participants from
46
+ # a process definition.
47
+ #
48
+ class UnregisterpExpression < RegisterpExpression
49
+
50
+ names :unregisterp
51
+
52
+ def apply
53
+
54
+ registerp_allowed?
55
+
56
+ name = attribute(:name) || attribute_text
57
+
58
+ result = begin
59
+ context.engine.unregister_participant(name)
60
+ true
61
+ rescue
62
+ false
63
+ end
64
+
65
+ h.applied_workitem['fields']['__result__'] = result
66
+
67
+ reply_to_parent(h.applied_workitem)
68
+ end
69
+ end
70
+ end
71
+
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -85,7 +85,7 @@ module Ruote::Exp
85
85
  #end
86
86
  #++
87
87
 
88
- def cancel (flavour)
88
+ def cancel(flavour)
89
89
 
90
90
  @context.storage.delete_schedule(h.schedule_id)
91
91
  reply_to_parent(h.applied_workitem)
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -60,6 +60,7 @@ module Ruote::Exp
60
60
  require 'ruote/exp/ro_persist'
61
61
  require 'ruote/exp/ro_attributes'
62
62
  require 'ruote/exp/ro_variables'
63
+ require 'ruote/exp/ro_filters'
63
64
 
64
65
  COMMON_ATT_KEYS = %w[
65
66
  if unless forget timeout on_error on_cancel on_timeout ]
@@ -79,11 +80,12 @@ module Ruote::Exp
79
80
  h_reader :on_cancel
80
81
  h_reader :on_timeout
81
82
 
82
- def initialize (context, h)
83
+ def initialize(context, h)
83
84
 
84
85
  @context = context
85
86
 
86
87
  @msg = nil
88
+ # contains generally the msg the expression got instantiated for
87
89
 
88
90
  self.h = h
89
91
 
@@ -99,22 +101,33 @@ module Ruote::Exp
99
101
  h.on_timeout ||= attribute(:on_timeout)
100
102
  end
101
103
 
102
- def h= (hash)
104
+ def h=(hash)
103
105
  @h = hash
104
106
  class << h
105
107
  include Ruote::HashDot
106
108
  end
107
109
  end
108
110
 
111
+ # Returns the Ruote::FlowExpressionId for this expression.
112
+ #
109
113
  def fei
114
+
110
115
  Ruote::FlowExpressionId.new(h.fei)
111
116
  end
112
117
 
118
+ # Returns the Ruote::FlowExpressionIf of the parent expression, or nil
119
+ # if there is no parent expression.
120
+ #
113
121
  def parent_id
122
+
114
123
  h.parent_id ? Ruote::FlowExpressionId.new(h.parent_id) : nil
115
124
  end
116
125
 
126
+ # Fetches the parent expression, or returns nil if there is no parent
127
+ # expression.
128
+ #
117
129
  def parent
130
+
118
131
  Ruote::Exp::FlowExpression.fetch(@context, h.parent_id)
119
132
  end
120
133
 
@@ -128,7 +141,7 @@ module Ruote::Exp
128
141
 
129
142
  # Instantiates expression back from hash.
130
143
  #
131
- def self.from_h (context, h)
144
+ def self.from_h(context, h)
132
145
 
133
146
  exp_class = context.expmap.expression_class(h['name'])
134
147
 
@@ -137,7 +150,7 @@ module Ruote::Exp
137
150
 
138
151
  # Fetches an expression from the storage and readies it for service.
139
152
  #
140
- def self.fetch (context, fei)
153
+ def self.fetch(context, fei)
141
154
 
142
155
  return nil if fei.nil?
143
156
 
@@ -152,7 +165,7 @@ module Ruote::Exp
152
165
 
153
166
  # Keeping track of names and aliases for the expression
154
167
  #
155
- def self.names (*exp_names)
168
+ def self.names(*exp_names)
156
169
 
157
170
  exp_names = exp_names.collect { |n| n.to_s }
158
171
  meta_def(:expression_names) { exp_names }
@@ -162,11 +175,15 @@ module Ruote::Exp
162
175
  # apply/reply
163
176
  #++
164
177
 
165
- def self.do_action (context, msg)
178
+ # Called by the worker when it has something to do for a FlowExpression.
179
+ #
180
+ def self.do_action(context, msg)
166
181
 
167
182
  fei = msg['fei']
168
183
  action = msg['action']
169
184
 
185
+ p msg unless fei
186
+
170
187
  if action == 'reply' && fei['engine_id'] != context.engine_id
171
188
  #
172
189
  # the reply has to go to another engine, let's locate the
@@ -199,7 +216,12 @@ module Ruote::Exp
199
216
  fexp.send("do_#{action}", msg) if fexp
200
217
  end
201
218
 
202
- def do_apply
219
+ # Called by the worker when it has just created this FlowExpression and
220
+ # wants to apply it.
221
+ #
222
+ def do_apply(msg)
223
+
224
+ @msg = Ruote.fulldup(msg)
203
225
 
204
226
  if not Condition.apply?(attribute(:if), attribute(:unless))
205
227
 
@@ -208,30 +230,48 @@ module Ruote::Exp
208
230
 
209
231
  if attribute(:forget).to_s == 'true'
210
232
 
211
- i = h.parent_id
233
+ pi = h.parent_id
212
234
  wi = Ruote.fulldup(h.applied_workitem)
213
235
 
214
236
  h.variables = compile_variables
215
237
  h.parent_id = nil
216
238
  h.forgotten = true
217
239
 
218
- @context.storage.put_msg('reply', 'fei' => i, 'workitem' => wi)
240
+ @context.storage.put_msg('reply', 'fei' => pi, 'workitem' => wi) if pi
241
+ # reply to parent immediately (if there is a parent)
242
+
243
+ elsif attribute(:lose).to_s == 'true'
244
+
245
+ h.lost = true
219
246
  end
220
247
 
248
+ filter
249
+
221
250
  consider_tag
222
251
  consider_timeout
223
252
 
224
253
  apply
225
254
  end
226
255
 
227
- def reply_to_parent (workitem, delete=true)
256
+ # FlowExpression call this method when they're done and they want their
257
+ # parent expression to take over (it will end up calling the #reply of
258
+ # the parent expression).
259
+ #
260
+ def reply_to_parent(workitem, delete=true)
261
+
262
+ filter(workitem)
228
263
 
229
264
  if h.tagname
230
265
 
231
266
  unset_variable(h.tagname)
232
267
 
268
+ Ruote::Workitem.remove_tag(workitem, h.tagname)
269
+
233
270
  @context.storage.put_msg(
234
- 'left_tag', 'tag' => h.tagname, 'fei' => h.fei)
271
+ 'left_tag',
272
+ 'tag' => h.tagname,
273
+ 'fei' => h.fei,
274
+ 'workitem' => workitem)
235
275
  end
236
276
 
237
277
  if h.timeout_schedule_id && h.state != 'timing_out'
@@ -243,25 +283,26 @@ module Ruote::Exp
243
283
 
244
284
  trigger('on_error', workitem)
245
285
 
246
- elsif (h.state == 'cancelling') and h.on_cancel
286
+ elsif h.state == 'cancelling' and h.on_cancel
247
287
 
248
288
  trigger('on_cancel', workitem)
249
289
 
250
- elsif (h.state == 'cancelling') and h.on_re_apply
290
+ elsif h.state == 'cancelling' and h.on_re_apply
251
291
 
252
292
  trigger('on_re_apply', workitem)
253
293
 
254
- elsif (h.state == 'timing_out') and h.on_timeout
294
+ elsif h.state == 'timing_out' and h.on_timeout
255
295
 
256
296
  trigger('on_timeout', workitem)
257
297
 
298
+ elsif h.lost and h.state == nil
299
+
300
+ # do not reply, sit here (and wait for cancellation probably)
301
+
258
302
  else # vanilla reply
259
303
 
260
- #unpersist_or_raise if delete
261
- #try_unpersist if delete
262
- if delete
263
- do_unpersist || return
264
- end
304
+ (do_unpersist || return) if delete
305
+ # remove expression from storage
265
306
 
266
307
  if h.parent_id
267
308
 
@@ -281,7 +322,9 @@ module Ruote::Exp
281
322
  end
282
323
  end
283
324
 
284
- def do_reply (msg)
325
+ # Wraps #reply (does the administrative part of the reply work).
326
+ #
327
+ def do_reply(msg)
285
328
 
286
329
  @msg = Ruote.fulldup(msg)
287
330
  # keeping the message, for 'retry' in collision cases
@@ -318,7 +361,7 @@ module Ruote::Exp
318
361
 
319
362
  # A default implementation for all the expressions.
320
363
  #
321
- def reply (workitem)
364
+ def reply(workitem)
322
365
 
323
366
  reply_to_parent(workitem)
324
367
  end
@@ -326,7 +369,9 @@ module Ruote::Exp
326
369
  # The raw handling of messages passed to expressions (the fine handling
327
370
  # is done in the #cancel method).
328
371
  #
329
- def do_cancel (msg)
372
+ def do_cancel(msg)
373
+
374
+ @msg = Ruote.fulldup(msg)
330
375
 
331
376
  flavour = msg['flavour']
332
377
 
@@ -375,7 +420,7 @@ module Ruote::Exp
375
420
  # This default implementation cancels all the [registered] children
376
421
  # of this expression.
377
422
  #
378
- def cancel (flavour)
423
+ def cancel(flavour)
379
424
 
380
425
  return reply_to_parent(h.applied_workitem) if h.children.empty?
381
426
  #
@@ -420,7 +465,13 @@ module Ruote::Exp
420
465
  #end
421
466
  end
422
467
 
423
- def do_fail (msg)
468
+ # Called when handling an on_error, will place itself in a 'failing' state
469
+ # and cancel the children (when the reply from the children comes back,
470
+ # the on_reply will get triggered).
471
+ #
472
+ def do_fail(msg)
473
+
474
+ @msg = Ruote.fulldup(msg)
424
475
 
425
476
  @h['state'] = 'failing'
426
477
  @h['applied_workitem'] = msg['workitem']
@@ -437,15 +488,18 @@ module Ruote::Exp
437
488
  # misc
438
489
  #++
439
490
 
440
- def launch_sub (pos, subtree, opts={})
491
+ # Launches a subprocesses (usually called from the #apply of certain
492
+ # expression implementations.
493
+ #
494
+ def launch_sub(pos, subtree, opts={})
441
495
 
442
- i = h.fei.dup
443
- i['sub_wfid'] = get_next_sub_wfid
444
- i['expid'] = pos
496
+ i = h.fei.merge(
497
+ 'subid' => Ruote.generate_subid(h.fei.inspect),
498
+ 'expid' => pos)
445
499
 
446
500
  #p '=== launch_sub ==='
447
- #p [ :launcher, h.fei['expid'], h.fei['sub_wfid'], h.fei['wfid'] ]
448
- #p [ :launched, i['expid'], i['sub_wfid'], i['wfid'] ]
501
+ #p [ :launcher, h.fei['expid'], h.fei['subid'], h.fei['wfid'] ]
502
+ #p [ :launched, i['expid'], i['subid'], i['wfid'] ]
449
503
 
450
504
  forget = opts[:forget]
451
505
 
@@ -468,7 +522,7 @@ module Ruote::Exp
468
522
  # Returns true if the given fei points to an expression in the parent
469
523
  # chain of this expression.
470
524
  #
471
- def ancestor? (fei)
525
+ def ancestor?(fei)
472
526
 
473
527
  return false unless h.parent_id
474
528
  return true if h.parent_id == fei
@@ -489,14 +543,15 @@ module Ruote::Exp
489
543
  par = parent
490
544
  # :( get_parent would probably be a better name for #parent
491
545
 
492
- unless par
493
- puts "~~"
494
- puts "parent gone for"
495
- p h.fei
496
- p h.parent_id
497
- p tree
498
- puts "~~"
499
- end
546
+ #if par.nil? && ($DEBUG || ARGV.include?('-d'))
547
+ # puts "~~"
548
+ # puts "parent gone for"
549
+ # puts "fei #{Ruote.sid(h.fei)}"
550
+ # puts "tree #{tree.inspect}"
551
+ # puts "replying to #{Ruote.sid(h.parent_id)}"
552
+ # puts "~~"
553
+ #end
554
+ # is sometimes helpful during debug sessions
500
555
 
501
556
  par ? par.lookup_on_error : nil
502
557
 
@@ -508,7 +563,7 @@ module Ruote::Exp
508
563
 
509
564
  # Looks up parent with on_error attribute and triggers it
510
565
  #
511
- def handle_on_error (msg, error)
566
+ def handle_on_error(msg, error)
512
567
 
513
568
  return false if h.state == 'failing'
514
569
 
@@ -524,8 +579,13 @@ module Ruote::Exp
524
579
 
525
580
  workitem = msg['workitem']
526
581
 
527
- workitem['fields']['__error__'] = [
528
- h.fei, Ruote.now_to_utc_s, error.class.to_s, error.message, error.backtrace ]
582
+ workitem['fields']['__error__'] = {
583
+ 'fei' => fei,
584
+ 'at' => Ruote.now_to_utc_s,
585
+ 'class' => error.class.to_s,
586
+ 'message' => error.message,
587
+ 'trace' => error.backtrace
588
+ }
529
589
 
530
590
  @context.storage.put_msg(
531
591
  'fail',
@@ -562,49 +622,43 @@ module Ruote::Exp
562
622
  # seq.updated_tree[2] << [ 'participant', { 'ref' => 'bob' }, [] ]
563
623
  # seq.do_persist
564
624
  #
565
- def update_tree (t=nil)
625
+ def update_tree(t=nil)
566
626
  h.updated_tree = t || Ruote.fulldup(h.original_tree)
567
627
  end
568
628
 
629
+ # Returns the name of this expression, like 'sequence', 'participant',
630
+ # 'cursor', etc...
631
+ #
569
632
  def name
633
+
570
634
  tree[0]
571
635
  end
572
636
 
637
+ # Returns the attributes of this expression (like { 'ref' => 'toto' } or
638
+ # { 'timeout' => '2d' }.
639
+ #
573
640
  def attributes
574
- tree[1]
575
- end
576
641
 
577
- def tree_children
578
- tree[2]
642
+ tree[1]
579
643
  end
580
644
 
581
- # A tiny class-bound counter used when generating subprocesses ids.
582
- #
583
- @@sub_wfid_counter = -1
584
-
585
- # Generates a sub_wfid, without hitting storage.
645
+ # Returns the "AST" view on the children of this expression...
586
646
  #
587
- # There's a better implementation for sure...
588
- #
589
- def get_next_sub_wfid
590
-
591
- i = [
592
- $$, Time.now.to_f.to_s, self.hash.to_s, @h['fei'].inspect
593
- ].join('-').hash
594
-
595
- @@sub_wfid_counter = (@@sub_wfid_counter + 1) % 1000
596
- i = i * 1000 + (@@sub_wfid_counter)
647
+ def tree_children
597
648
 
598
- (i < 0 ? "1#{i * -1}" : "0#{i}").to_s
649
+ tree[2]
599
650
  end
600
651
 
601
652
  protected
602
653
 
603
- def to_dot (opts)
654
+ # Returns a Graphviz dot string representing this expression (and its
655
+ # children).
656
+ #
657
+ def to_dot(opts)
604
658
 
605
659
  i = fei()
606
660
 
607
- label = "#{[ i.wfid, i.sub_wfid, i.expid].join(" ")} #{tree.first}"
661
+ label = "#{[ i.wfid, i.subid, i.expid].join(' ')} #{tree.first}"
608
662
  label += " (#{h.state})" if h.state
609
663
 
610
664
  a = []
@@ -625,9 +679,14 @@ module Ruote::Exp
625
679
  a
626
680
  end
627
681
 
628
- def pre_apply_child (child_index, workitem, forget)
682
+ # Used locally but also by ConcurrenceExpression, when preparing children
683
+ # before they get applied.
684
+ #
685
+ def pre_apply_child(child_index, workitem, forget)
629
686
 
630
- child_fei = h.fei.merge('expid' => "#{h.fei['expid']}_#{child_index}")
687
+ child_fei = h.fei.merge(
688
+ 'expid' => "#{h.fei['expid']}_#{child_index}",
689
+ 'subid' => Ruote.generate_subid(h.fei.inspect))
631
690
 
632
691
  h.children << child_fei unless forget
633
692
 
@@ -643,29 +702,43 @@ module Ruote::Exp
643
702
  msg
644
703
  end
645
704
 
646
- def apply_child (child_index, workitem, forget=false)
705
+ # Used by expressions when, well, applying a child expression of theirs.
706
+ #
707
+ def apply_child(child_index, workitem, forget=false)
647
708
 
648
709
  msg = pre_apply_child(child_index, workitem, forget)
649
710
 
650
711
  persist_or_raise unless forget
712
+ # no need to persist the parent (this) if the child is to be forgotten
651
713
 
652
714
  @context.storage.put_msg('apply', msg)
653
715
  end
654
716
 
655
- def register_child (fei)
717
+ # Some expressions have to keep track of their (instantiated) children,
718
+ # this method does the registration (of the child's fei).
719
+ #
720
+ def register_child(fei)
656
721
 
657
722
  h.children << fei
658
723
  persist_or_raise
659
724
  end
660
725
 
726
+ # Called to check if the expression has a :tag attribute. If yes,
727
+ # will register the tag in a variable (and in the workitem).
728
+ #
661
729
  def consider_tag
662
730
 
663
731
  if h.tagname = attribute(:tag)
664
732
 
665
733
  set_variable(h.tagname, h.fei)
666
734
 
735
+ Ruote::Workitem.add_tag(h.applied_workitem, h.tagname)
736
+
667
737
  @context.storage.put_msg(
668
- 'entered_tag', 'tag' => h.tagname, 'fei' => h.fei)
738
+ 'entered_tag',
739
+ 'tag' => h.tagname,
740
+ 'fei' => h.fei,
741
+ 'workitem' => h.applied_workitem)
669
742
  end
670
743
  end
671
744
 
@@ -679,9 +752,10 @@ module Ruote::Exp
679
752
  # Called by consider_timeout (FlowExpression) and schedule_timeout
680
753
  # (ParticipantExpression).
681
754
  #
682
- def do_schedule_timeout (timeout)
755
+ def do_schedule_timeout(timeout)
756
+
757
+ timeout = timeout.to_s
683
758
 
684
- return unless timeout
685
759
  return if timeout.strip == ''
686
760
 
687
761
  h.timeout_schedule_id = @context.storage.put_schedule(
@@ -695,7 +769,7 @@ module Ruote::Exp
695
769
 
696
770
  # (Called by trigger_on_cancel & co)
697
771
  #
698
- def supplant_with (tree, opts)
772
+ def supplant_with(tree, opts)
699
773
 
700
774
  # at first, nuke self
701
775
 
@@ -724,7 +798,7 @@ module Ruote::Exp
724
798
 
725
799
  # 'on_{error|timeout|cancel|re_apply}' triggering
726
800
  #
727
- def trigger (on, workitem)
801
+ def trigger(on, workitem)
728
802
 
729
803
  hon = h[on]
730
804
 
@@ -732,20 +806,21 @@ module Ruote::Exp
732
806
 
733
807
  if on == 'on_error'
734
808
 
735
- if hon == 'redo'
809
+ if hon == 'redo' or hon == 'retry'
736
810
 
737
811
  t = tree
738
812
 
739
- elsif hon == 'undo'
813
+ elsif hon == 'undo' or hon == 'pass'
740
814
 
741
815
  h.state = 'failed'
742
816
  reply_to_parent(workitem)
817
+
743
818
  return
744
819
  end
745
820
 
746
821
  elsif on == 'on_timeout'
747
822
 
748
- t = tree if hon == 'redo'
823
+ t = tree if hon == 'redo' or hon == 'retry'
749
824
  end
750
825
 
751
826
  supplant_with(t, 'trigger' => on)