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.
- data/CHANGELOG.txt +290 -0
- data/CREDITS.txt +99 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +88 -0
- data/Rakefile +108 -0
- data/TODO.txt +488 -0
- data/lib/ruote.rb +7 -0
- data/lib/ruote/context.rb +194 -0
- data/lib/ruote/engine.rb +1062 -0
- data/lib/ruote/engine/process_error.rb +122 -0
- data/lib/ruote/engine/process_status.rb +448 -0
- data/lib/ruote/exp/command.rb +87 -0
- data/lib/ruote/exp/commanded.rb +69 -0
- data/lib/ruote/exp/condition.rb +227 -0
- data/lib/ruote/exp/fe_add_branches.rb +138 -0
- data/lib/ruote/exp/fe_apply.rb +154 -0
- data/lib/ruote/exp/fe_cancel_process.rb +78 -0
- data/lib/ruote/exp/fe_command.rb +156 -0
- data/lib/ruote/exp/fe_concurrence.rb +321 -0
- data/lib/ruote/exp/fe_concurrent_iterator.rb +219 -0
- data/lib/ruote/exp/fe_cron.rb +141 -0
- data/lib/ruote/exp/fe_cursor.rb +324 -0
- data/lib/ruote/exp/fe_define.rb +112 -0
- data/lib/ruote/exp/fe_echo.rb +60 -0
- data/lib/ruote/exp/fe_equals.rb +115 -0
- data/lib/ruote/exp/fe_error.rb +82 -0
- data/lib/ruote/exp/fe_filter.rb +648 -0
- data/lib/ruote/exp/fe_forget.rb +88 -0
- data/lib/ruote/exp/fe_given.rb +154 -0
- data/lib/ruote/exp/fe_if.rb +127 -0
- data/lib/ruote/exp/fe_inc.rb +205 -0
- data/lib/ruote/exp/fe_iterator.rb +234 -0
- data/lib/ruote/exp/fe_let.rb +75 -0
- data/lib/ruote/exp/fe_listen.rb +304 -0
- data/lib/ruote/exp/fe_lose.rb +110 -0
- data/lib/ruote/exp/fe_noop.rb +45 -0
- data/lib/ruote/exp/fe_once.rb +215 -0
- data/lib/ruote/exp/fe_participant.rb +287 -0
- data/lib/ruote/exp/fe_read.rb +69 -0
- data/lib/ruote/exp/fe_redo.rb +82 -0
- data/lib/ruote/exp/fe_ref.rb +152 -0
- data/lib/ruote/exp/fe_registerp.rb +110 -0
- data/lib/ruote/exp/fe_reserve.rb +126 -0
- data/lib/ruote/exp/fe_restore.rb +102 -0
- data/lib/ruote/exp/fe_save.rb +72 -0
- data/lib/ruote/exp/fe_sequence.rb +59 -0
- data/lib/ruote/exp/fe_set.rb +154 -0
- data/lib/ruote/exp/fe_subprocess.rb +211 -0
- data/lib/ruote/exp/fe_that.rb +92 -0
- data/lib/ruote/exp/fe_undo.rb +67 -0
- data/lib/ruote/exp/fe_unregisterp.rb +69 -0
- data/lib/ruote/exp/fe_wait.rb +95 -0
- data/lib/ruote/exp/flowexpression.rb +886 -0
- data/lib/ruote/exp/iterator.rb +81 -0
- data/lib/ruote/exp/merge.rb +118 -0
- data/lib/ruote/exp/ro_attributes.rb +212 -0
- data/lib/ruote/exp/ro_filters.rb +136 -0
- data/lib/ruote/exp/ro_persist.rb +154 -0
- data/lib/ruote/exp/ro_variables.rb +189 -0
- data/lib/ruote/exp/ro_vf.rb +68 -0
- data/lib/ruote/fei.rb +260 -0
- data/lib/ruote/id/mnemo_wfid_generator.rb +43 -0
- data/lib/ruote/id/wfid_generator.rb +81 -0
- data/lib/ruote/log/default_history.rb +122 -0
- data/lib/ruote/log/pretty.rb +176 -0
- data/lib/ruote/log/storage_history.rb +159 -0
- data/lib/ruote/log/test_logger.rb +208 -0
- data/lib/ruote/log/wait_logger.rb +64 -0
- data/lib/ruote/part/block_participant.rb +137 -0
- data/lib/ruote/part/code_participant.rb +81 -0
- data/lib/ruote/part/engine_participant.rb +189 -0
- data/lib/ruote/part/local_participant.rb +138 -0
- data/lib/ruote/part/no_op_participant.rb +60 -0
- data/lib/ruote/part/null_participant.rb +54 -0
- data/lib/ruote/part/rev_participant.rb +169 -0
- data/lib/ruote/part/smtp_participant.rb +116 -0
- data/lib/ruote/part/storage_participant.rb +392 -0
- data/lib/ruote/part/template.rb +84 -0
- data/lib/ruote/participant.rb +7 -0
- data/lib/ruote/reader.rb +278 -0
- data/lib/ruote/reader/json.rb +49 -0
- data/lib/ruote/reader/radial.rb +290 -0
- data/lib/ruote/reader/ruby_dsl.rb +186 -0
- data/lib/ruote/reader/xml.rb +99 -0
- data/lib/ruote/receiver/base.rb +212 -0
- data/lib/ruote/storage/base.rb +364 -0
- data/lib/ruote/storage/composite_storage.rb +121 -0
- data/lib/ruote/storage/fs_storage.rb +139 -0
- data/lib/ruote/storage/hash_storage.rb +211 -0
- data/lib/ruote/svc/dispatch_pool.rb +158 -0
- data/lib/ruote/svc/dollar_sub.rb +298 -0
- data/lib/ruote/svc/error_handler.rb +138 -0
- data/lib/ruote/svc/expression_map.rb +97 -0
- data/lib/ruote/svc/participant_list.rb +397 -0
- data/lib/ruote/svc/tracker.rb +172 -0
- data/lib/ruote/svc/treechecker.rb +141 -0
- data/lib/ruote/tree_dot.rb +85 -0
- data/lib/ruote/util/filter.rb +525 -0
- data/lib/ruote/util/hashdot.rb +79 -0
- data/lib/ruote/util/look.rb +128 -0
- data/lib/ruote/util/lookup.rb +127 -0
- data/lib/ruote/util/misc.rb +167 -0
- data/lib/ruote/util/ometa.rb +71 -0
- data/lib/ruote/util/serializer.rb +103 -0
- data/lib/ruote/util/subprocess.rb +88 -0
- data/lib/ruote/util/time.rb +100 -0
- data/lib/ruote/util/tree.rb +58 -0
- data/lib/ruote/version.rb +29 -0
- data/lib/ruote/worker.rb +386 -0
- data/lib/ruote/workitem.rb +394 -0
- data/phil.txt +14 -0
- data/ruote.gemspec +44 -0
- data/test/bm/ci.rb +55 -0
- data/test/bm/ici.rb +71 -0
- data/test/bm/juuman.rb +54 -0
- data/test/bm/launch_bench.rb +37 -0
- data/test/bm/load_26c.rb +97 -0
- data/test/bm/mega.rb +64 -0
- data/test/bm/seq_thousand.rb +31 -0
- data/test/bm/t.rb +35 -0
- data/test/functional/base.rb +247 -0
- data/test/functional/concurrent_base.rb +98 -0
- data/test/functional/crunner.rb +31 -0
- data/test/functional/ct_0_concurrence.rb +65 -0
- data/test/functional/ct_1_iterator.rb +67 -0
- data/test/functional/ct_2_cancel.rb +81 -0
- data/test/functional/eft_0_process_definition.rb +65 -0
- data/test/functional/eft_10_cancel_process.rb +46 -0
- data/test/functional/eft_11_wait.rb +109 -0
- data/test/functional/eft_12_listen.rb +500 -0
- data/test/functional/eft_13_iterator.rb +342 -0
- data/test/functional/eft_14_cursor.rb +456 -0
- data/test/functional/eft_15_loop.rb +69 -0
- data/test/functional/eft_16_if.rb +183 -0
- data/test/functional/eft_17_equals.rb +55 -0
- data/test/functional/eft_18_concurrent_iterator.rb +410 -0
- data/test/functional/eft_19_reserve.rb +136 -0
- data/test/functional/eft_1_echo.rb +68 -0
- data/test/functional/eft_20_save.rb +116 -0
- data/test/functional/eft_21_restore.rb +61 -0
- data/test/functional/eft_22_noop.rb +28 -0
- data/test/functional/eft_23_apply.rb +168 -0
- data/test/functional/eft_24_add_branches.rb +98 -0
- data/test/functional/eft_25_command.rb +28 -0
- data/test/functional/eft_26_error.rb +77 -0
- data/test/functional/eft_27_inc.rb +280 -0
- data/test/functional/eft_28_once.rb +135 -0
- data/test/functional/eft_29_cron.rb +64 -0
- data/test/functional/eft_2_sequence.rb +58 -0
- data/test/functional/eft_30_ref.rb +155 -0
- data/test/functional/eft_31_registerp.rb +130 -0
- data/test/functional/eft_32_lose.rb +93 -0
- data/test/functional/eft_33_let.rb +31 -0
- data/test/functional/eft_34_given.rb +123 -0
- data/test/functional/eft_35_filter.rb +375 -0
- data/test/functional/eft_36_read.rb +95 -0
- data/test/functional/eft_3_participant.rb +149 -0
- data/test/functional/eft_4_set.rb +296 -0
- data/test/functional/eft_5_subprocess.rb +163 -0
- data/test/functional/eft_6_concurrence.rb +304 -0
- data/test/functional/eft_7_forget.rb +61 -0
- data/test/functional/eft_8_undo.rb +114 -0
- data/test/functional/eft_9_redo.rb +138 -0
- data/test/functional/ft_0_worker.rb +65 -0
- data/test/functional/ft_10_dollar.rb +304 -0
- data/test/functional/ft_11_recursion.rb +109 -0
- data/test/functional/ft_12_launchitem.rb +43 -0
- data/test/functional/ft_13_variables.rb +151 -0
- data/test/functional/ft_14_re_apply.rb +324 -0
- data/test/functional/ft_15_timeout.rb +226 -0
- data/test/functional/ft_16_participant_params.rb +98 -0
- data/test/functional/ft_17_conditional.rb +102 -0
- data/test/functional/ft_18_kill.rb +138 -0
- data/test/functional/ft_19_participant_code.rb +67 -0
- data/test/functional/ft_1_process_status.rb +796 -0
- data/test/functional/ft_20_storage_participant.rb +543 -0
- data/test/functional/ft_21_forget.rb +153 -0
- data/test/functional/ft_22_process_definitions.rb +90 -0
- data/test/functional/ft_23_load_defs.rb +79 -0
- data/test/functional/ft_24_block_participant.rb +235 -0
- data/test/functional/ft_25_receiver.rb +207 -0
- data/test/functional/ft_26_participant_rtimeout.rb +179 -0
- data/test/functional/ft_27_var_indirection.rb +128 -0
- data/test/functional/ft_28_null_noop_participants.rb +51 -0
- data/test/functional/ft_29_part_template.rb +60 -0
- data/test/functional/ft_2_errors.rb +380 -0
- data/test/functional/ft_30_smtp_participant.rb +122 -0
- data/test/functional/ft_31_part_blocking.rb +72 -0
- data/test/functional/ft_33_participant_subprocess_priority.rb +32 -0
- data/test/functional/ft_34_cursor_rewind.rb +101 -0
- data/test/functional/ft_35_add_service.rb +56 -0
- data/test/functional/ft_36_storage_history.rb +150 -0
- data/test/functional/ft_37_default_history.rb +109 -0
- data/test/functional/ft_38_participant_more.rb +193 -0
- data/test/functional/ft_39_wait_for.rb +136 -0
- data/test/functional/ft_3_participant_registration.rb +574 -0
- data/test/functional/ft_40_wait_logger.rb +62 -0
- data/test/functional/ft_41_participants.rb +91 -0
- data/test/functional/ft_42_storage_copy.rb +71 -0
- data/test/functional/ft_43_participant_on_reply.rb +87 -0
- data/test/functional/ft_44_var_participant.rb +35 -0
- data/test/functional/ft_45_participant_accept.rb +64 -0
- data/test/functional/ft_46_launch_single.rb +83 -0
- data/test/functional/ft_47_wfid_generator.rb +54 -0
- data/test/functional/ft_48_lose.rb +112 -0
- data/test/functional/ft_49_engine_on_error.rb +201 -0
- data/test/functional/ft_4_cancel.rb +132 -0
- data/test/functional/ft_50_engine_config.rb +22 -0
- data/test/functional/ft_51_misc.rb +67 -0
- data/test/functional/ft_52_case.rb +134 -0
- data/test/functional/ft_53_engine_on_terminate.rb +95 -0
- data/test/functional/ft_54_patterns.rb +104 -0
- data/test/functional/ft_55_engine_participant.rb +303 -0
- data/test/functional/ft_56_filter_attribute.rb +259 -0
- data/test/functional/ft_57_rev_participant.rb +252 -0
- data/test/functional/ft_58_workitem.rb +69 -0
- data/test/functional/ft_59_pause.rb +343 -0
- data/test/functional/ft_5_on_error.rb +384 -0
- data/test/functional/ft_60_code_participant.rb +45 -0
- data/test/functional/ft_61_trailing_fields.rb +34 -0
- data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
- data/test/functional/ft_6_on_cancel.rb +221 -0
- data/test/functional/ft_7_tags.rb +177 -0
- data/test/functional/ft_8_participant_consumption.rb +124 -0
- data/test/functional/ft_9_subprocesses.rb +146 -0
- data/test/functional/restart_base.rb +34 -0
- data/test/functional/rt_0_wait.rb +55 -0
- data/test/functional/rt_1_listen.rb +56 -0
- data/test/functional/rt_2_errors.rb +56 -0
- data/test/functional/rt_3_once.rb +70 -0
- data/test/functional/rt_4_cron.rb +64 -0
- data/test/functional/rt_5_timeout.rb +60 -0
- data/test/functional/rtest.rb +8 -0
- data/test/functional/storage_helper.rb +93 -0
- data/test/functional/test.rb +44 -0
- data/test/functional/vertical.rb +46 -0
- data/test/path_helper.rb +15 -0
- data/test/test.rb +13 -0
- data/test/test_helper.rb +28 -0
- data/test/unit/storage.rb +428 -0
- data/test/unit/storages.rb +37 -0
- data/test/unit/test.rb +28 -0
- data/test/unit/ut_0_ruby_reader.rb +223 -0
- data/test/unit/ut_11_lookup.rb +122 -0
- data/test/unit/ut_13_serializer.rb +65 -0
- data/test/unit/ut_14_is_uri.rb +28 -0
- data/test/unit/ut_15_util.rb +57 -0
- data/test/unit/ut_16_reader.rb +225 -0
- data/test/unit/ut_18_engine.rb +47 -0
- data/test/unit/ut_19_part_template.rb +86 -0
- data/test/unit/ut_1_fei.rb +165 -0
- data/test/unit/ut_20_composite_storage.rb +74 -0
- data/test/unit/ut_21_svc_participant_list.rb +46 -0
- data/test/unit/ut_22_filter.rb +1094 -0
- data/test/unit/ut_23_svc_tracker.rb +48 -0
- data/test/unit/ut_24_radial_reader.rb +332 -0
- data/test/unit/ut_25_merge.rb +113 -0
- data/test/unit/ut_3_wait_logger.rb +39 -0
- data/test/unit/ut_4_expmap.rb +20 -0
- data/test/unit/ut_5_tree.rb +54 -0
- data/test/unit/ut_6_condition.rb +303 -0
- data/test/unit/ut_7_workitem.rb +99 -0
- data/test/unit/ut_8_tree_to_dot.rb +72 -0
- data/test/unit/ut_9_xml_reader.rb +61 -0
- metadata +504 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
|
26
|
+
module Ruote::Exp
|
27
|
+
|
28
|
+
#
|
29
|
+
# Never replies to its parent expression. Simply applies its first child,
|
30
|
+
# if any, and just sits there.
|
31
|
+
#
|
32
|
+
# When cancelled, cancels its child (if any).
|
33
|
+
#
|
34
|
+
# In this example, the reminding sequence never replies to the concurrence.
|
35
|
+
# The concurrence is only over when "alfred" replies.
|
36
|
+
#
|
37
|
+
# Ruote.process_definition do
|
38
|
+
# concurrence :count => 1 do
|
39
|
+
# alfred
|
40
|
+
# lose do
|
41
|
+
# sequence do
|
42
|
+
# wait '2d'
|
43
|
+
# send_reminder_to_alfred
|
44
|
+
# wait '2h'
|
45
|
+
# send_alarm_to_boss
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# Maybe shorter :
|
52
|
+
#
|
53
|
+
# Ruote.process_definition do
|
54
|
+
# concurrence :count => 1 do
|
55
|
+
# alfred
|
56
|
+
# sequence do
|
57
|
+
# wait '2d'
|
58
|
+
# send_reminder_to_alfred
|
59
|
+
# wait '2h'
|
60
|
+
# send_alarm_to_boss
|
61
|
+
# lose
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# 'lose' on its own acts like a dead-end.
|
67
|
+
#
|
68
|
+
#
|
69
|
+
# == the :lose attribute
|
70
|
+
#
|
71
|
+
# Every expression understands the 'lose' attribute :
|
72
|
+
#
|
73
|
+
# Ruote.process_definition do
|
74
|
+
# concurrence :count => 1 do
|
75
|
+
# alfred
|
76
|
+
# sequence :lose => true do
|
77
|
+
# wait '2d'
|
78
|
+
# send_reminder_to_alfred
|
79
|
+
# wait '2h'
|
80
|
+
# send_alarm_to_boss
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# Probably produces definitions more compact than when using the 'lose'
|
86
|
+
# expression.
|
87
|
+
#
|
88
|
+
# == forget vs lose
|
89
|
+
#
|
90
|
+
# forget : replies to parent expression immediately, is not cancellable
|
91
|
+
# (not reachable).
|
92
|
+
#
|
93
|
+
# lose : never replies to parent expression, is cancellable.
|
94
|
+
#
|
95
|
+
class LoseExpression < FlowExpression
|
96
|
+
|
97
|
+
names :lose
|
98
|
+
|
99
|
+
def apply
|
100
|
+
|
101
|
+
apply_child(0, h.applied_workitem)
|
102
|
+
end
|
103
|
+
|
104
|
+
def reply(workitem)
|
105
|
+
|
106
|
+
# never gets called
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
|
26
|
+
module Ruote::Exp
|
27
|
+
|
28
|
+
#
|
29
|
+
# 'No Operation' expression. Does nothing, immediately replies to
|
30
|
+
# its parent expression.
|
31
|
+
#
|
32
|
+
# Could be useful within a cursor expression with a :tag attribute
|
33
|
+
# as a jump expression target.
|
34
|
+
#
|
35
|
+
class NoOpExpression < FlowExpression
|
36
|
+
|
37
|
+
names :noop
|
38
|
+
|
39
|
+
def apply
|
40
|
+
|
41
|
+
reply_to_parent(h.applied_workitem)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,215 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
|
26
|
+
module Ruote::Exp
|
27
|
+
|
28
|
+
#
|
29
|
+
# The 'once' / 'when' expression verifies if a condition is true,
|
30
|
+
# if not it will block and after 10 seconds it will check again.
|
31
|
+
# If true, it will resume or it will execute its child expression (before
|
32
|
+
# resuming).
|
33
|
+
#
|
34
|
+
# concurrence do
|
35
|
+
#
|
36
|
+
# once '${v:/invoice_status} == emitted' do
|
37
|
+
# open_customer_support_account
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# sequence do
|
41
|
+
# participant 'accounting'
|
42
|
+
# set 'v:/invoice_status' => 'emitted'
|
43
|
+
# participant 'accounting 2'
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# The condition is usually something about variables, since the workitem that
|
48
|
+
# this expression has access to is always the one that reached it, at apply
|
49
|
+
# time.
|
50
|
+
#
|
51
|
+
# Without a child expression, this expression behaves in a 'blocking way', and
|
52
|
+
# it makes most sense in a 'sequence' or in a 'cursor'.
|
53
|
+
#
|
54
|
+
# sequence do
|
55
|
+
# first_stage
|
56
|
+
# once '${v:ready_for_second_stage}'
|
57
|
+
# second_stage
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# When there is a child expression, it will get triggered when the condition
|
61
|
+
# realizes. Only 1 child expression is accepted, there is no implicit
|
62
|
+
# 'sequence'.
|
63
|
+
#
|
64
|
+
# concurrence do
|
65
|
+
# once :test => '${v:go_on} == yes' do
|
66
|
+
# subprocess :ref => 'final_stage'
|
67
|
+
# end
|
68
|
+
# sequence do
|
69
|
+
# participant :ref => 'controller'
|
70
|
+
# set 'v:go_on' => 'yes'
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# == :test
|
75
|
+
#
|
76
|
+
# Most of the example process definitions until now were placing the condition
|
77
|
+
# directly after the expression name itself. In an XML process definition or
|
78
|
+
# if you prefer it this way, you can use the :test attribute to formulate the
|
79
|
+
# condition :
|
80
|
+
#
|
81
|
+
# <once test="${v:ready}">
|
82
|
+
# <participant ref="role_publisher" />
|
83
|
+
# </once>
|
84
|
+
#
|
85
|
+
# In a Ruby process definition :
|
86
|
+
#
|
87
|
+
# once :test => '${v:ready}' do
|
88
|
+
# participant :ref => 'role_publisher'
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
#
|
92
|
+
# == :frequency
|
93
|
+
#
|
94
|
+
# As said, the default 'check' frequency is 10 seconds. This can be changed
|
95
|
+
# by using the :frequency (or :freq) attribute.
|
96
|
+
#
|
97
|
+
# sequence do
|
98
|
+
# participant 'logistic_unit'
|
99
|
+
# once '${v:/delivery_ok}', :frequency => '2d'
|
100
|
+
# # block until delivery is OK (another branch of the process probably)
|
101
|
+
# # check every two days
|
102
|
+
# participant 'accounting_unit'
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
#
|
106
|
+
# == :frequency and cron notation
|
107
|
+
#
|
108
|
+
# It's OK to pass a 'cron string' to the :frequency attribute.
|
109
|
+
#
|
110
|
+
# once '${v:delivery_complete}', :freq => '5 0 * * *'
|
111
|
+
# # this 'once' will check its condition once per day, five minutes
|
112
|
+
# # after midnight
|
113
|
+
#
|
114
|
+
# See "man 5 crontab" on your favourite unix system for the details of
|
115
|
+
# the 'cron string', but please note that ruote (thanks to the
|
116
|
+
# rufus-scheduler (http://rufus.rubyforge.org/rufus-scheduler) accepts
|
117
|
+
# seconds as well.
|
118
|
+
#
|
119
|
+
#
|
120
|
+
# == the :timeout attribute common to all expressions
|
121
|
+
#
|
122
|
+
# Don't forget that this expression, like all the other expressions accepts
|
123
|
+
# the :timeout attribute. It's perhaps better to use :timeout when there is
|
124
|
+
# a child expression, so that the child won't get 'triggered' in case of
|
125
|
+
# timeout. When there is no child expression and the 'once' behaves in a
|
126
|
+
# 'blocking way', a timeout will unblock, as if the condition became true.
|
127
|
+
#
|
128
|
+
#
|
129
|
+
# == ${ruby:'hello'}
|
130
|
+
#
|
131
|
+
# Remember that, if the engine's 'ruby_eval_allowed' is set to true, the
|
132
|
+
# condition may contain Ruby code.
|
133
|
+
#
|
134
|
+
# once '${r:"hell" + "o"} == hello'
|
135
|
+
#
|
136
|
+
# This Ruby code is checked before hand against malicious code, but beware...
|
137
|
+
#
|
138
|
+
#
|
139
|
+
# == aliases
|
140
|
+
#
|
141
|
+
# 'once', '_when' and 'as_soon_as' are three different names for this
|
142
|
+
# expression.
|
143
|
+
#
|
144
|
+
class OnceExpression < FlowExpression
|
145
|
+
|
146
|
+
names :once, :when, :as_soon_as
|
147
|
+
|
148
|
+
def apply
|
149
|
+
|
150
|
+
h.frequency = attribute(:frequency) || attribute(:freq) || '10s'
|
151
|
+
h.triggered = false
|
152
|
+
h.job_id = nil
|
153
|
+
|
154
|
+
reply(h.applied_workitem)
|
155
|
+
end
|
156
|
+
|
157
|
+
def reply(workitem)
|
158
|
+
|
159
|
+
return reply_to_parent(workitem) if h.triggered
|
160
|
+
|
161
|
+
t = attribute(:test) || attribute_text
|
162
|
+
|
163
|
+
if Condition.true?(t)
|
164
|
+
|
165
|
+
h.triggered = true
|
166
|
+
|
167
|
+
@context.storage.delete_schedule(h.job_id)
|
168
|
+
# especially for a cron...
|
169
|
+
|
170
|
+
if tree_children[0]
|
171
|
+
#
|
172
|
+
# trigger first child
|
173
|
+
#
|
174
|
+
apply_child(0, workitem)
|
175
|
+
else
|
176
|
+
#
|
177
|
+
# blocking case
|
178
|
+
#
|
179
|
+
reply_to_parent(workitem)
|
180
|
+
end
|
181
|
+
else
|
182
|
+
|
183
|
+
reschedule
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def cancel(flavour)
|
188
|
+
|
189
|
+
@context.storage.delete_schedule(h.job_id)
|
190
|
+
super
|
191
|
+
end
|
192
|
+
|
193
|
+
protected
|
194
|
+
|
195
|
+
def reschedule
|
196
|
+
|
197
|
+
h.job_id = @context.storage.put_schedule(
|
198
|
+
'cron',
|
199
|
+
h.fei,
|
200
|
+
h.frequency,
|
201
|
+
'action' => 'reply',
|
202
|
+
'fei' => h.fei,
|
203
|
+
'workitem' => h.applied_workitem)
|
204
|
+
|
205
|
+
@context.storage.delete_schedule(h.job_id) if try_persist
|
206
|
+
#
|
207
|
+
# if the persist failed, immediately unschedule
|
208
|
+
# the just scheduled job
|
209
|
+
#
|
210
|
+
# this is meant to cope with cases where one worker reschedules
|
211
|
+
# while another just cancelled
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
@@ -0,0 +1,287 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
|
26
|
+
require 'ruote/exp/condition'
|
27
|
+
|
28
|
+
|
29
|
+
module Ruote::Exp
|
30
|
+
|
31
|
+
#
|
32
|
+
# The 'participant' expression is very special. It sits on the fence between
|
33
|
+
# the engine and the external world.
|
34
|
+
#
|
35
|
+
# The participant expression is used to pass workitems to participants
|
36
|
+
# from the engine. Those participants are bound at start time (usually) in
|
37
|
+
# the engine via its register_participant method.
|
38
|
+
#
|
39
|
+
# Here's an example of two concurrent participant expressions in use :
|
40
|
+
#
|
41
|
+
# concurrence do
|
42
|
+
# participant :ref => 'alice'
|
43
|
+
# participant :ref => 'bob'
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# Upon encountering the two expressions, the engine will lookup their name
|
47
|
+
# in the participant map and hand the workitems to the participant instances
|
48
|
+
# registered for those names.
|
49
|
+
#
|
50
|
+
#
|
51
|
+
# == attributes passed as arguments
|
52
|
+
#
|
53
|
+
# All the attributes passed to a participant will be fed to the outgoing
|
54
|
+
# workitem under a new 'params' field.
|
55
|
+
#
|
56
|
+
# Thus, with
|
57
|
+
#
|
58
|
+
# participant :ref => 'alice', :task => 'maw the lawn', :timeout => '2d'
|
59
|
+
#
|
60
|
+
# Alice will receive a workitem with a field params set to
|
61
|
+
#
|
62
|
+
# { :ref => 'alice', :task => 'maw the lawn', :timeout => '2d' }
|
63
|
+
#
|
64
|
+
# The fields named 'params' will be deleted before the workitems resumes
|
65
|
+
# in the flow (with the engine replying to the parent expression of this
|
66
|
+
# participant expression).
|
67
|
+
#
|
68
|
+
#
|
69
|
+
# == simplified participant notation
|
70
|
+
#
|
71
|
+
# This process definition is equivalent to the one above. Less to write.
|
72
|
+
#
|
73
|
+
# concurrence do
|
74
|
+
# participant 'alice'
|
75
|
+
# bob
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# Please note that 'bob' alone could stand for the participant 'bob' or
|
79
|
+
# the subprocess named 'bob'. Subprocesses do take precedence over
|
80
|
+
# participants (if there is a subprocess named 'bob' and a participant
|
81
|
+
# named 'bob'.
|
82
|
+
#
|
83
|
+
#
|
84
|
+
# == participant defined timeout
|
85
|
+
#
|
86
|
+
# Usually, timeouts are given for an expression in the process definition.
|
87
|
+
#
|
88
|
+
# participant 'alice', :timeout => '2d'
|
89
|
+
#
|
90
|
+
# where alice as two days to complete her task (send back the workitem).
|
91
|
+
#
|
92
|
+
# But it's OK for participant classes registered in the engine to provide
|
93
|
+
# their own timeout value. The participant instance simply has to reply to
|
94
|
+
# the #rtimeout method and provide a meaningful timeout value (like a
|
95
|
+
# number of seconds, or a string like "2d" or "1M2w".
|
96
|
+
#
|
97
|
+
# Note however, that the process definition timeout (if any) will take
|
98
|
+
# precedence over the participant specified one.
|
99
|
+
#
|
100
|
+
#
|
101
|
+
# == asynchronous
|
102
|
+
#
|
103
|
+
# The expression will make sure to dispatch to the participant in an
|
104
|
+
# asynchronous way. This means that the dispatch will occur in a dedicated
|
105
|
+
# thread.
|
106
|
+
#
|
107
|
+
# Since the dispatching to the participant could take a long time and block
|
108
|
+
# the engine for too long, this 'do thread' policy is used by default.
|
109
|
+
#
|
110
|
+
# If the participant itself replies to the method #do_not_thread and replies
|
111
|
+
# positively to it, a new thread (or a next_tick) won't get used. This is
|
112
|
+
# practical for tiny participants that don't do IO and reply immediately
|
113
|
+
# (after a few operations). By default, BlockParticipant instances do not
|
114
|
+
# thread.
|
115
|
+
#
|
116
|
+
class ParticipantExpression < FlowExpression
|
117
|
+
|
118
|
+
names :participant
|
119
|
+
|
120
|
+
# Should yield true when the dispatch was successful.
|
121
|
+
#
|
122
|
+
h_reader :dispatched
|
123
|
+
|
124
|
+
h_reader :participant
|
125
|
+
|
126
|
+
def apply
|
127
|
+
|
128
|
+
#
|
129
|
+
# determine participant
|
130
|
+
|
131
|
+
h.participant_name = (attribute(:ref) || attribute_text).to_s
|
132
|
+
|
133
|
+
raise ArgumentError.new(
|
134
|
+
"no participant name specified"
|
135
|
+
) if h.participant_name == ''
|
136
|
+
|
137
|
+
h.participant ||=
|
138
|
+
@context.plist.lookup_info(h.participant_name, h.applied_workitem)
|
139
|
+
|
140
|
+
raise(ArgumentError.new(
|
141
|
+
"no participant named #{h.participant_name.inspect}")
|
142
|
+
) if h.participant.nil?
|
143
|
+
|
144
|
+
#
|
145
|
+
# dispatch to participant
|
146
|
+
|
147
|
+
h.applied_workitem['participant_name'] = h.participant_name
|
148
|
+
|
149
|
+
h.applied_workitem['fields']['params'] = compile_atts
|
150
|
+
h.applied_workitem['fields'].delete('t')
|
151
|
+
|
152
|
+
schedule_timeout(h.participant)
|
153
|
+
|
154
|
+
persist_or_raise
|
155
|
+
|
156
|
+
@context.storage.put_msg(
|
157
|
+
'dispatch',
|
158
|
+
'fei' => h.fei,
|
159
|
+
'participant_name' => h.participant_name,
|
160
|
+
'participant' => h.participant,
|
161
|
+
'workitem' => h.applied_workitem)
|
162
|
+
end
|
163
|
+
|
164
|
+
def cancel(flavour)
|
165
|
+
|
166
|
+
return reply_to_parent(h.applied_workitem) unless h.participant_name
|
167
|
+
# no participant, reply immediately
|
168
|
+
|
169
|
+
do_persist || return
|
170
|
+
#
|
171
|
+
# if do_persist returns false, it means we're operating on stale
|
172
|
+
# data and cannot continue
|
173
|
+
|
174
|
+
@context.storage.put_msg(
|
175
|
+
'dispatch_cancel',
|
176
|
+
'fei' => h.fei,
|
177
|
+
'participant_name' => h.participant_name,
|
178
|
+
'participant' => h.participant,
|
179
|
+
'flavour' => flavour,
|
180
|
+
'workitem' => h.applied_workitem)
|
181
|
+
end
|
182
|
+
|
183
|
+
def reply(workitem)
|
184
|
+
|
185
|
+
pinfo =
|
186
|
+
h.participant ||
|
187
|
+
@context.plist.lookup_info(h.participant_name, workitem)
|
188
|
+
|
189
|
+
pa = @context.plist.instantiate(pinfo, :if_respond_to? => :on_reply)
|
190
|
+
|
191
|
+
pa.on_reply(Ruote::Workitem.new(workitem)) if pa
|
192
|
+
|
193
|
+
super(workitem)
|
194
|
+
end
|
195
|
+
|
196
|
+
def reply_to_parent(workitem)
|
197
|
+
|
198
|
+
workitem['fields'].delete('params')
|
199
|
+
workitem['fields'].delete('dispatched_at')
|
200
|
+
super(workitem)
|
201
|
+
end
|
202
|
+
|
203
|
+
protected
|
204
|
+
|
205
|
+
# Once the dispatching work (done by the dispatch pool) is done, a
|
206
|
+
# 'dispatched' msg is sent, we have to flag the participant expression
|
207
|
+
# as 'dispatched' => true
|
208
|
+
#
|
209
|
+
# See http://groups.google.com/group/openwferu-users/browse_thread/thread/ff29f26d6b5fd135
|
210
|
+
# for the motivation.
|
211
|
+
#
|
212
|
+
def do_dispatched(msg)
|
213
|
+
|
214
|
+
h.dispatched = true
|
215
|
+
do_persist
|
216
|
+
# let's not care if it fails...
|
217
|
+
end
|
218
|
+
|
219
|
+
# Overriden with an empty behaviour. The work is now done a bit later
|
220
|
+
# via the #schedule_timeout method.
|
221
|
+
#
|
222
|
+
def consider_timeout
|
223
|
+
end
|
224
|
+
|
225
|
+
# Determines and schedules timeout if any.
|
226
|
+
#
|
227
|
+
# Note that process definition timeout has priority over participant
|
228
|
+
# specified timeout.
|
229
|
+
#
|
230
|
+
def schedule_timeout(p_info)
|
231
|
+
|
232
|
+
timeout = attribute(:timeout)
|
233
|
+
|
234
|
+
unless timeout
|
235
|
+
|
236
|
+
pa = @context.plist.instantiate(p_info, :if_respond_to? => :rtimeout)
|
237
|
+
|
238
|
+
timeout = (pa.method(:rtimeout).arity == 0 ?
|
239
|
+
pa.rtimeout :
|
240
|
+
pa.rtimeout(Ruote::Workitem.new(h.applied_workitem))
|
241
|
+
) if pa
|
242
|
+
end
|
243
|
+
|
244
|
+
do_schedule_timeout(timeout)
|
245
|
+
end
|
246
|
+
|
247
|
+
def do_pause(msg)
|
248
|
+
|
249
|
+
return if h.state != nil
|
250
|
+
|
251
|
+
h['state'] = 'paused'
|
252
|
+
h['breakpoint'] = true if msg['breakpoint']
|
253
|
+
|
254
|
+
do_persist || return
|
255
|
+
|
256
|
+
@context.storage.put_msg(
|
257
|
+
'dispatch_pause',
|
258
|
+
'fei' => h.fei,
|
259
|
+
'participant_name' => h.participant_name,
|
260
|
+
'participant' => h.participant
|
261
|
+
) unless msg['breakpoint']
|
262
|
+
end
|
263
|
+
|
264
|
+
def do_resume(msg)
|
265
|
+
|
266
|
+
return if h.state != 'paused'
|
267
|
+
|
268
|
+
h['state'] = nil
|
269
|
+
replies = h.delete('paused_replies') || []
|
270
|
+
|
271
|
+
do_persist || return
|
272
|
+
|
273
|
+
if replies.empty?
|
274
|
+
@context.storage.put_msg(
|
275
|
+
'dispatch_resume',
|
276
|
+
'fei' => h.fei,
|
277
|
+
'participant_name' => h.participant_name,
|
278
|
+
'participant' => h.participant
|
279
|
+
) unless h['breakpoint']
|
280
|
+
else
|
281
|
+
replies.each { |m| @context.storage.put_msg(m.delete('action'), m) }
|
282
|
+
# trigger replies
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|