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,234 @@
|
|
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/commanded'
|
27
|
+
require 'ruote/exp/iterator'
|
28
|
+
|
29
|
+
|
30
|
+
module Ruote::Exp
|
31
|
+
|
32
|
+
#
|
33
|
+
# Iterating on a list of values
|
34
|
+
#
|
35
|
+
# pdef = Ruote.process_definition :name => 'test' do
|
36
|
+
# iterator :on_val => 'alice, bob, charly', :to_var => 'v' do
|
37
|
+
# participant '${v:v}'
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# This expression expects at list an 'on' attribute, which can be :on,
|
42
|
+
# :on_val, :on_value for a value (usually a comma separated list), :on_v,
|
43
|
+
# :on_var, :on_variable for a list contained in the designated variable and
|
44
|
+
# :on_f, :on_fld, :on_field for a list contained in the designated workitem
|
45
|
+
# field.
|
46
|
+
#
|
47
|
+
# The 'on' attribute is used to instruct the expression on which list/array
|
48
|
+
# it should iterate.
|
49
|
+
#
|
50
|
+
# The 'to' attribute takes two forms, :to_v, :to_var, :to_variable or
|
51
|
+
# :to_f, :to_fld, :to_field. Finally, you can write :to => 'field_name',
|
52
|
+
# :to => 'f:field_name' or :to => 'v:variable_name'.
|
53
|
+
#
|
54
|
+
# The 'to' attribute instructs the iterator into which variable or field
|
55
|
+
# it should place the current value (the value being iterated over).
|
56
|
+
#
|
57
|
+
# If there is no 'to' specified, the current value is placed in the variable
|
58
|
+
# named 'i'.
|
59
|
+
#
|
60
|
+
# The variables 'ii' contains the index (from 0 to ...) of the current value
|
61
|
+
# (think Ruby's #each_with_index).
|
62
|
+
#
|
63
|
+
# The 'on' attribute can be replaced by a :time or a :branches attribute.
|
64
|
+
#
|
65
|
+
# pdef = Ruote.process_definition :name => 'test' do
|
66
|
+
# iterator :times => '3'
|
67
|
+
# participant 'accounting'
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# will be equivalent to
|
72
|
+
#
|
73
|
+
# pdef = Ruote.process_definition :name => 'test' do
|
74
|
+
# sequence do
|
75
|
+
# participant 'accounting'
|
76
|
+
# participant 'accounting'
|
77
|
+
# participant 'accounting'
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
#
|
82
|
+
# == the classical case
|
83
|
+
#
|
84
|
+
# Iterating over a workitem field :
|
85
|
+
#
|
86
|
+
# pdef = Ruote.process_definition :name => 'test' do
|
87
|
+
# iterator :on_field => 'customers', :to_f => 'customer'
|
88
|
+
# participant '${f:customer}'
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
#
|
93
|
+
# == break/rewind/continue/skip/jump
|
94
|
+
#
|
95
|
+
# The 'iterator' expression understands a certain the following commands :
|
96
|
+
#
|
97
|
+
# * break (_break) : exits the iteration
|
98
|
+
# * rewind : places the iteration back at the first iterated value
|
99
|
+
# * continue : same as 'rewind'
|
100
|
+
# * skip : skips a certain number of steps (relative)
|
101
|
+
# * jump : jump to certain step (absolute)
|
102
|
+
#
|
103
|
+
# pdef = Ruote.process_definition :name => 'test' do
|
104
|
+
# iterator :times => '3'
|
105
|
+
# sequence do
|
106
|
+
# participant 'accounting', :review => '${v:i}'
|
107
|
+
# rewind :if => '${f:redo_everything} == true'
|
108
|
+
# end
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# == iterator command in the workitem
|
113
|
+
#
|
114
|
+
# It's OK to issue a command to the iterator from a participant via the
|
115
|
+
# workitem.
|
116
|
+
#
|
117
|
+
# pdef = Ruote.process_definition do
|
118
|
+
# iterator :times => 10
|
119
|
+
# sequence do
|
120
|
+
# participant 'accounting'
|
121
|
+
# participant 'adjust'
|
122
|
+
# end
|
123
|
+
# end
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# where
|
127
|
+
#
|
128
|
+
# class Adjust
|
129
|
+
# include Ruote::LocalParticipant
|
130
|
+
# def consume(workitem)
|
131
|
+
# workitem.command = 'break' if workitem.fields['amount'] > 10_000
|
132
|
+
# reply_to_engine(workitem)
|
133
|
+
# end
|
134
|
+
# def cancel(fei, flavour)
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# A completely stupid example... The adjust participant will make the
|
139
|
+
# loop break if the amount reaches 10_000 (euros?).
|
140
|
+
#
|
141
|
+
#
|
142
|
+
# == break/rewind/continue/skip/jump with :ref
|
143
|
+
#
|
144
|
+
# An iterator can be tagged (with the :tag attribute) and directly referenced
|
145
|
+
# from a break/rewind/continue/skip/jump command.
|
146
|
+
#
|
147
|
+
# It's very useful when iterators (and cursors/loops) are nested within each
|
148
|
+
# other or when one has to act on an iterator from outside of it.
|
149
|
+
#
|
150
|
+
# concurrence do
|
151
|
+
#
|
152
|
+
# iterator :on => 'alpha, bravo, charly', :tag => 'review' do
|
153
|
+
# participant '${v:i}'
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# # meanwhile ...
|
157
|
+
#
|
158
|
+
# sequence do
|
159
|
+
# participant 'main control program'
|
160
|
+
# _break :ref => 'review', :if => '${f:cancel_review} == yes'
|
161
|
+
# end
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# in this example, the participant 'main control program' may cancel the
|
165
|
+
# review.
|
166
|
+
#
|
167
|
+
# iterator :on => 'c1, c2, c3', :to_f => 'client', :tag => 'main' do
|
168
|
+
# cursor do
|
169
|
+
# participant :ref => '${f:client}'
|
170
|
+
# _break :ref => 'main', :if => '${f:cancel_everything}'
|
171
|
+
# participant :ref => 'salesclerk'
|
172
|
+
# participant :ref => 'salesclerk'
|
173
|
+
# end
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# in this weird process, if one customer says "cancel everything" (set the
|
177
|
+
# workitem field "cancel_everything" to true), then the whole iterator
|
178
|
+
# gets 'broken' out of.
|
179
|
+
#
|
180
|
+
class IteratorExpression < CommandedExpression
|
181
|
+
|
182
|
+
include IteratorMixin
|
183
|
+
|
184
|
+
names :iterator
|
185
|
+
|
186
|
+
def apply
|
187
|
+
|
188
|
+
return reply_to_parent(h.applied_workitem) if tree_children.size < 1
|
189
|
+
|
190
|
+
h.list = determine_list
|
191
|
+
h.to_v, h.to_f = determine_tos
|
192
|
+
h.position = -1
|
193
|
+
|
194
|
+
h.to_v = 'i' if h.to_v == nil && h.to_f == nil
|
195
|
+
|
196
|
+
move_on
|
197
|
+
end
|
198
|
+
|
199
|
+
protected
|
200
|
+
|
201
|
+
def move_on(workitem=h.applied_workitem)
|
202
|
+
|
203
|
+
h.position += 1
|
204
|
+
|
205
|
+
com, arg = get_command(workitem)
|
206
|
+
|
207
|
+
return reply_to_parent(workitem) if com == 'break'
|
208
|
+
|
209
|
+
case com
|
210
|
+
when 'rewind', 'continue' then h.position = 0
|
211
|
+
when 'skip' then h.position += arg
|
212
|
+
when 'jump' then h.position = arg
|
213
|
+
end
|
214
|
+
|
215
|
+
h.position = h.list.length + h.position if h.position < 0
|
216
|
+
|
217
|
+
val = h.list[h.position]
|
218
|
+
|
219
|
+
return reply_to_parent(workitem) if val == nil
|
220
|
+
|
221
|
+
(h.variables ||= {})['ii'] = h.position
|
222
|
+
|
223
|
+
if h.to_v
|
224
|
+
h.variables[h.to_v] = val
|
225
|
+
else #if h.to_f
|
226
|
+
workitem['fields'][h.to_f] = val
|
227
|
+
end
|
228
|
+
|
229
|
+
apply_child(0, workitem)
|
230
|
+
# persist is done in there
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
@@ -0,0 +1,75 @@
|
|
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
|
+
# Behaves like a sequence, but the children have their own variable
|
32
|
+
# scope.
|
33
|
+
#
|
34
|
+
# pdef = Ruote.process_definition do
|
35
|
+
# set 'v:var' => 'val'
|
36
|
+
# echo "out:${v:var}"
|
37
|
+
# let do
|
38
|
+
# set 'v:var' => 'val1'
|
39
|
+
# echo "in:${v:var}"
|
40
|
+
# end
|
41
|
+
# echo "out:${v:var}"
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # => out:val, in:val1, out:val
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# == as a 'case' statement
|
48
|
+
#
|
49
|
+
# let do
|
50
|
+
# define 'published' do
|
51
|
+
# do_this
|
52
|
+
# end
|
53
|
+
# define 'reviewed' do
|
54
|
+
# do_that
|
55
|
+
# end
|
56
|
+
# subprocess '${case}'
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# Subprocesses 'published' and 'reviewed' are bound in a local scope,
|
60
|
+
# that gets discarded when the let exits.
|
61
|
+
#
|
62
|
+
class LetExpression < SequenceExpression
|
63
|
+
|
64
|
+
names :let
|
65
|
+
|
66
|
+
def apply
|
67
|
+
|
68
|
+
h.variables = {}
|
69
|
+
# the blank local scope
|
70
|
+
|
71
|
+
reply(h.applied_workitem)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,304 @@
|
|
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
|
+
# Listens for activity (incoming or outgoing workitems) on a (set of)
|
33
|
+
# participant(s).
|
34
|
+
#
|
35
|
+
# This expression is an advanced one. It allows for cross process instance
|
36
|
+
# communication or at least cross branch communication within the same
|
37
|
+
# process instance.
|
38
|
+
#
|
39
|
+
# DO NOT confuse the listen expression with the 'listener' concept. They are
|
40
|
+
# not directly related. The listen expression listens to workitem activity
|
41
|
+
# inside of the engine, while a listener listens for workitems or launchitems
|
42
|
+
# from sources external to the ruote workflow engine.
|
43
|
+
#
|
44
|
+
# It can be used in two ways : 'blocking' or 'triggering'. In both cases
|
45
|
+
# the listen expression 'reacts' upon activity (incoming or outgoing workitem)
|
46
|
+
# happening on a channel (a participant name or a tag name).
|
47
|
+
#
|
48
|
+
# == blocking
|
49
|
+
#
|
50
|
+
# A blocking example :
|
51
|
+
#
|
52
|
+
# sequence do
|
53
|
+
# participant 'alice'
|
54
|
+
# listen :to => 'bob'
|
55
|
+
# participant 'charly'
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# Once the listen expression got applied, this process will block until a
|
59
|
+
# workitem (in any other process instance in the same engine) is dispatched
|
60
|
+
# to participant 'bob'. It then proceeds to charly.
|
61
|
+
#
|
62
|
+
# == triggering
|
63
|
+
#
|
64
|
+
# This way of using 'listen' is useful for launching processes that "stalk"
|
65
|
+
# other processes :
|
66
|
+
#
|
67
|
+
# Ruote.process_definition :name => 'stalker' do
|
68
|
+
# listen :to => 'bob' do
|
69
|
+
# participant :ref => 'charly'
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# This small process will never exits and will send a workitem to charly
|
74
|
+
# each time the ruote engine sends a workitem to bob.
|
75
|
+
#
|
76
|
+
# The workitems passed to charly will be copies of the workitem initially
|
77
|
+
# applied to the 'listen' expression, but with a copy of the fields of the
|
78
|
+
# workitem passed to bob, merged in.
|
79
|
+
#
|
80
|
+
# Note : for now, the triggered segments of processes are 'forgotten'. The
|
81
|
+
# 'listen' expression doesn't keep track of them. This also means that in
|
82
|
+
# case of cancel, the triggered segments will not get cancelled.
|
83
|
+
#
|
84
|
+
# == :merge
|
85
|
+
#
|
86
|
+
# By default, :merge is set to true, the listened for workitems see their
|
87
|
+
# values merged into a copy of the workitem held in the listen expression
|
88
|
+
# and this copy is delivered to the expressions that are client to the
|
89
|
+
# 'listen'.
|
90
|
+
#
|
91
|
+
# == :upon
|
92
|
+
#
|
93
|
+
# There are two kinds of main events in ruote, apply and reply. Thus,
|
94
|
+
# a listen expression may listen to 'apply' and to 'reply' and this is
|
95
|
+
# defined by the :upon attribute.
|
96
|
+
#
|
97
|
+
# By default, listens upon 'apply' (engine handing workitem to participant).
|
98
|
+
#
|
99
|
+
# Can be set to 'reply', to react on workitems being handed back to the
|
100
|
+
# engine by the participant.
|
101
|
+
#
|
102
|
+
# Setting :upon to 'entering' or 'leaving' tells the listen to focus on
|
103
|
+
# tag events.
|
104
|
+
#
|
105
|
+
# sequence do
|
106
|
+
# sequence :tag => 'phase_one' do
|
107
|
+
# alpha
|
108
|
+
# end
|
109
|
+
# sequence :tag => 'phase_two' do
|
110
|
+
# bravo
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# In this dummy process definition, there are four tag events :
|
115
|
+
#
|
116
|
+
# * 'entering' 'phase_one'
|
117
|
+
# * 'leaving' 'phase_one'
|
118
|
+
# * 'entering' 'phase_two'
|
119
|
+
# * 'leaving' 'phase_two'
|
120
|
+
#
|
121
|
+
#
|
122
|
+
# == :to and :on
|
123
|
+
#
|
124
|
+
# The :to attribute has already been seen, it can be replaced by the :on one.
|
125
|
+
#
|
126
|
+
# listen :to => 'alpha'
|
127
|
+
#
|
128
|
+
# is equivalent to
|
129
|
+
#
|
130
|
+
# listen :on => 'alpha'
|
131
|
+
#
|
132
|
+
#
|
133
|
+
# == :to (:on) and regular expressions
|
134
|
+
#
|
135
|
+
# It's OK to write things like :
|
136
|
+
#
|
137
|
+
# listen :to => "/^user\_.+/"
|
138
|
+
#
|
139
|
+
# or
|
140
|
+
#
|
141
|
+
# listen :to => /^user\_.+/
|
142
|
+
#
|
143
|
+
# To listen for workitems for all the participant whose name start with
|
144
|
+
# "user_".
|
145
|
+
#
|
146
|
+
#
|
147
|
+
# == :wfid
|
148
|
+
#
|
149
|
+
# By default, a listen expression listens for any workitem/participant event
|
150
|
+
# in the engine. Setting the :wfid attribute to 'true' or 'same' or 'current'
|
151
|
+
# will make the listen expression only care for events belonging to the
|
152
|
+
# same process instance (same wfid).
|
153
|
+
#
|
154
|
+
#
|
155
|
+
# == :where
|
156
|
+
#
|
157
|
+
# The :wfid can be considered a 'guard'. Another tool for guarding listen
|
158
|
+
# is to use the :where attribute.
|
159
|
+
#
|
160
|
+
# listen :to => 'alpha', :where => '${customer.state} == CA'
|
161
|
+
#
|
162
|
+
# The listen will trigger only if the workitem has a customer field with
|
163
|
+
# a subfield state containing the value "CA".
|
164
|
+
#
|
165
|
+
# The documentation about the dollar notation and the one about common
|
166
|
+
# attributes :if and :unless applies for the :where attribute.
|
167
|
+
#
|
168
|
+
#
|
169
|
+
# == listen :to => :errors
|
170
|
+
#
|
171
|
+
# The listen expression can be made to listen to errors.
|
172
|
+
#
|
173
|
+
# listen :to => errors do
|
174
|
+
# participant 'supervisor_sms', :task => 'verify system'
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# Whenever an error happens in the process with this listen stance,
|
178
|
+
# the listen will trigger.
|
179
|
+
#
|
180
|
+
# "listen :to => :errors" only works with errors in the same process instance
|
181
|
+
# (same wfid).
|
182
|
+
#
|
183
|
+
# "listen :to => :errors" doesn't trigger when the error is caught (via
|
184
|
+
# :on_error).
|
185
|
+
#
|
186
|
+
# === listen :to => :errors, :class => 'ArgumentError'
|
187
|
+
#
|
188
|
+
# One can restrict the listen to certain classes of errors.
|
189
|
+
# Passing a list of error classes separated by a comma is OK.
|
190
|
+
#
|
191
|
+
# === listen :to => :errors, :message => /x/
|
192
|
+
#
|
193
|
+
# One can restrict the error listening to errors matching a certain regex
|
194
|
+
# or equal to a certain string. The attribute is :message or :msg. The
|
195
|
+
# value is a String (strict equality) or a Regex (matching).
|
196
|
+
#
|
197
|
+
class ListenExpression < FlowExpression
|
198
|
+
|
199
|
+
names :listen, :receive, :intercept
|
200
|
+
|
201
|
+
UPONS = {
|
202
|
+
'apply' => 'dispatch', 'reply' => 'receive',
|
203
|
+
'entering' => 'entered_tag', 'leaving' => 'left_tag'
|
204
|
+
}
|
205
|
+
|
206
|
+
def apply
|
207
|
+
|
208
|
+
# gathering info
|
209
|
+
|
210
|
+
h.to = attribute(:to) || attribute(:on)
|
211
|
+
|
212
|
+
h.upon = UPONS[attribute(:upon) || 'apply']
|
213
|
+
h.upon = 'error_intercepted' if h.to == 'errors'
|
214
|
+
|
215
|
+
h.lmerge = attribute(:merge).to_s
|
216
|
+
h.lmerge = 'true' if h.lmerge == ''
|
217
|
+
|
218
|
+
h.lwfid = attribute(:wfid).to_s
|
219
|
+
h.lwfid = %w[ same current true ].include?(h.lwfid)
|
220
|
+
|
221
|
+
h.lwfid = true if h.to == 'errors'
|
222
|
+
# can only listen to errors in the same process instance
|
223
|
+
|
224
|
+
persist_or_raise
|
225
|
+
|
226
|
+
# adding a new tracker
|
227
|
+
|
228
|
+
@context.tracker.add_tracker(
|
229
|
+
h.lwfid ? h.fei['wfid'] : nil,
|
230
|
+
h.upon,
|
231
|
+
Ruote.to_storage_id(h.fei),
|
232
|
+
determine_condition,
|
233
|
+
{ 'action' => 'reply',
|
234
|
+
'fei' => h.fei,
|
235
|
+
'workitem' => 'replace',
|
236
|
+
'flavour' => 'listen' })
|
237
|
+
end
|
238
|
+
|
239
|
+
def reply(workitem)
|
240
|
+
|
241
|
+
#
|
242
|
+
# :where guard
|
243
|
+
|
244
|
+
where = attribute(:where, workitem)
|
245
|
+
return if where && ( ! Condition.true?(where))
|
246
|
+
|
247
|
+
#
|
248
|
+
# green for trigger
|
249
|
+
|
250
|
+
wi = h.applied_workitem.dup
|
251
|
+
|
252
|
+
if h.lmerge == 'true'
|
253
|
+
wi['fields'].merge!(workitem['fields'])
|
254
|
+
elsif h.lmerge == 'override'
|
255
|
+
wi['fields'] = workitem['fields']
|
256
|
+
#else don't touch
|
257
|
+
end
|
258
|
+
|
259
|
+
if tree_children.size > 0
|
260
|
+
|
261
|
+
launch_sub(
|
262
|
+
"#{h.fei['expid']}_0", tree[2][0], :forget => true, :workitem => wi)
|
263
|
+
else
|
264
|
+
|
265
|
+
reply_to_parent(wi)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
protected
|
270
|
+
|
271
|
+
# Overriding the parent's #reply_to_parent to make sure the tracker is
|
272
|
+
# removed before (expression terminating, no need for it to track anything
|
273
|
+
# anymore).
|
274
|
+
#
|
275
|
+
def reply_to_parent(workitem)
|
276
|
+
|
277
|
+
@context.tracker.remove_tracker(h.fei)
|
278
|
+
|
279
|
+
super(workitem)
|
280
|
+
end
|
281
|
+
|
282
|
+
def determine_condition
|
283
|
+
|
284
|
+
if h.upon == 'dispatch' || h.upon == 'receive'
|
285
|
+
|
286
|
+
{ 'participant_name' => h.to }
|
287
|
+
|
288
|
+
elsif h.upon == 'error_intercepted'
|
289
|
+
|
290
|
+
{
|
291
|
+
'class' => (attribute(:class) || '').split(/, */),
|
292
|
+
'message' => attribute(:message) || attribute(:msg)
|
293
|
+
}.delete_if { |k, v|
|
294
|
+
v == nil or v == []
|
295
|
+
}
|
296
|
+
|
297
|
+
else
|
298
|
+
|
299
|
+
{ 'tag' => h.to }
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|