ruote 2.1.11 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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)