ruote 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +166 -1
- data/CREDITS.txt +36 -17
- data/LICENSE.txt +1 -1
- data/README.rdoc +1 -7
- data/Rakefile +38 -29
- data/TODO.txt +93 -52
- data/lib/ruote-fs.rb +3 -0
- data/lib/ruote.rb +5 -1
- data/lib/ruote/context.rb +140 -35
- data/lib/ruote/dashboard.rb +1247 -0
- data/lib/ruote/{engine → dboard}/process_error.rb +22 -2
- data/lib/ruote/dboard/process_status.rb +587 -0
- data/lib/ruote/engine.rb +6 -871
- data/lib/ruote/exp/command.rb +7 -2
- data/lib/ruote/exp/commanded.rb +2 -2
- data/lib/ruote/exp/condition.rb +38 -13
- data/lib/ruote/exp/fe_add_branches.rb +1 -1
- data/lib/ruote/exp/fe_apply.rb +1 -1
- data/lib/ruote/exp/fe_await.rb +357 -0
- data/lib/ruote/exp/fe_cancel_process.rb +17 -3
- data/lib/ruote/exp/fe_command.rb +8 -4
- data/lib/ruote/exp/fe_concurrence.rb +218 -18
- data/lib/ruote/exp/fe_concurrent_iterator.rb +71 -10
- data/lib/ruote/exp/fe_cron.rb +3 -10
- data/lib/ruote/exp/fe_cursor.rb +14 -4
- data/lib/ruote/exp/fe_define.rb +3 -1
- data/lib/ruote/exp/fe_echo.rb +1 -1
- data/lib/ruote/exp/fe_equals.rb +1 -1
- data/lib/ruote/exp/fe_error.rb +1 -1
- data/lib/ruote/exp/fe_filter.rb +163 -4
- data/lib/ruote/exp/fe_forget.rb +21 -4
- data/lib/ruote/exp/fe_given.rb +1 -1
- data/lib/ruote/exp/fe_if.rb +1 -1
- data/lib/ruote/exp/fe_inc.rb +102 -35
- data/lib/ruote/exp/fe_iterator.rb +47 -12
- data/lib/ruote/exp/fe_listen.rb +96 -11
- data/lib/ruote/exp/fe_lose.rb +31 -4
- data/lib/ruote/exp/fe_noop.rb +1 -1
- data/lib/ruote/exp/fe_on_error.rb +109 -0
- data/lib/ruote/exp/fe_once.rb +10 -19
- data/lib/ruote/exp/fe_participant.rb +90 -28
- data/lib/ruote/exp/fe_read.rb +69 -0
- data/lib/ruote/exp/fe_redo.rb +3 -2
- data/lib/ruote/exp/fe_ref.rb +57 -27
- data/lib/ruote/exp/fe_registerp.rb +1 -3
- data/lib/ruote/exp/fe_reserve.rb +1 -1
- data/lib/ruote/exp/fe_restore.rb +6 -6
- data/lib/ruote/exp/fe_save.rb +12 -19
- data/lib/ruote/exp/fe_sequence.rb +38 -2
- data/lib/ruote/exp/fe_set.rb +143 -40
- data/lib/ruote/exp/{fe_let.rb → fe_stall.rb} +7 -38
- data/lib/ruote/exp/fe_subprocess.rb +8 -2
- data/lib/ruote/exp/fe_that.rb +1 -1
- data/lib/ruote/exp/fe_undo.rb +40 -4
- data/lib/ruote/exp/fe_unregisterp.rb +1 -3
- data/lib/ruote/exp/fe_wait.rb +12 -25
- data/lib/ruote/exp/{flowexpression.rb → flow_expression.rb} +375 -229
- data/lib/ruote/exp/iterator.rb +2 -2
- data/lib/ruote/exp/merge.rb +78 -17
- data/lib/ruote/exp/ro_attributes.rb +46 -36
- data/lib/ruote/exp/ro_filters.rb +34 -8
- data/lib/ruote/exp/ro_on_x.rb +431 -0
- data/lib/ruote/exp/ro_persist.rb +19 -7
- data/lib/ruote/exp/ro_timers.rb +123 -0
- data/lib/ruote/exp/ro_variables.rb +90 -29
- data/lib/ruote/fei.rb +57 -3
- data/lib/ruote/fs.rb +3 -0
- data/lib/ruote/id/mnemo_wfid_generator.rb +30 -7
- data/lib/ruote/id/wfid_generator.rb +17 -38
- data/lib/ruote/log/default_history.rb +23 -9
- data/lib/ruote/log/fancy_printing.rb +265 -0
- data/lib/ruote/log/storage_history.rb +23 -13
- data/lib/ruote/log/wait_logger.rb +224 -17
- data/lib/ruote/observer.rb +82 -0
- data/lib/ruote/part/block_participant.rb +65 -28
- data/lib/ruote/part/code_participant.rb +81 -0
- data/lib/ruote/part/engine_participant.rb +7 -2
- data/lib/ruote/part/local_participant.rb +221 -21
- data/lib/ruote/part/no_op_participant.rb +1 -1
- data/lib/ruote/part/null_participant.rb +1 -1
- data/lib/ruote/part/participant.rb +50 -0
- data/lib/ruote/part/rev_participant.rb +178 -0
- data/lib/ruote/part/smtp_participant.rb +2 -2
- data/lib/ruote/part/storage_participant.rb +228 -60
- data/lib/ruote/part/template.rb +1 -1
- data/lib/ruote/participant.rb +2 -0
- data/lib/ruote/reader.rb +205 -68
- data/lib/ruote/reader/json.rb +49 -0
- data/lib/ruote/reader/radial.rb +303 -0
- data/lib/ruote/reader/ruby_dsl.rb +44 -9
- data/lib/ruote/reader/xml.rb +11 -8
- data/lib/ruote/receiver/base.rb +98 -45
- data/lib/ruote/storage/base.rb +104 -35
- data/lib/ruote/storage/composite_storage.rb +50 -60
- data/lib/ruote/storage/fs_storage.rb +25 -34
- data/lib/ruote/storage/hash_storage.rb +38 -36
- data/lib/ruote/svc/dispatch_pool.rb +104 -35
- data/lib/ruote/svc/dollar_sub.rb +10 -8
- data/lib/ruote/svc/error_handler.rb +108 -52
- data/lib/ruote/svc/expression_map.rb +3 -3
- data/lib/ruote/svc/participant_list.rb +160 -55
- data/lib/ruote/svc/tracker.rb +31 -31
- data/lib/ruote/svc/treechecker.rb +28 -16
- data/lib/ruote/tree_dot.rb +1 -1
- data/lib/ruote/util/deep.rb +143 -0
- data/lib/ruote/util/filter.rb +125 -18
- data/lib/ruote/util/hashdot.rb +15 -13
- data/lib/ruote/util/look.rb +1 -1
- data/lib/ruote/util/lookup.rb +60 -22
- data/lib/ruote/util/misc.rb +63 -18
- data/lib/ruote/util/mpatch.rb +53 -0
- data/lib/ruote/util/ometa.rb +1 -2
- data/lib/ruote/util/process_observer.rb +177 -0
- data/lib/ruote/util/subprocess.rb +1 -1
- data/lib/ruote/util/time.rb +2 -2
- data/lib/ruote/util/tree.rb +64 -2
- data/lib/ruote/version.rb +3 -2
- data/lib/ruote/worker.rb +421 -92
- data/lib/ruote/workitem.rb +157 -22
- data/ruote.gemspec +15 -9
- data/test/bm/ci.rb +0 -2
- data/test/bm/ici.rb +0 -2
- data/test/bm/load_26c.rb +0 -3
- data/test/bm/mega.rb +0 -2
- data/test/functional/base.rb +57 -43
- data/test/functional/concurrent_base.rb +16 -13
- data/test/functional/ct_0_concurrence.rb +7 -11
- data/test/functional/ct_1_iterator.rb +9 -11
- data/test/functional/ct_2_cancel.rb +28 -17
- data/test/functional/eft_0_flow_expression.rb +35 -0
- data/test/functional/eft_10_cancel_process.rb +1 -1
- data/test/functional/eft_11_wait.rb +13 -13
- data/test/functional/eft_12_listen.rb +199 -66
- data/test/functional/eft_13_iterator.rb +95 -29
- data/test/functional/eft_14_cursor.rb +74 -24
- data/test/functional/eft_15_loop.rb +7 -7
- data/test/functional/eft_16_if.rb +1 -1
- data/test/functional/eft_17_equals.rb +1 -1
- data/test/functional/eft_18_concurrent_iterator.rb +156 -68
- data/test/functional/eft_19_reserve.rb +15 -15
- data/test/functional/eft_1_echo.rb +1 -1
- data/test/functional/eft_20_save.rb +51 -9
- data/test/functional/eft_21_restore.rb +1 -1
- data/test/functional/eft_22_noop.rb +1 -1
- data/test/functional/eft_23_apply.rb +1 -1
- data/test/functional/eft_24_add_branches.rb +7 -8
- data/test/functional/eft_25_command.rb +1 -1
- data/test/functional/eft_26_error.rb +11 -11
- data/test/functional/eft_27_inc.rb +111 -67
- data/test/functional/eft_28_once.rb +16 -16
- data/test/functional/eft_29_cron.rb +9 -9
- data/test/functional/eft_2_sequence.rb +23 -4
- data/test/functional/eft_30_ref.rb +36 -24
- data/test/functional/eft_31_registerp.rb +24 -24
- data/test/functional/eft_32_lose.rb +46 -20
- data/test/functional/eft_34_given.rb +1 -1
- data/test/functional/eft_35_filter.rb +161 -7
- data/test/functional/eft_36_read.rb +97 -0
- data/test/functional/{eft_0_process_definition.rb → eft_37_process_definition.rb} +4 -4
- data/test/functional/eft_38_on_error.rb +195 -0
- data/test/functional/eft_39_stall.rb +35 -0
- data/test/functional/eft_3_participant.rb +77 -22
- data/test/functional/eft_40_await.rb +297 -0
- data/test/functional/eft_4_set.rb +110 -11
- data/test/functional/eft_5_subprocess.rb +27 -5
- data/test/functional/eft_6_concurrence.rb +299 -60
- data/test/functional/eft_7_forget.rb +24 -22
- data/test/functional/eft_8_undo.rb +52 -15
- data/test/functional/eft_9_redo.rb +18 -20
- data/test/functional/ft_0_worker.rb +122 -13
- data/test/functional/ft_10_dollar.rb +77 -16
- data/test/functional/ft_11_recursion.rb +9 -9
- data/test/functional/ft_12_launchitem.rb +7 -9
- data/test/functional/ft_13_variables.rb +125 -22
- data/test/functional/ft_14_re_apply.rb +112 -56
- data/test/functional/ft_15_timeout.rb +64 -33
- data/test/functional/ft_16_participant_params.rb +59 -6
- data/test/functional/ft_17_conditional.rb +68 -2
- data/test/functional/ft_18_kill.rb +48 -30
- data/test/functional/ft_19_participant_code.rb +67 -0
- data/test/functional/ft_1_process_status.rb +222 -150
- data/test/functional/ft_20_storage_participant.rb +445 -44
- data/test/functional/ft_21_forget.rb +21 -26
- data/test/functional/ft_22_process_definitions.rb +8 -6
- data/test/functional/ft_23_load_defs.rb +29 -5
- data/test/functional/ft_24_block_participant.rb +199 -20
- data/test/functional/ft_25_receiver.rb +98 -46
- data/test/functional/ft_26_participant_rtimeout.rb +34 -26
- data/test/functional/ft_27_var_indirection.rb +40 -5
- data/test/functional/ft_28_null_noop_participants.rb +5 -5
- data/test/functional/ft_29_part_template.rb +2 -2
- data/test/functional/ft_2_errors.rb +106 -74
- data/test/functional/ft_30_smtp_participant.rb +7 -7
- data/test/functional/ft_31_part_blocking.rb +11 -11
- data/test/functional/ft_32_scope.rb +50 -0
- data/test/functional/ft_33_participant_subprocess_priority.rb +3 -3
- data/test/functional/ft_34_cursor_rewind.rb +14 -14
- data/test/functional/ft_35_add_service.rb +67 -9
- data/test/functional/ft_36_storage_history.rb +92 -24
- data/test/functional/ft_37_default_history.rb +35 -23
- data/test/functional/ft_38_participant_more.rb +189 -32
- data/test/functional/ft_39_wait_for.rb +25 -25
- data/test/functional/ft_3_participant_registration.rb +235 -107
- data/test/functional/ft_40_wait_logger.rb +105 -18
- data/test/functional/ft_41_participants.rb +13 -12
- data/test/functional/ft_42_storage_copy.rb +12 -12
- data/test/functional/ft_43_participant_on_reply.rb +85 -11
- data/test/functional/ft_44_var_participant.rb +5 -5
- data/test/functional/ft_45_participant_accept.rb +3 -3
- data/test/functional/ft_46_launch_single.rb +17 -17
- data/test/functional/ft_47_wfids.rb +41 -0
- data/test/functional/ft_48_lose.rb +19 -25
- data/test/functional/ft_49_engine_on_error.rb +54 -70
- data/test/functional/ft_4_cancel.rb +84 -26
- data/test/functional/ft_50_engine_config.rb +4 -4
- data/test/functional/ft_51_misc.rb +12 -12
- data/test/functional/ft_52_case.rb +17 -17
- data/test/functional/ft_53_engine_on_terminate.rb +18 -21
- data/test/functional/ft_54_patterns.rb +18 -16
- data/test/functional/ft_55_engine_participant.rb +55 -55
- data/test/functional/ft_56_filter_attribute.rb +90 -52
- data/test/functional/ft_57_rev_participant.rb +252 -0
- data/test/functional/ft_58_workitem.rb +150 -0
- data/test/functional/ft_59_pause.rb +329 -0
- data/test/functional/ft_5_on_error.rb +430 -77
- data/test/functional/ft_60_code_participant.rb +65 -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_63_participants_221.rb +458 -0
- data/test/functional/ft_64_stash.rb +41 -0
- data/test/functional/ft_65_timers.rb +313 -0
- data/test/functional/ft_66_flank.rb +133 -0
- data/test/functional/ft_67_radial_misc.rb +34 -0
- data/test/functional/ft_68_reput.rb +72 -0
- data/test/functional/ft_69_worker_info.rb +56 -0
- data/test/functional/ft_6_on_cancel.rb +189 -36
- data/test/functional/ft_70_take_and_discard_attributes.rb +94 -0
- data/test/functional/ft_71_retries.rb +144 -0
- data/test/functional/ft_72_on_terminate.rb +60 -0
- data/test/functional/ft_73_raise_msg.rb +107 -0
- data/test/functional/ft_74_respark.rb +106 -0
- data/test/functional/ft_75_context.rb +66 -0
- data/test/functional/ft_76_observer.rb +53 -0
- data/test/functional/ft_77_process_observer.rb +157 -0
- data/test/functional/ft_78_part_participant.rb +37 -0
- data/test/functional/ft_7_tags.rb +238 -50
- data/test/functional/ft_8_participant_consumption.rb +27 -21
- data/test/functional/ft_9_subprocesses.rb +48 -18
- data/test/functional/restart_base.rb +4 -6
- data/test/functional/rt_0_wait.rb +10 -10
- data/test/functional/rt_1_listen.rb +6 -6
- data/test/functional/rt_2_errors.rb +12 -12
- data/test/functional/rt_3_once.rb +17 -12
- data/test/functional/rt_4_cron.rb +17 -17
- data/test/functional/rt_5_timeout.rb +13 -13
- data/test/functional/signals.rb +103 -0
- data/test/functional/storage.rb +730 -0
- data/test/functional/storage_helper.rb +48 -35
- data/test/functional/test.rb +6 -2
- data/test/misc/idle.rb +21 -0
- data/test/misc/light.rb +29 -0
- data/test/path_helper.rb +1 -1
- data/test/test.rb +2 -5
- data/test/test_helper.rb +13 -0
- data/test/unit/test.rb +1 -4
- data/test/unit/ut_0_ruby_reader.rb +25 -9
- data/test/unit/ut_10_participants.rb +47 -0
- data/test/unit/ut_11_lookup.rb +59 -2
- data/test/unit/ut_12_wait_logger.rb +123 -0
- data/test/unit/ut_14_is_uri.rb +1 -1
- data/test/unit/ut_15_util.rb +1 -1
- data/test/unit/ut_16_reader.rb +136 -14
- data/test/unit/ut_17_merge.rb +155 -0
- data/test/unit/ut_19_part_template.rb +1 -1
- data/test/unit/ut_1_fei.rb +11 -2
- data/test/unit/ut_20_composite_storage.rb +27 -1
- data/test/unit/{ut_21_participant_list.rb → ut_21_svc_participant_list.rb} +2 -3
- data/test/unit/ut_22_filter.rb +231 -10
- data/test/unit/ut_23_svc_tracker.rb +48 -0
- data/test/unit/ut_24_radial_reader.rb +458 -0
- data/test/unit/ut_25_process_status.rb +143 -0
- data/test/unit/ut_26_deep.rb +131 -0
- data/test/unit/ut_2_dashboard.rb +114 -0
- data/test/unit/ut_3_worker.rb +54 -0
- data/test/unit/ut_4_expmap.rb +1 -1
- data/test/unit/ut_5_tree.rb +23 -23
- data/test/unit/ut_6_condition.rb +71 -29
- data/test/unit/ut_7_workitem.rb +18 -4
- data/test/unit/ut_8_tree_to_dot.rb +1 -1
- data/test/unit/ut_9_xml_reader.rb +1 -1
- metadata +142 -63
- data/jruby_issue.txt +0 -32
- data/lib/ruote/engine/process_status.rb +0 -403
- data/lib/ruote/log/pretty.rb +0 -165
- data/lib/ruote/log/test_logger.rb +0 -204
- data/lib/ruote/util/serializer.rb +0 -103
- data/phil.txt +0 -14
- data/test/functional/eft_33_let.rb +0 -31
- data/test/functional/ft_19_alias.rb +0 -33
- data/test/functional/ft_47_wfid_generator.rb +0 -54
- data/test/unit/storage.rb +0 -403
- data/test/unit/storages.rb +0 -37
- data/test/unit/ut_13_serializer.rb +0 -65
- data/test/unit/ut_18_engine.rb +0 -47
- data/test/unit/ut_3_wait_logger.rb +0 -39
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
21
|
+
#
|
|
22
|
+
# Made in Japan.
|
|
23
|
+
#++
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
require 'open-uri'
|
|
27
|
+
|
|
28
|
+
require 'ruote/part/local_participant'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
module Ruote
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# This participant was born out of a suggestion from Jan Topiński in
|
|
35
|
+
# http://groups.google.com/group/openwferu-users/browse_thread/thread/be20a5d861556fd8
|
|
36
|
+
#
|
|
37
|
+
# This participant is a gateway to code placed in a directory.
|
|
38
|
+
#
|
|
39
|
+
# engine.register do
|
|
40
|
+
# toto, Ruote::RevParticipant, :dir => 'participants/toto/'
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# Then in the participants/toto/ dir :
|
|
44
|
+
#
|
|
45
|
+
# /my_workflow__0.1__toto_0.6.rb
|
|
46
|
+
# # participant toto, workflow 'my_workflow' with revision '0.1'
|
|
47
|
+
# /my_workflow__toto.rb
|
|
48
|
+
# # participant toto, workflow 'my_workflow' any revision
|
|
49
|
+
# /toto_0.6.rb
|
|
50
|
+
# # participant toto with rev '0.6', any workflow
|
|
51
|
+
# /toto.rb
|
|
52
|
+
# # participant toto, any rev, any workflow
|
|
53
|
+
# # ...
|
|
54
|
+
#
|
|
55
|
+
# The scheme goes like :
|
|
56
|
+
#
|
|
57
|
+
# /wf-name__wf-revision__participant-name__p-revision.rb
|
|
58
|
+
#
|
|
59
|
+
# The files themselves look like :
|
|
60
|
+
#
|
|
61
|
+
# def consume(workitem)
|
|
62
|
+
# workitem.fields['kilroy'] = 'was here'
|
|
63
|
+
# reply_to_engine(workitem)
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# The file directly contains the classical participant methods defined at the
|
|
67
|
+
# top level. #cancel, #accept?, #on_reply and of course #consume are OK.
|
|
68
|
+
#
|
|
69
|
+
#
|
|
70
|
+
# Maybe, look at the tests for more clues :
|
|
71
|
+
#
|
|
72
|
+
# https://github.com/jmettraux/ruote/blob/master/test/functional/ft_57_rev_participant.rb
|
|
73
|
+
#
|
|
74
|
+
# *Note* : It's probably not the best participant in a distributed context, it
|
|
75
|
+
# grabs the code to execute from a directory. If you use it in a distributed
|
|
76
|
+
# context, you'll have to make sure to synchronize the directory to each host
|
|
77
|
+
# running a worker.
|
|
78
|
+
#
|
|
79
|
+
# *Warning* : this participant trusts the code it deals with, there is no
|
|
80
|
+
# security check.
|
|
81
|
+
#
|
|
82
|
+
class RevParticipant
|
|
83
|
+
|
|
84
|
+
include LocalParticipant
|
|
85
|
+
|
|
86
|
+
# TODO : how to deal with >= and ~> ?
|
|
87
|
+
|
|
88
|
+
def initialize(opts=nil)
|
|
89
|
+
|
|
90
|
+
@dir = opts['dir']
|
|
91
|
+
|
|
92
|
+
raise ArgumentError.new(
|
|
93
|
+
"missing option :dir for #{self.class}"
|
|
94
|
+
) unless @dir
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def on_workitem
|
|
98
|
+
|
|
99
|
+
Ruote.participant_send(
|
|
100
|
+
lookup_code,
|
|
101
|
+
[ :on_workitem, :consume ],
|
|
102
|
+
'workitem' => workitem)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def on_cancel
|
|
106
|
+
|
|
107
|
+
Ruote.participant_send(
|
|
108
|
+
lookup_code,
|
|
109
|
+
[ :on_cancel, :cancel ],
|
|
110
|
+
'fei' => fei, 'flavour' => flavour)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
#--
|
|
114
|
+
#def accept?(workitem)
|
|
115
|
+
# part = lookup_code
|
|
116
|
+
# part.respond_to?(:accept?) ? part.accept?(workitem) : true
|
|
117
|
+
#end
|
|
118
|
+
#
|
|
119
|
+
# Can't do this at this level, since it isn't the rev_participant's
|
|
120
|
+
# own accept?, it has to go in lookup_code
|
|
121
|
+
#++
|
|
122
|
+
|
|
123
|
+
def on_reply
|
|
124
|
+
|
|
125
|
+
part = lookup_code
|
|
126
|
+
|
|
127
|
+
if part.respond_to?(:on_reply)
|
|
128
|
+
Ruote.participant_send(part, :on_reply, 'workitem' => workitem)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def rtimeout(workitem)
|
|
133
|
+
|
|
134
|
+
part = lookup_code
|
|
135
|
+
|
|
136
|
+
part.respond_to?(:rtimeout) ? part.rtimeout(workitem) : nil
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
protected
|
|
140
|
+
|
|
141
|
+
# Maybe "lookup_real_participant_code" would be a better name...
|
|
142
|
+
#
|
|
143
|
+
def lookup_code
|
|
144
|
+
|
|
145
|
+
wi = workitem
|
|
146
|
+
|
|
147
|
+
rev = wi.params['revision'] || wi.params['rev']
|
|
148
|
+
|
|
149
|
+
[
|
|
150
|
+
[ wi.wf_name, wi.wf_revision, wi.participant_name, rev ],
|
|
151
|
+
[ wi.wf_name, wi.wf_revision, wi.participant_name ],
|
|
152
|
+
[ wi.wf_name, '', wi.participant_name ],
|
|
153
|
+
[ wi.participant_name, rev ],
|
|
154
|
+
[ wi.participant_name ],
|
|
155
|
+
].each do |fname|
|
|
156
|
+
|
|
157
|
+
fname = File.join(@dir, "#{fname.compact.join('__')}.rb")
|
|
158
|
+
next unless File.exist?(fname)
|
|
159
|
+
|
|
160
|
+
cpart = Class.new
|
|
161
|
+
cpart.send(:include, Ruote::LocalParticipant)
|
|
162
|
+
cpart.module_eval(File.read(fname))
|
|
163
|
+
part = cpart.new
|
|
164
|
+
part.context = @context
|
|
165
|
+
|
|
166
|
+
next if part.respond_to?(:accept?) and (not part.accept?(wi))
|
|
167
|
+
|
|
168
|
+
return part
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
raise ArgumentError.new(
|
|
172
|
+
"couldn't find code for participant #{wi.participant_name} " +
|
|
173
|
+
"in dir #{@dir}"
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2005-
|
|
2
|
+
# Copyright (c) 2005-2012, Alain Hoang and John Mettraux.
|
|
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
|
|
@@ -82,7 +82,7 @@ module Ruote
|
|
|
82
82
|
|
|
83
83
|
def initialize(opts)
|
|
84
84
|
|
|
85
|
-
@opts =
|
|
85
|
+
@opts = Ruote.keys_to_s(opts)
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def consume(workitem)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2005-
|
|
2
|
+
# Copyright (c) 2005-2012, 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
|
|
@@ -55,8 +55,6 @@ module Ruote
|
|
|
55
55
|
include LocalParticipant
|
|
56
56
|
include Enumerable
|
|
57
57
|
|
|
58
|
-
attr_accessor :context
|
|
59
|
-
|
|
60
58
|
def initialize(engine_or_options={}, options=nil)
|
|
61
59
|
|
|
62
60
|
if engine_or_options.respond_to?(:context)
|
|
@@ -76,7 +74,10 @@ module Ruote
|
|
|
76
74
|
#
|
|
77
75
|
def do_not_thread; true; end
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
# This is the method called by ruote when passing a workitem to
|
|
78
|
+
# this participant.
|
|
79
|
+
#
|
|
80
|
+
def on_workitem
|
|
80
81
|
|
|
81
82
|
doc = workitem.to_h
|
|
82
83
|
|
|
@@ -90,19 +91,39 @@ module Ruote
|
|
|
90
91
|
|
|
91
92
|
@context.storage.put(doc)
|
|
92
93
|
end
|
|
93
|
-
alias :update :consume
|
|
94
94
|
|
|
95
|
-
#
|
|
95
|
+
# Used by client code when "saving" a workitem (fields may have changed).
|
|
96
|
+
# Calling #update won't proceed the workitem.
|
|
97
|
+
#
|
|
98
|
+
# Returns nil in case of success, true if the workitem is already gone and
|
|
99
|
+
# the newer version of the workitem if the workitem changed in the mean
|
|
100
|
+
# time.
|
|
101
|
+
#
|
|
102
|
+
def update(workitem)
|
|
103
|
+
|
|
104
|
+
r = @context.storage.put(workitem.h)
|
|
105
|
+
|
|
106
|
+
r.is_a?(Hash) ? Ruote::Workitem.new(r) : r
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Removes the document/workitem from the storage.
|
|
110
|
+
#
|
|
111
|
+
# Warning: this method is called by the engine (worker), i.e. not by you.
|
|
96
112
|
#
|
|
97
|
-
def
|
|
113
|
+
def on_cancel
|
|
98
114
|
|
|
99
115
|
doc = fetch(fei)
|
|
100
116
|
|
|
117
|
+
return unless doc
|
|
118
|
+
|
|
101
119
|
r = @context.storage.delete(doc)
|
|
102
120
|
|
|
103
|
-
|
|
121
|
+
on_cancel(fei, flavour) if r != nil
|
|
104
122
|
end
|
|
105
123
|
|
|
124
|
+
# Given a fei (or its string version, a sid), returns the corresponding
|
|
125
|
+
# workitem (or nil).
|
|
126
|
+
#
|
|
106
127
|
def [](fei)
|
|
107
128
|
|
|
108
129
|
doc = fetch(fei)
|
|
@@ -110,31 +131,46 @@ module Ruote
|
|
|
110
131
|
doc ? Ruote::Workitem.new(doc) : nil
|
|
111
132
|
end
|
|
112
133
|
|
|
113
|
-
|
|
134
|
+
alias by_fei []
|
|
114
135
|
|
|
115
|
-
|
|
136
|
+
# Removes the workitem from the storage and replies to the engine.
|
|
137
|
+
#
|
|
138
|
+
def proceed(workitem)
|
|
116
139
|
|
|
117
|
-
|
|
140
|
+
r = remove_workitem('proceed', workitem)
|
|
141
|
+
|
|
142
|
+
return proceed(workitem) if r != nil
|
|
143
|
+
|
|
144
|
+
workitem.h.delete('_rev')
|
|
145
|
+
|
|
146
|
+
reply_to_engine(workitem)
|
|
118
147
|
end
|
|
119
148
|
|
|
120
|
-
# Removes the workitem
|
|
149
|
+
# Removes the workitem and hands it back to the flow with an error to
|
|
150
|
+
# raise for the participant expression that emitted the workitem.
|
|
121
151
|
#
|
|
122
|
-
|
|
123
|
-
# TODO : should it accept just the fei ?
|
|
124
|
-
#
|
|
125
|
-
def reply(workitem)
|
|
152
|
+
def flunk(workitem, err_class_or_instance, *err_arguments)
|
|
126
153
|
|
|
127
|
-
|
|
154
|
+
r = remove_workitem('reject', workitem)
|
|
128
155
|
|
|
129
|
-
|
|
156
|
+
return flunk(workitem) if r != nil
|
|
130
157
|
|
|
131
|
-
|
|
158
|
+
workitem.h.delete('_rev')
|
|
132
159
|
|
|
133
|
-
|
|
160
|
+
super(workitem, err_class_or_instance, *err_arguments)
|
|
161
|
+
end
|
|
134
162
|
|
|
135
|
-
|
|
163
|
+
# (soon to be removed)
|
|
164
|
+
#
|
|
165
|
+
def reply(workitem)
|
|
136
166
|
|
|
137
|
-
|
|
167
|
+
puts '-' * 80
|
|
168
|
+
puts '*** WARNING : please use the Ruote::StorageParticipant#proceed(wi)'
|
|
169
|
+
puts ' instead of #reply(wi) which is deprecated'
|
|
170
|
+
#caller.each { |l| puts l }
|
|
171
|
+
puts '-' * 80
|
|
172
|
+
|
|
173
|
+
proceed(workitem)
|
|
138
174
|
end
|
|
139
175
|
|
|
140
176
|
# Returns the count of workitems stored in this participant.
|
|
@@ -155,7 +191,9 @@ module Ruote
|
|
|
155
191
|
#
|
|
156
192
|
def all(opts={})
|
|
157
193
|
|
|
158
|
-
fetch_all(opts)
|
|
194
|
+
res = fetch_all(opts)
|
|
195
|
+
|
|
196
|
+
res.is_a?(Array) ? res.map { |hwi| Ruote::Workitem.new(hwi) } : res
|
|
159
197
|
end
|
|
160
198
|
|
|
161
199
|
# A convenience method (especially when testing), returns the first
|
|
@@ -163,36 +201,31 @@ module Ruote
|
|
|
163
201
|
#
|
|
164
202
|
def first
|
|
165
203
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
hwi ? Ruote::Workitem.new(hwi) : nil
|
|
204
|
+
wi(fetch_all({}).first)
|
|
169
205
|
end
|
|
170
206
|
|
|
171
207
|
# Return all workitems for the specified wfid
|
|
172
208
|
#
|
|
173
|
-
def by_wfid(wfid)
|
|
209
|
+
def by_wfid(wfid, opts={})
|
|
174
210
|
|
|
175
|
-
@context.storage.
|
|
176
|
-
|
|
177
|
-
|
|
211
|
+
if @context.storage.respond_to?(:by_wfid)
|
|
212
|
+
return @context.storage.by_wfid('workitems', wfid, opts)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
wis(@context.storage.get_many('workitems', wfid, opts))
|
|
178
216
|
end
|
|
179
217
|
|
|
180
218
|
# Returns all workitems for the specified participant name
|
|
181
219
|
#
|
|
182
220
|
def by_participant(participant_name, opts={})
|
|
183
221
|
|
|
184
|
-
|
|
222
|
+
return @context.storage.by_participant(
|
|
223
|
+
'workitems', participant_name, opts
|
|
224
|
+
) if @context.storage.respond_to?(:by_participant)
|
|
185
225
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
else
|
|
189
|
-
|
|
190
|
-
fetch_all(opts).select { |wi|
|
|
191
|
-
wi['participant_name'] == participant_name
|
|
192
|
-
}
|
|
226
|
+
do_select(opts) do |hwi|
|
|
227
|
+
hwi['participant_name'] == participant_name
|
|
193
228
|
end
|
|
194
|
-
|
|
195
|
-
hwis.collect { |hwi| Ruote::Workitem.new(hwi) }
|
|
196
229
|
end
|
|
197
230
|
|
|
198
231
|
# field : returns all the workitems with the given field name present.
|
|
@@ -204,21 +237,18 @@ module Ruote
|
|
|
204
237
|
# CouchStorage), the others will load all the workitems and then filter
|
|
205
238
|
# them.
|
|
206
239
|
#
|
|
207
|
-
def by_field(field, value=nil)
|
|
208
|
-
|
|
209
|
-
hwis = if @context.storage.respond_to?(:by_field)
|
|
240
|
+
def by_field(field, value=nil, opts={})
|
|
210
241
|
|
|
211
|
-
|
|
242
|
+
(value, opts = nil, value) if value.is_a?(Hash)
|
|
212
243
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
fetch_all.select { |hwi|
|
|
216
|
-
hwi['fields'].keys.include?(field) &&
|
|
217
|
-
(value.nil? || hwi['fields'][field] == value)
|
|
218
|
-
}
|
|
244
|
+
if @context.storage.respond_to?(:by_field)
|
|
245
|
+
return @context.storage.by_field('workitems', field, value, opts)
|
|
219
246
|
end
|
|
220
247
|
|
|
221
|
-
|
|
248
|
+
do_select(opts) do |hwi|
|
|
249
|
+
hwi['fields'].keys.include?(field) &&
|
|
250
|
+
(value.nil? || hwi['fields'][field] == value)
|
|
251
|
+
end
|
|
222
252
|
end
|
|
223
253
|
|
|
224
254
|
# Queries the store participant for workitems.
|
|
@@ -242,7 +272,7 @@ module Ruote
|
|
|
242
272
|
#
|
|
243
273
|
def query(criteria)
|
|
244
274
|
|
|
245
|
-
cr =
|
|
275
|
+
cr = Ruote.keys_to_s(criteria)
|
|
246
276
|
|
|
247
277
|
if @context.storage.respond_to?(:query_workitems)
|
|
248
278
|
return @context.storage.query_workitems(cr)
|
|
@@ -254,25 +284,29 @@ module Ruote
|
|
|
254
284
|
opts[:count] = cr.delete('count')
|
|
255
285
|
|
|
256
286
|
wfid = cr.delete('wfid')
|
|
287
|
+
|
|
288
|
+
count = opts[:count]
|
|
289
|
+
|
|
257
290
|
pname = cr.delete('participant_name') || cr.delete('participant')
|
|
291
|
+
opts.delete(:count) if pname
|
|
258
292
|
|
|
259
293
|
hwis = wfid ?
|
|
260
294
|
@context.storage.get_many('workitems', wfid, opts) : fetch_all(opts)
|
|
261
295
|
|
|
262
|
-
return hwis
|
|
296
|
+
return hwis unless hwis.is_a?(Array)
|
|
263
297
|
|
|
264
|
-
hwis.select { |hwi|
|
|
298
|
+
hwis = hwis.select { |hwi|
|
|
265
299
|
Ruote::StorageParticipant.matches?(hwi, pname, cr)
|
|
266
|
-
}.collect { |hwi|
|
|
267
|
-
Ruote::Workitem.new(hwi)
|
|
268
300
|
}
|
|
301
|
+
|
|
302
|
+
count ? hwis.size : wis(hwis)
|
|
269
303
|
end
|
|
270
304
|
|
|
271
305
|
# Cleans this participant out completely
|
|
272
306
|
#
|
|
273
307
|
def purge!
|
|
274
308
|
|
|
275
|
-
fetch_all.each { |hwi| @context.storage.delete(hwi) }
|
|
309
|
+
fetch_all({}).each { |hwi| @context.storage.delete(hwi) }
|
|
276
310
|
end
|
|
277
311
|
|
|
278
312
|
# Used by #query when filtering workitems.
|
|
@@ -295,7 +329,7 @@ module Ruote
|
|
|
295
329
|
#
|
|
296
330
|
def per_participant
|
|
297
331
|
|
|
298
|
-
|
|
332
|
+
each_with_object({}) { |wi, h| (h[wi.participant_name] ||= []) << wi }
|
|
299
333
|
end
|
|
300
334
|
|
|
301
335
|
# Mostly a test method. Returns a Hash were keys are participant names
|
|
@@ -304,15 +338,95 @@ module Ruote
|
|
|
304
338
|
#
|
|
305
339
|
def per_participant_count
|
|
306
340
|
|
|
307
|
-
per_participant.
|
|
341
|
+
per_participant.remap { |(k, v), h| h[k] = v.size }
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Claims a workitem. Returns the [updated] workitem if successful.
|
|
345
|
+
#
|
|
346
|
+
# Returns nil if the workitem is already reserved.
|
|
347
|
+
#
|
|
348
|
+
# Fails if the workitem can't be found, is gone, or got modified
|
|
349
|
+
# elsewhere.
|
|
350
|
+
#
|
|
351
|
+
# Here is a mini-diagram explaining the reserve/delegate/proceed flow:
|
|
352
|
+
#
|
|
353
|
+
# in delegate(nil) delegate(other)
|
|
354
|
+
# | +---------------+ +------+
|
|
355
|
+
# v v | | v
|
|
356
|
+
# +-------+ reserve +----------+ proceed
|
|
357
|
+
# | ready | ---------> | reserved | ---------> out
|
|
358
|
+
# +-------+ +----------+
|
|
359
|
+
#
|
|
360
|
+
def reserve(workitem_or_fei, owner)
|
|
361
|
+
|
|
362
|
+
hwi = fetch(workitem_or_fei)
|
|
363
|
+
|
|
364
|
+
fail ArgumentError.new("workitem not found") if hwi.nil?
|
|
365
|
+
|
|
366
|
+
return nil if hwi['owner'] && hwi['owner'] != owner
|
|
367
|
+
|
|
368
|
+
hwi['owner'] = owner
|
|
369
|
+
|
|
370
|
+
r = @context.storage.put(hwi, :update_rev => true)
|
|
371
|
+
|
|
372
|
+
fail ArgumentError.new("workitem is gone") if r == true
|
|
373
|
+
fail ArgumentError.new("workitem got modified meanwhile") if r != nil
|
|
374
|
+
|
|
375
|
+
Workitem.new(hwi)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# Delegates a currently owned workitem to a new owner.
|
|
379
|
+
#
|
|
380
|
+
# Fails if the workitem can't be found, belongs to noone, or if the
|
|
381
|
+
# workitem passed as argument is out of date (got modified in the mean
|
|
382
|
+
# time).
|
|
383
|
+
#
|
|
384
|
+
# It's OK to delegate to nil, thus freeing the workitem.
|
|
385
|
+
#
|
|
386
|
+
# See #reserve for an an explanation of the reserve/delegate/proceed flow.
|
|
387
|
+
#
|
|
388
|
+
def delegate(workitem, new_owner)
|
|
389
|
+
|
|
390
|
+
hwi = fetch(workitem)
|
|
391
|
+
|
|
392
|
+
fail ArgumentError.new(
|
|
393
|
+
"workitem not found"
|
|
394
|
+
) if hwi == nil
|
|
395
|
+
|
|
396
|
+
fail ArgumentError.new(
|
|
397
|
+
"cannot delegate, workitem doesn't belong to anyone"
|
|
398
|
+
) if hwi['owner'] == nil
|
|
399
|
+
|
|
400
|
+
fail ArgumentError.new(
|
|
401
|
+
"cannot delegate, " +
|
|
402
|
+
"workitem owned by '#{hwi['owner']}', not '#{workitem.owner}'"
|
|
403
|
+
) if hwi['owner'] != workitem.owner
|
|
404
|
+
|
|
405
|
+
hwi['owner'] = new_owner
|
|
406
|
+
|
|
407
|
+
r = @context.storage.put(hwi, :update_rev => true)
|
|
408
|
+
|
|
409
|
+
fail ArgumentError.new("workitem is gone") if r == true
|
|
410
|
+
fail ArgumentError.new("workitem got modified meanwhile") if r != nil
|
|
411
|
+
|
|
412
|
+
Workitem.new(hwi)
|
|
308
413
|
end
|
|
309
414
|
|
|
310
415
|
protected
|
|
311
416
|
|
|
417
|
+
# Fetches a workitem in its raw form (Hash).
|
|
418
|
+
#
|
|
419
|
+
def fetch(workitem_or_fei)
|
|
420
|
+
|
|
421
|
+
hfei = Ruote::FlowExpressionId.extract_h(workitem_or_fei)
|
|
422
|
+
|
|
423
|
+
@context.storage.get('workitems', to_id(hfei))
|
|
424
|
+
end
|
|
425
|
+
|
|
312
426
|
# Fetches all the workitems. If there is a @store_name, will only fetch
|
|
313
427
|
# the workitems in that store.
|
|
314
428
|
#
|
|
315
|
-
def fetch_all(opts
|
|
429
|
+
def fetch_all(opts)
|
|
316
430
|
|
|
317
431
|
@context.storage.get_many(
|
|
318
432
|
'workitems',
|
|
@@ -320,6 +434,26 @@ module Ruote
|
|
|
320
434
|
opts)
|
|
321
435
|
end
|
|
322
436
|
|
|
437
|
+
# Given a few options and a block, returns all the workitems that match
|
|
438
|
+
# the block
|
|
439
|
+
#
|
|
440
|
+
def do_select(opts, &block)
|
|
441
|
+
|
|
442
|
+
skip = opts[:offset] || opts[:skip]
|
|
443
|
+
limit = opts[:limit]
|
|
444
|
+
count = opts[:count]
|
|
445
|
+
|
|
446
|
+
hwis = fetch_all({})
|
|
447
|
+
hwis = hwis.select(&block)
|
|
448
|
+
|
|
449
|
+
hwis = hwis[skip..-1] if skip
|
|
450
|
+
hwis = hwis[0, limit] if limit
|
|
451
|
+
|
|
452
|
+
return hwis.size if count
|
|
453
|
+
|
|
454
|
+
hwis.collect { |hwi| Ruote::Workitem.new(hwi) }
|
|
455
|
+
end
|
|
456
|
+
|
|
323
457
|
# Computes the id for the document representing the document in the storage.
|
|
324
458
|
#
|
|
325
459
|
def to_id(fei)
|
|
@@ -332,6 +466,40 @@ module Ruote
|
|
|
332
466
|
|
|
333
467
|
a.join('!')
|
|
334
468
|
end
|
|
469
|
+
|
|
470
|
+
def wi(hwi)
|
|
471
|
+
|
|
472
|
+
hwi ? Ruote::Workitem.new(hwi) : nil
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def wis(workitems_or_count)
|
|
476
|
+
|
|
477
|
+
workitems_or_count.is_a?(Array) ?
|
|
478
|
+
workitems_or_count.collect { |wi| Ruote::Workitem.new(wi) } :
|
|
479
|
+
workitems_or_count
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def remove_workitem(action, workitem)
|
|
483
|
+
|
|
484
|
+
hwi = fetch(workitem)
|
|
485
|
+
|
|
486
|
+
fail ArgumentError.new(
|
|
487
|
+
"cannot #{action}, workitem not found"
|
|
488
|
+
) if hwi == nil
|
|
489
|
+
|
|
490
|
+
fail ArgumentError.new(
|
|
491
|
+
"cannot #{action}, " +
|
|
492
|
+
"workitem is owned by '#{hwi['owner']}', not '#{workitem.owner}'"
|
|
493
|
+
) if hwi['owner'] && hwi['owner'] != workitem.owner
|
|
494
|
+
|
|
495
|
+
r = @context.storage.delete(hwi)
|
|
496
|
+
|
|
497
|
+
fail ArgumentError.new(
|
|
498
|
+
"cannot #{action}, workitem is gone"
|
|
499
|
+
) if r == true
|
|
500
|
+
|
|
501
|
+
r
|
|
502
|
+
end
|
|
335
503
|
end
|
|
336
504
|
end
|
|
337
505
|
|