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,116 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005-2011, Alain Hoang and John Mettraux.
|
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 'net/smtp'
|
26
|
+
|
27
|
+
require 'ruote/participant'
|
28
|
+
require 'ruote/part/template'
|
29
|
+
|
30
|
+
|
31
|
+
module Ruote
|
32
|
+
|
33
|
+
#
|
34
|
+
# A very stupid SMTP participant.
|
35
|
+
#
|
36
|
+
# == options
|
37
|
+
#
|
38
|
+
# * :server - the IP address or hostname of the SMTP server/gateway (defaults to '127.0.0.1')
|
39
|
+
# * :port - the port of the SMTP server/gateway (defaults to 25)
|
40
|
+
# * :from - the from mail address (mandatory)
|
41
|
+
# * :to - the to mail address[es]
|
42
|
+
# * :template - a String template for the mail message
|
43
|
+
# * :notification - when set to true, the flow will resume immediately after having sent the email
|
44
|
+
#
|
45
|
+
#
|
46
|
+
# == :template
|
47
|
+
#
|
48
|
+
# @engine.register_participant(
|
49
|
+
# :no_good_notification,
|
50
|
+
# Ruote::SmtpParticipant,
|
51
|
+
# :server => 'smtp.example.com'
|
52
|
+
# :port => 25,
|
53
|
+
# :to => 'toto@example.com',
|
54
|
+
# :from => 'john@example.com',
|
55
|
+
# :notification => true,
|
56
|
+
# :template => "Subject: ${f:email_subject}\n\nno good.")
|
57
|
+
#
|
58
|
+
# Process variable / workitem field substitution works the same as in
|
59
|
+
# process definitions (in this example, the workitem field email_subject will
|
60
|
+
# be used as the subject of the email...)
|
61
|
+
#
|
62
|
+
#
|
63
|
+
# == :to or workitem.fields['email_target']
|
64
|
+
#
|
65
|
+
# The target of the email is either given via the workitem field
|
66
|
+
# 'email_target', either by the option :to. The workitem field takes
|
67
|
+
# precedence if both are present.
|
68
|
+
#
|
69
|
+
# This parameter/option may be either a single (string) email address, either
|
70
|
+
# an array of (string) email addresses.
|
71
|
+
#
|
72
|
+
#
|
73
|
+
# == final note : mail listener
|
74
|
+
#
|
75
|
+
# This participant cannot read POP/IMAP accounts for you. You have to
|
76
|
+
# use a mail listener or get a web reply by placing a link in the message...
|
77
|
+
#
|
78
|
+
class SmtpParticipant
|
79
|
+
|
80
|
+
include LocalParticipant
|
81
|
+
include TemplateMixin
|
82
|
+
|
83
|
+
def initialize(opts)
|
84
|
+
|
85
|
+
@opts = Ruote.keys_to_s(opts)
|
86
|
+
end
|
87
|
+
|
88
|
+
def consume(workitem)
|
89
|
+
|
90
|
+
to = workitem.fields['email_target'] || @opts['to']
|
91
|
+
to = Array(to)
|
92
|
+
|
93
|
+
text = render_template(
|
94
|
+
@opts['template'],
|
95
|
+
Ruote::Exp::FlowExpression.fetch(@context, workitem.fei.to_h),
|
96
|
+
workitem)
|
97
|
+
|
98
|
+
server = @opts['server'] || '127.0.0.1'
|
99
|
+
port = @opts['port'] || 25
|
100
|
+
|
101
|
+
Net::SMTP.start(server, port) do |smtp|
|
102
|
+
smtp.send_message(text, @opts['from'] || 'ruote@example.org', *to)
|
103
|
+
end
|
104
|
+
|
105
|
+
reply_to_engine(workitem) if @opts['notification']
|
106
|
+
end
|
107
|
+
|
108
|
+
def cancel(fei, flavour)
|
109
|
+
|
110
|
+
# does nothing
|
111
|
+
#
|
112
|
+
# one variant could send a "cancellation email"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
@@ -0,0 +1,392 @@
|
|
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/part/local_participant'
|
26
|
+
|
27
|
+
|
28
|
+
module Ruote
|
29
|
+
|
30
|
+
#
|
31
|
+
# A participant that stores the workitem in the same storage used by the
|
32
|
+
# engine and the worker(s).
|
33
|
+
#
|
34
|
+
# part = engine.register_participant 'alfred', Ruote::StorageParticipant
|
35
|
+
#
|
36
|
+
# # ... a bit later
|
37
|
+
#
|
38
|
+
# puts "workitems still open : "
|
39
|
+
# part.each do |workitem|
|
40
|
+
# puts "#{workitem.fei.wfid} - #{workitem.fields['params']['task']}"
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# # ... when done with a workitem
|
44
|
+
#
|
45
|
+
# part.reply(workitem)
|
46
|
+
# # this will remove the workitem from the storage and hand it back
|
47
|
+
# # to the engine
|
48
|
+
#
|
49
|
+
# Does not thread by default (the engine will not spawn a dedicated thread
|
50
|
+
# to handle the delivery to this participant, the workitem will get stored
|
51
|
+
# via the main engine thread and basta).
|
52
|
+
#
|
53
|
+
class StorageParticipant
|
54
|
+
|
55
|
+
include LocalParticipant
|
56
|
+
include Enumerable
|
57
|
+
|
58
|
+
def initialize(engine_or_options={}, options=nil)
|
59
|
+
|
60
|
+
if engine_or_options.respond_to?(:context)
|
61
|
+
@context = engine_or_options.context
|
62
|
+
elsif engine_or_options.is_a?(Ruote::Context)
|
63
|
+
@context = engine_or_options
|
64
|
+
else
|
65
|
+
@options = engine_or_options
|
66
|
+
end
|
67
|
+
|
68
|
+
@options ||= {}
|
69
|
+
|
70
|
+
@store_name = @options['store_name']
|
71
|
+
end
|
72
|
+
|
73
|
+
# No need for a separate thread when delivering to this participant.
|
74
|
+
#
|
75
|
+
def do_not_thread; true; end
|
76
|
+
|
77
|
+
# This is the method called by ruote when passing a workitem to
|
78
|
+
# this participant.
|
79
|
+
#
|
80
|
+
def consume(workitem)
|
81
|
+
|
82
|
+
doc = workitem.to_h
|
83
|
+
|
84
|
+
doc.merge!(
|
85
|
+
'type' => 'workitems',
|
86
|
+
'_id' => to_id(doc['fei']),
|
87
|
+
'participant_name' => doc['participant_name'],
|
88
|
+
'wfid' => doc['fei']['wfid'])
|
89
|
+
|
90
|
+
doc['store_name'] = @store_name if @store_name
|
91
|
+
|
92
|
+
@context.storage.put(doc)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Though #update is an alias to #consume, it is meant to be used by
|
96
|
+
# client code when "saving" a workitem (fields may have changed). Calling
|
97
|
+
# update won't proceed the workitem.
|
98
|
+
#
|
99
|
+
alias update consume
|
100
|
+
|
101
|
+
# Removes the document/workitem from the storage
|
102
|
+
#
|
103
|
+
def cancel(fei, flavour)
|
104
|
+
|
105
|
+
doc = fetch(fei)
|
106
|
+
|
107
|
+
r = @context.storage.delete(doc)
|
108
|
+
|
109
|
+
cancel(fei, flavour) if r != nil
|
110
|
+
end
|
111
|
+
|
112
|
+
# Given a fei (or its string version, a sid), returns the corresponding
|
113
|
+
# workitem (or nil).
|
114
|
+
#
|
115
|
+
def [](fei)
|
116
|
+
|
117
|
+
doc = fetch(fei)
|
118
|
+
|
119
|
+
doc ? Ruote::Workitem.new(doc) : nil
|
120
|
+
end
|
121
|
+
|
122
|
+
alias by_fei []
|
123
|
+
|
124
|
+
# Removes the workitem from the storage and replies to the engine.
|
125
|
+
#
|
126
|
+
# TODO : should it raise if the workitem can't be found ?
|
127
|
+
# TODO : should it accept just the fei ?
|
128
|
+
#
|
129
|
+
def proceed(workitem)
|
130
|
+
|
131
|
+
doc = fetch(Ruote::FlowExpressionId.extract_h(workitem))
|
132
|
+
|
133
|
+
r = @context.storage.delete(doc)
|
134
|
+
|
135
|
+
raise ArgumentError.new('cannot proceed, workitem is gone') if r == true
|
136
|
+
return proceed(workitem) if r != nil
|
137
|
+
|
138
|
+
workitem.h.delete('_rev')
|
139
|
+
|
140
|
+
reply_to_engine(workitem)
|
141
|
+
end
|
142
|
+
|
143
|
+
# (soon to be removed)
|
144
|
+
#
|
145
|
+
def reply(workitem)
|
146
|
+
|
147
|
+
puts '-' * 80
|
148
|
+
puts '*** WARNING : please use the Ruote::StorageParticipant#proceed(wi)'
|
149
|
+
puts ' instead of #reply(wi) which is deprecated'
|
150
|
+
#caller.each { |l| puts l }
|
151
|
+
puts '-' * 80
|
152
|
+
|
153
|
+
proceed(workitem)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Returns the count of workitems stored in this participant.
|
157
|
+
#
|
158
|
+
def size
|
159
|
+
|
160
|
+
fetch_all(:count => true)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Iterates over the workitems stored in here.
|
164
|
+
#
|
165
|
+
def each(&block)
|
166
|
+
|
167
|
+
all.each { |wi| block.call(wi) }
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns all the workitems stored in here.
|
171
|
+
#
|
172
|
+
def all(opts={})
|
173
|
+
|
174
|
+
res = fetch_all(opts)
|
175
|
+
|
176
|
+
res.is_a?(Array) ? res.map { |hwi| Ruote::Workitem.new(hwi) } : res
|
177
|
+
end
|
178
|
+
|
179
|
+
# A convenience method (especially when testing), returns the first
|
180
|
+
# (only ?) workitem in the participant.
|
181
|
+
#
|
182
|
+
def first
|
183
|
+
|
184
|
+
wi(fetch_all({}).first)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Return all workitems for the specified wfid
|
188
|
+
#
|
189
|
+
def by_wfid(wfid, opts={})
|
190
|
+
|
191
|
+
if @context.storage.respond_to?(:by_wfid)
|
192
|
+
return @context.storage.by_wfid('workitems', wfid, opts)
|
193
|
+
end
|
194
|
+
|
195
|
+
wis(@context.storage.get_many('workitems', wfid, opts))
|
196
|
+
end
|
197
|
+
|
198
|
+
# Returns all workitems for the specified participant name
|
199
|
+
#
|
200
|
+
def by_participant(participant_name, opts={})
|
201
|
+
|
202
|
+
return @context.storage.by_participant(
|
203
|
+
'workitems', participant_name, opts
|
204
|
+
) if @context.storage.respond_to?(:by_participant)
|
205
|
+
|
206
|
+
do_select(opts) do |hwi|
|
207
|
+
hwi['participant_name'] == participant_name
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# field : returns all the workitems with the given field name present.
|
212
|
+
#
|
213
|
+
# field and value : returns all the workitems with the given field name
|
214
|
+
# and the given value for that field.
|
215
|
+
#
|
216
|
+
# Warning : only some storages are optimized for such queries (like
|
217
|
+
# CouchStorage), the others will load all the workitems and then filter
|
218
|
+
# them.
|
219
|
+
#
|
220
|
+
def by_field(field, value=nil, opts={})
|
221
|
+
|
222
|
+
(value, opts = nil, value) if value.is_a?(Hash)
|
223
|
+
|
224
|
+
if @context.storage.respond_to?(:by_field)
|
225
|
+
return @context.storage.by_field('workitems', field, value, opts)
|
226
|
+
end
|
227
|
+
|
228
|
+
do_select(opts) do |hwi|
|
229
|
+
hwi['fields'].keys.include?(field) &&
|
230
|
+
(value.nil? || hwi['fields'][field] == value)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Queries the store participant for workitems.
|
235
|
+
#
|
236
|
+
# Some examples :
|
237
|
+
#
|
238
|
+
# part.query(:wfid => @wfid).size
|
239
|
+
# part.query('place' => 'nara').size
|
240
|
+
# part.query('place' => 'heiankyou').size
|
241
|
+
# part.query(:wfid => @wfid, :place => 'heiankyou').size
|
242
|
+
#
|
243
|
+
# There are two 'reserved' criterion : 'wfid' and 'participant'
|
244
|
+
# ('participant_name' as well). The rest of the criteria are considered
|
245
|
+
# constraints for fields.
|
246
|
+
#
|
247
|
+
# 'offset' and 'limit' are reserved as well. They should prove useful
|
248
|
+
# for pagination. 'skip' can be used instead of 'offset'.
|
249
|
+
#
|
250
|
+
# Note : the criteria is AND only, you'll have to do ORs (aggregation)
|
251
|
+
# by yourself.
|
252
|
+
#
|
253
|
+
def query(criteria)
|
254
|
+
|
255
|
+
cr = Ruote.keys_to_s(criteria)
|
256
|
+
|
257
|
+
if @context.storage.respond_to?(:query_workitems)
|
258
|
+
return @context.storage.query_workitems(cr)
|
259
|
+
end
|
260
|
+
|
261
|
+
opts = {}
|
262
|
+
opts[:skip] = cr.delete('offset') || cr.delete('skip')
|
263
|
+
opts[:limit] = cr.delete('limit')
|
264
|
+
opts[:count] = cr.delete('count')
|
265
|
+
|
266
|
+
wfid = cr.delete('wfid')
|
267
|
+
|
268
|
+
count = opts[:count]
|
269
|
+
|
270
|
+
pname = cr.delete('participant_name') || cr.delete('participant')
|
271
|
+
opts.delete(:count) if pname
|
272
|
+
|
273
|
+
hwis = wfid ?
|
274
|
+
@context.storage.get_many('workitems', wfid, opts) : fetch_all(opts)
|
275
|
+
|
276
|
+
return hwis unless hwis.is_a?(Array)
|
277
|
+
|
278
|
+
hwis = hwis.select { |hwi|
|
279
|
+
Ruote::StorageParticipant.matches?(hwi, pname, cr)
|
280
|
+
}
|
281
|
+
|
282
|
+
count ? hwis.size : wis(hwis)
|
283
|
+
end
|
284
|
+
|
285
|
+
# Cleans this participant out completely
|
286
|
+
#
|
287
|
+
def purge!
|
288
|
+
|
289
|
+
fetch_all({}).each { |hwi| @context.storage.delete(hwi) }
|
290
|
+
end
|
291
|
+
|
292
|
+
# Used by #query when filtering workitems.
|
293
|
+
#
|
294
|
+
def self.matches?(hwi, pname, criteria)
|
295
|
+
|
296
|
+
return false if pname && hwi['participant_name'] != pname
|
297
|
+
|
298
|
+
fields = hwi['fields']
|
299
|
+
|
300
|
+
criteria.each do |fname, fvalue|
|
301
|
+
return false if fields[fname] != fvalue
|
302
|
+
end
|
303
|
+
|
304
|
+
true
|
305
|
+
end
|
306
|
+
|
307
|
+
# Mostly a test method. Returns a Hash were keys are participant names
|
308
|
+
# and values are lists of workitems.
|
309
|
+
#
|
310
|
+
def per_participant
|
311
|
+
|
312
|
+
inject({}) { |h, wi| (h[wi.participant_name] ||= []) << wi; h }
|
313
|
+
end
|
314
|
+
|
315
|
+
# Mostly a test method. Returns a Hash were keys are participant names
|
316
|
+
# and values are integers, the count of workitems for a given participant
|
317
|
+
# name.
|
318
|
+
#
|
319
|
+
def per_participant_count
|
320
|
+
|
321
|
+
per_participant.inject({}) { |h, (k, v)| h[k] = v.size; h }
|
322
|
+
end
|
323
|
+
|
324
|
+
protected
|
325
|
+
|
326
|
+
# Fetches a workitem in its raw form (Hash).
|
327
|
+
#
|
328
|
+
def fetch(fei)
|
329
|
+
|
330
|
+
hfei = Ruote::FlowExpressionId.extract_h(fei)
|
331
|
+
|
332
|
+
@context.storage.get('workitems', to_id(hfei))
|
333
|
+
end
|
334
|
+
|
335
|
+
# Fetches all the workitems. If there is a @store_name, will only fetch
|
336
|
+
# the workitems in that store.
|
337
|
+
#
|
338
|
+
def fetch_all(opts)
|
339
|
+
|
340
|
+
@context.storage.get_many(
|
341
|
+
'workitems',
|
342
|
+
@store_name ? /^wi!#{@store_name}::/ : nil,
|
343
|
+
opts)
|
344
|
+
end
|
345
|
+
|
346
|
+
# Given a few options and a block, returns all the workitems that match
|
347
|
+
# the block
|
348
|
+
#
|
349
|
+
def do_select(opts, &block)
|
350
|
+
|
351
|
+
skip = opts[:offset] || opts[:skip]
|
352
|
+
limit = opts[:limit]
|
353
|
+
count = opts[:count]
|
354
|
+
|
355
|
+
hwis = fetch_all({})
|
356
|
+
hwis = hwis.select(&block)
|
357
|
+
|
358
|
+
hwis = hwis[skip..-1] if skip
|
359
|
+
hwis = hwis[0, limit] if limit
|
360
|
+
|
361
|
+
return hwis.size if count
|
362
|
+
|
363
|
+
hwis.collect { |hwi| Ruote::Workitem.new(hwi) }
|
364
|
+
end
|
365
|
+
|
366
|
+
# Computes the id for the document representing the document in the storage.
|
367
|
+
#
|
368
|
+
def to_id(fei)
|
369
|
+
|
370
|
+
a = [ Ruote.to_storage_id(fei) ]
|
371
|
+
|
372
|
+
a.unshift(@store_name) if @store_name
|
373
|
+
|
374
|
+
a.unshift('wi')
|
375
|
+
|
376
|
+
a.join('!')
|
377
|
+
end
|
378
|
+
|
379
|
+
def wi(hwi)
|
380
|
+
|
381
|
+
hwi ? Ruote::Workitem.new(hwi) : nil
|
382
|
+
end
|
383
|
+
|
384
|
+
def wis(workitems_or_count)
|
385
|
+
|
386
|
+
workitems_or_count.is_a?(Array) ?
|
387
|
+
workitems_or_count.collect { |wi| Ruote::Workitem.new(wi) } :
|
388
|
+
workitems_or_count
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|