ruote 0.9.18
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/README.txt +24 -0
- data/bin/validate-workflow.rb +89 -0
- data/examples/about_state.rb +81 -0
- data/examples/bigflow.rb +19 -0
- data/examples/csv_weather.rb +23 -0
- data/examples/engine_template.rb +247 -0
- data/examples/flowtracing.rb +24 -0
- data/examples/homeworkreview.rb +68 -0
- data/examples/kotoba.rb +22 -0
- data/examples/mano_tracker.rb +172 -0
- data/examples/openwferu.rb +58 -0
- data/examples/quotereporter.rb +157 -0
- data/examples/scheduler_cron_usage.rb +48 -0
- data/examples/scheduler_usage.rb +56 -0
- data/lib/openwfe.rb +41 -0
- data/lib/openwfe/contextual.rb +111 -0
- data/lib/openwfe/def.rb +46 -0
- data/lib/openwfe/engine.rb +37 -0
- data/lib/openwfe/engine/engine.rb +756 -0
- data/lib/openwfe/engine/expool_methods.rb +172 -0
- data/lib/openwfe/engine/file_persisted_engine.rb +105 -0
- data/lib/openwfe/engine/participant_methods.rb +133 -0
- data/lib/openwfe/engine/status_methods.rb +353 -0
- data/lib/openwfe/engine/update_exp_methods.rb +112 -0
- data/lib/openwfe/exceptions.rb +51 -0
- data/lib/openwfe/expool/errorjournal.rb +476 -0
- data/lib/openwfe/expool/expressionpool.rb +1144 -0
- data/lib/openwfe/expool/expstorage.rb +403 -0
- data/lib/openwfe/expool/history.rb +174 -0
- data/lib/openwfe/expool/journal.rb +224 -0
- data/lib/openwfe/expool/journal_replay.rb +321 -0
- data/lib/openwfe/expool/parser.rb +242 -0
- data/lib/openwfe/expool/representation.rb +121 -0
- data/lib/openwfe/expool/threadedexpstorage.rb +188 -0
- data/lib/openwfe/expool/wfidgen.rb +388 -0
- data/lib/openwfe/expool/yamlexpstorage.rb +224 -0
- data/lib/openwfe/expressions/condition.rb +244 -0
- data/lib/openwfe/expressions/environment.rb +246 -0
- data/lib/openwfe/expressions/expressionmap.rb +258 -0
- data/lib/openwfe/expressions/fe_cancel.rb +109 -0
- data/lib/openwfe/expressions/fe_command.rb +241 -0
- data/lib/openwfe/expressions/fe_concurrence.rb +662 -0
- data/lib/openwfe/expressions/fe_cron.rb +259 -0
- data/lib/openwfe/expressions/fe_cursor.rb +259 -0
- data/lib/openwfe/expressions/fe_define.rb +192 -0
- data/lib/openwfe/expressions/fe_do.rb +168 -0
- data/lib/openwfe/expressions/fe_equals.rb +291 -0
- data/lib/openwfe/expressions/fe_filter.rb +129 -0
- data/lib/openwfe/expressions/fe_filter_definition.rb +168 -0
- data/lib/openwfe/expressions/fe_fqv.rb +250 -0
- data/lib/openwfe/expressions/fe_if.rb +303 -0
- data/lib/openwfe/expressions/fe_iterator.rb +145 -0
- data/lib/openwfe/expressions/fe_listen.rb +371 -0
- data/lib/openwfe/expressions/fe_losfor.rb +111 -0
- data/lib/openwfe/expressions/fe_misc.rb +421 -0
- data/lib/openwfe/expressions/fe_participant.rb +269 -0
- data/lib/openwfe/expressions/fe_reserve.rb +212 -0
- data/lib/openwfe/expressions/fe_save.rb +274 -0
- data/lib/openwfe/expressions/fe_sequence.rb +117 -0
- data/lib/openwfe/expressions/fe_set.rb +139 -0
- data/lib/openwfe/expressions/fe_sleep.rb +166 -0
- data/lib/openwfe/expressions/fe_step.rb +159 -0
- data/lib/openwfe/expressions/fe_subprocess.rb +168 -0
- data/lib/openwfe/expressions/fe_timeout.rb +127 -0
- data/lib/openwfe/expressions/fe_wait.rb +78 -0
- data/lib/openwfe/expressions/fe_when.rb +142 -0
- data/lib/openwfe/expressions/filter.rb +104 -0
- data/lib/openwfe/expressions/flowexpression.rb +847 -0
- data/lib/openwfe/expressions/iterator.rb +221 -0
- data/lib/openwfe/expressions/merge.rb +84 -0
- data/lib/openwfe/expressions/raw.rb +547 -0
- data/lib/openwfe/expressions/rprocdef.rb +375 -0
- data/lib/openwfe/expressions/time.rb +333 -0
- data/lib/openwfe/expressions/timeout.rb +178 -0
- data/lib/openwfe/expressions/value.rb +126 -0
- data/lib/openwfe/filterdef.rb +259 -0
- data/lib/openwfe/flowexpressionid.rb +357 -0
- data/lib/openwfe/listeners/listener.rb +97 -0
- data/lib/openwfe/listeners/listeners.rb +139 -0
- data/lib/openwfe/listeners/socketlisteners.rb +272 -0
- data/lib/openwfe/logging.rb +122 -0
- data/lib/openwfe/omixins.rb +95 -0
- data/lib/openwfe/orest/controlclient.rb +119 -0
- data/lib/openwfe/orest/definitions.rb +113 -0
- data/lib/openwfe/orest/exception.rb +60 -0
- data/lib/openwfe/orest/oldrestservlet.rb +279 -0
- data/lib/openwfe/orest/osocket.rb +148 -0
- data/lib/openwfe/orest/restclient.rb +176 -0
- data/lib/openwfe/orest/workitem.rb +206 -0
- data/lib/openwfe/orest/worklistclient.rb +272 -0
- data/lib/openwfe/orest/xmlcodec.rb +670 -0
- data/lib/openwfe/participants.rb +38 -0
- data/lib/openwfe/participants/enoparticipants.rb +230 -0
- data/lib/openwfe/participants/participant.rb +141 -0
- data/lib/openwfe/participants/participantmap.rb +249 -0
- data/lib/openwfe/participants/participants.rb +407 -0
- data/lib/openwfe/participants/soapparticipants.rb +135 -0
- data/lib/openwfe/participants/socketparticipants.rb +202 -0
- data/lib/openwfe/participants/storeparticipants.rb +254 -0
- data/lib/openwfe/rudefinitions.rb +130 -0
- data/lib/openwfe/service.rb +103 -0
- data/lib/openwfe/storage/yamlcustom.rb +106 -0
- data/lib/openwfe/storage/yamlfilestorage.rb +245 -0
- data/lib/openwfe/tools/flowtracer.rb +81 -0
- data/lib/openwfe/util/dollar.rb +217 -0
- data/lib/openwfe/util/irb.rb +86 -0
- data/lib/openwfe/util/observable.rb +144 -0
- data/lib/openwfe/util/ometa.rb +62 -0
- data/lib/openwfe/util/workqueue.rb +124 -0
- data/lib/openwfe/util/xml.rb +418 -0
- data/lib/openwfe/utils.rb +554 -0
- data/lib/openwfe/version.rb +37 -0
- data/lib/openwfe/workitem.rb +499 -0
- data/lib/openwfe/worklist/oldrest.rb +244 -0
- data/lib/openwfe/worklist/storelocks.rb +293 -0
- data/lib/openwfe/worklist/storeparticipant.rb +44 -0
- data/lib/openwfe/worklist/worklist.rb +297 -0
- data/test/README.txt +27 -0
- data/test/back_0916_test.rb +111 -0
- data/test/bm/bm_1_xml_vs_prog.rb +56 -0
- data/test/bm/bm_2_step.rb +109 -0
- data/test/bm/ft_0f_5ms.rb +35 -0
- data/test/bm/ft_26_load.rb +210 -0
- data/test/bm/ft_26b_load.rb +86 -0
- data/test/bm/ft_26c_load.rb +97 -0
- data/test/bm/ft_26d_load.rb +97 -0
- data/test/bm/ft_recu.rb +71 -0
- data/test/clone_test.rb +122 -0
- data/test/concurrence_test.rb +77 -0
- data/test/condition_test.rb +155 -0
- data/test/console_test.rb +12 -0
- data/test/cron_ltest.rb +15 -0
- data/test/description_test.rb +87 -0
- data/test/eno_test.rb +76 -0
- data/test/expmap_test.rb +54 -0
- data/test/expool_20031219_0916.tgz +0 -0
- data/test/fe_lookup_att_test.rb +62 -0
- data/test/fei_test.rb +181 -0
- data/test/file_persisted_engine_test.rb +64 -0
- data/test/file_persistence_test.rb +134 -0
- data/test/filep_cancel_test.rb +123 -0
- data/test/filter_test.rb +109 -0
- data/test/flowtestbase.rb +351 -0
- data/test/ft_0.rb +68 -0
- data/test/ft_0b_sequence.rb +36 -0
- data/test/ft_0c_testname.rb +33 -0
- data/test/ft_0d_participant.rb +30 -0
- data/test/ft_0e_multibody.rb +34 -0
- data/test/ft_10_loop.rb +134 -0
- data/test/ft_11_ppd.rb +415 -0
- data/test/ft_11b_ppd.rb +54 -0
- data/test/ft_12_blockparticipant.rb +97 -0
- data/test/ft_13_eno.rb +52 -0
- data/test/ft_14_subprocess.rb +88 -0
- data/test/ft_14b_subprocess.rb +192 -0
- data/test/ft_14c_subprocess.rb +68 -0
- data/test/ft_15_iterator.rb +216 -0
- data/test/ft_15b_iterator.rb +74 -0
- data/test/ft_16_fqv.rb +73 -0
- data/test/ft_17_condition.rb +84 -0
- data/test/ft_18_pname.rb +56 -0
- data/test/ft_1_unset.rb +175 -0
- data/test/ft_1b_unset.rb +39 -0
- data/test/ft_20_cron.rb +53 -0
- data/test/ft_21_cron.rb +87 -0
- data/test/ft_21b_cron_pause.rb +82 -0
- data/test/ft_22_history.rb +74 -0
- data/test/ft_23_when.rb +77 -0
- data/test/ft_23b_when.rb +70 -0
- data/test/ft_23c_wait.rb +80 -0
- data/test/ft_23d_cww.rb +58 -0
- data/test/ft_24_def.rb +44 -0
- data/test/ft_25_cancel.rb +89 -0
- data/test/ft_27_getflowpos.rb +147 -0
- data/test/ft_28_fileparticipant.rb +63 -0
- data/test/ft_29_httprb.rb +106 -0
- data/test/ft_2_concurrence.rb +135 -0
- data/test/ft_2b_concurrence.rb +188 -0
- data/test/ft_2c_concurrence.rb +64 -0
- data/test/ft_30_socketlistener.rb +203 -0
- data/test/ft_31_flowname.rb +40 -0
- data/test/ft_32_journal.rb +91 -0
- data/test/ft_32c_journal.rb +102 -0
- data/test/ft_32d_journal.rb +84 -0
- data/test/ft_33_description.rb +107 -0
- data/test/ft_34_cancelwfid.rb +80 -0
- data/test/ft_35_localdefs.rb +75 -0
- data/test/ft_36_subprocids.rb +97 -0
- data/test/ft_37_pnames.rb +70 -0
- data/test/ft_38_tag.rb +127 -0
- data/test/ft_38b_tag.rb +161 -0
- data/test/ft_38c_tag.rb +100 -0
- data/test/ft_39_reserve.rb +63 -0
- data/test/ft_39b_reserve.rb +84 -0
- data/test/ft_3_equals.rb +170 -0
- data/test/ft_3b_lookup_vf.rb +83 -0
- data/test/ft_40_defined.rb +61 -0
- data/test/ft_41_case.rb +110 -0
- data/test/ft_42_environments.rb +75 -0
- data/test/ft_43_pat10.rb +85 -0
- data/test/ft_44_save.rb +70 -0
- data/test/ft_44b_restore.rb +212 -0
- data/test/ft_45_citerator.rb +214 -0
- data/test/ft_46_pparams.rb +62 -0
- data/test/ft_47_filter.rb +160 -0
- data/test/ft_48_fe_filter.rb +88 -0
- data/test/ft_49_condition.rb +126 -0
- data/test/ft_4_misc.rb +237 -0
- data/test/ft_50_xml_attribute.rb +155 -0
- data/test/ft_51_stack.rb +55 -0
- data/test/ft_52_obs_participant.rb +123 -0
- data/test/ft_53_null_noop_participant.rb +62 -0
- data/test/ft_54_listen.rb +288 -0
- data/test/ft_54b_listen.rb +66 -0
- data/test/ft_54c_listen.rb +99 -0
- data/test/ft_55_ptimeout.rb +59 -0
- data/test/ft_56_timeout.rb +59 -0
- data/test/ft_57_a.rb +145 -0
- data/test/ft_58_ejournal.rb +151 -0
- data/test/ft_59_ps.rb +150 -0
- data/test/ft_59b_ps_for_pat.rb +58 -0
- data/test/ft_5_time.rb +118 -0
- data/test/ft_60_ecancel.rb +161 -0
- data/test/ft_61_elsub.rb +51 -0
- data/test/ft_62_procparticipant.rb +71 -0
- data/test/ft_63_pause.rb +124 -0
- data/test/ft_64_alias.rb +102 -0
- data/test/ft_64_clone.rb +69 -0
- data/test/ft_65_stringlaunch.rb +59 -0
- data/test/ft_66_subforget.rb +70 -0
- data/test/ft_67_schedlaunch.rb +116 -0
- data/test/ft_68_ifparticipant.rb +70 -0
- data/test/ft_69_cancelmissing.rb +51 -0
- data/test/ft_6_lambda.rb +64 -0
- data/test/ft_70_lookupvar.rb +55 -0
- data/test/ft_71_log.rb +60 -0
- data/test/ft_72_lookup_processes.rb +76 -0
- data/test/ft_73_cancel_sub.rb +139 -0
- data/test/ft_74_block_and_workitem_dup.rb +63 -0
- data/test/ft_75_ruby_attributes.rb +87 -0
- data/test/ft_76_merge_isolate.rb +88 -0
- data/test/ft_77_segments.rb +35 -0
- data/test/ft_78_eval.rb +150 -0
- data/test/ft_79_tticket.rb +187 -0
- data/test/ft_79b_tticket.rb +172 -0
- data/test/ft_79c_outcome.rb +56 -0
- data/test/ft_7_lose.rb +104 -0
- data/test/ft_7b_lose.rb +78 -0
- data/test/ft_80_spname.rb +91 -0
- data/test/ft_81_exp.rb +60 -0
- data/test/ft_82_trecu.rb +46 -0
- data/test/ft_83_badpause.rb +58 -0
- data/test/ft_84_updateexp.rb +198 -0
- data/test/ft_85_dolhash.rb +43 -0
- data/test/ft_86_dollar_fv.rb +68 -0
- data/test/ft_87_define.rb +74 -0
- data/test/ft_8_forget.rb +44 -0
- data/test/ft_9_cursor.rb +145 -0
- data/test/ft_9b_cursor.rb +105 -0
- data/test/ft_tests.rb +124 -0
- data/test/hash_test.rb +75 -0
- data/test/hparticipant_test.rb +164 -0
- data/test/lookup_att_test.rb +90 -0
- data/test/lookup_vf_test.rb +94 -0
- data/test/misc_test.rb +90 -0
- data/test/nut_0_irb.rb +20 -0
- data/test/obs_test.rb +142 -0
- data/test/orest_test.rb +251 -0
- data/test/param_test.rb +290 -0
- data/test/participant_test.rb +101 -0
- data/test/pending.rb +23 -0
- data/test/ps_representation.rb +133 -0
- data/test/rake_ltest.rb +38 -0
- data/test/rake_qtest.rb +68 -0
- data/test/raw_prog_test.rb +412 -0
- data/test/restart_cron_test.rb +136 -0
- data/test/restart_paused_test.rb +98 -0
- data/test/restart_sleep_test.rb +140 -0
- data/test/restart_tests.rb +18 -0
- data/test/restart_when_test.rb +112 -0
- data/test/ruby_procdef_test.rb +132 -0
- data/test/rutest_utils.rb +63 -0
- data/test/sec_test.rb +205 -0
- data/test/slock_test.rb +80 -0
- data/test/storage_test.rb +44 -0
- data/test/test.rb +3 -0
- data/test/timeout_test.rb +105 -0
- data/test/util_xml_test.rb +112 -0
- data/test/wfid_test.rb +175 -0
- data/test/wi_test.rb +75 -0
- metadata +433 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#
|
|
2
|
+
#--
|
|
3
|
+
# Copyright (c) 2007, John Mettraux, OpenWFE.org
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
|
8
|
+
#
|
|
9
|
+
# . Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
# list of conditions and the following disclaimer.
|
|
11
|
+
#
|
|
12
|
+
# . Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
# and/or other materials provided with the distribution.
|
|
15
|
+
#
|
|
16
|
+
# . Neither the name of the "OpenWFE" nor the names of its contributors may be
|
|
17
|
+
# used to endorse or promote products derived from this software without
|
|
18
|
+
# specific prior written permission.
|
|
19
|
+
#
|
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
|
31
|
+
#++
|
|
32
|
+
#
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
# "made in Japan"
|
|
36
|
+
#
|
|
37
|
+
# John Mettraux at openwfe.org
|
|
38
|
+
#
|
|
39
|
+
|
|
40
|
+
require 'rexml/element'
|
|
41
|
+
require 'openwfe/orest/xmlcodec'
|
|
42
|
+
require 'openwfe/orest/oldrestservlet'
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
module OpenWFE
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# This webrick servlet provides a REST interface for an old style
|
|
49
|
+
# OpenWFE worklist.
|
|
50
|
+
#
|
|
51
|
+
class OldRestWorklistServlet < OldRestServlet
|
|
52
|
+
|
|
53
|
+
def initialize (server, params)
|
|
54
|
+
super
|
|
55
|
+
@worklist = params[:Worklist]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# The realm for HTTP authentication.
|
|
60
|
+
#
|
|
61
|
+
def get_realm_name
|
|
62
|
+
"worklist"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Lists the stores in the worklist
|
|
67
|
+
#
|
|
68
|
+
def do__getstorenames (req, res)
|
|
69
|
+
|
|
70
|
+
e = REXML::Element.new 'stores'
|
|
71
|
+
|
|
72
|
+
@worklist.each_store do |regex, store_name, store|
|
|
73
|
+
|
|
74
|
+
perms = @worklist.get_permissions(
|
|
75
|
+
req.attributes['username'], store_name)
|
|
76
|
+
|
|
77
|
+
es = REXML::Element.new 'store'
|
|
78
|
+
es.add_attribute 'name', store_name
|
|
79
|
+
es.add_attribute 'workitem-count', store.size
|
|
80
|
+
es.add_attribute 'permissions', perms
|
|
81
|
+
e << es
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
reply_with_xml res, 200, e
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
alias :do__liststores :do__getstorenames
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# This implementation simply encodes the workitem, no transformation
|
|
91
|
+
# into headers at all.
|
|
92
|
+
#
|
|
93
|
+
def do__getheaders (req, res)
|
|
94
|
+
|
|
95
|
+
limit = req.query['limit']
|
|
96
|
+
limit = limit.to_s.to_i if limit
|
|
97
|
+
limit = nil if limit and limit < 1
|
|
98
|
+
|
|
99
|
+
hs = @worklist.get_headers(
|
|
100
|
+
req.attributes['username'],
|
|
101
|
+
get_store_name(req),
|
|
102
|
+
limit)
|
|
103
|
+
|
|
104
|
+
# TODO raise "404 no store named '#{store_name}'" unless store
|
|
105
|
+
# TODO raise "403 forbidden"
|
|
106
|
+
|
|
107
|
+
e = REXML::Element.new 'headers'
|
|
108
|
+
|
|
109
|
+
hs.each do |h|
|
|
110
|
+
|
|
111
|
+
workitem, locked = h
|
|
112
|
+
|
|
113
|
+
e << OpenWFE::XmlCodec::encode_workitem_as_header(
|
|
114
|
+
workitem, locked)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
reply_with_xml res, 200, e
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
#
|
|
121
|
+
# Launches a new process instance.
|
|
122
|
+
#
|
|
123
|
+
def do__launchflow (req, res)
|
|
124
|
+
|
|
125
|
+
engine_name = req.query['engineid']
|
|
126
|
+
engine_name = "__nil__" unless engine_name
|
|
127
|
+
|
|
128
|
+
launch_item = OpenWFE::XmlCodec::decode req.body
|
|
129
|
+
|
|
130
|
+
r = @worklist.launch_flow engine_name, launch_item
|
|
131
|
+
|
|
132
|
+
e = REXML::Element.new 'ok'
|
|
133
|
+
|
|
134
|
+
e.add_attribute 'flow-id', r.to_s
|
|
135
|
+
|
|
136
|
+
reply_with_xml res, 200, e
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
#
|
|
140
|
+
# Retrieves a workitem from the worklist
|
|
141
|
+
#
|
|
142
|
+
def do__getworkitem (req, res)
|
|
143
|
+
|
|
144
|
+
execute_wi_get :get, req, res
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
#
|
|
148
|
+
# Retrieves a workitem from the worklist, locks it and returns it
|
|
149
|
+
#
|
|
150
|
+
def do__getandlockworkitem (req, res)
|
|
151
|
+
|
|
152
|
+
execute_wi_get :get_and_lock, req, res
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
#
|
|
156
|
+
# Returns the flow expression ids of the workitems with a given
|
|
157
|
+
# workflow instance id in a store.
|
|
158
|
+
#
|
|
159
|
+
def do__findflowinstance (req, res)
|
|
160
|
+
|
|
161
|
+
store_name = get_store_name req
|
|
162
|
+
|
|
163
|
+
wfid = req.query['id']
|
|
164
|
+
raise "404 'id' not specified" unless wfid
|
|
165
|
+
|
|
166
|
+
wis = @worklist.list_workitems(
|
|
167
|
+
req.attributes['username'], store_name, wfid)
|
|
168
|
+
|
|
169
|
+
e = REXML::Element.new 'stores'
|
|
170
|
+
|
|
171
|
+
wis.each do |wi|
|
|
172
|
+
e << OpenWFE::XmlCodec::encode(wi.fei)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
reply_with_xml res, 200, e
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
#
|
|
179
|
+
# Releases a workitem (unlocks it).
|
|
180
|
+
#
|
|
181
|
+
def do__releaseworkitem (req, res)
|
|
182
|
+
|
|
183
|
+
execute_wi_post :release, req, res
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
#
|
|
187
|
+
# Simply saves the workitem and the modifications done to it.
|
|
188
|
+
#
|
|
189
|
+
def do__saveworkitem (req, res)
|
|
190
|
+
|
|
191
|
+
execute_wi_post :save, req, res
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
#
|
|
195
|
+
# Forwards the workitem (makes the worklist reply to the engine
|
|
196
|
+
# with the modified workitem)
|
|
197
|
+
#
|
|
198
|
+
def do__forwardworkitem (req, res)
|
|
199
|
+
|
|
200
|
+
execute_wi_post :forward, req, res
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
protected
|
|
204
|
+
|
|
205
|
+
def execute_wi_post (method, req, res)
|
|
206
|
+
|
|
207
|
+
store_name = get_store_name req
|
|
208
|
+
|
|
209
|
+
wi = OpenWFE::XmlCodec::decode req.body
|
|
210
|
+
|
|
211
|
+
@worklist.send(
|
|
212
|
+
method,
|
|
213
|
+
req.attributes['username'],
|
|
214
|
+
store_name,
|
|
215
|
+
wi)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def execute_wi_get (method, req, res)
|
|
219
|
+
|
|
220
|
+
store_name = get_store_name req
|
|
221
|
+
fei = OpenWFE::XmlCodec::decode req.body
|
|
222
|
+
|
|
223
|
+
wi = @worklist.send(
|
|
224
|
+
method, req.attributes['username'], store_name, fei)
|
|
225
|
+
|
|
226
|
+
raise "404 no workitem found for #{fei.to_s}" unless wi
|
|
227
|
+
|
|
228
|
+
reply_with_wi res, wi
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def reply_with_wi (res, wi)
|
|
232
|
+
|
|
233
|
+
reply_with_xml res, 200, OpenWFE::XmlCodec::encode(wi)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def get_store_name (req)
|
|
237
|
+
|
|
238
|
+
ss = req.path.split("/")
|
|
239
|
+
raise "404 'store' not specified" if ss.length != 3
|
|
240
|
+
ss[-1]
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
#
|
|
2
|
+
#--
|
|
3
|
+
# Copyright (c) 2007-2008, John Mettraux, OpenWFE.org
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
|
8
|
+
#
|
|
9
|
+
# . Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
# list of conditions and the following disclaimer.
|
|
11
|
+
#
|
|
12
|
+
# . Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
# and/or other materials provided with the distribution.
|
|
15
|
+
#
|
|
16
|
+
# . Neither the name of the "OpenWFE" nor the names of its contributors may be
|
|
17
|
+
# used to endorse or promote products derived from this software without
|
|
18
|
+
# specific prior written permission.
|
|
19
|
+
#
|
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
|
31
|
+
#++
|
|
32
|
+
#
|
|
33
|
+
#
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# "made in Japan"
|
|
37
|
+
#
|
|
38
|
+
# John Mettraux at openwfe.org
|
|
39
|
+
#
|
|
40
|
+
|
|
41
|
+
require 'thread'
|
|
42
|
+
require 'rufus/otime'
|
|
43
|
+
require 'openwfe/contextual'
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
module OpenWFE
|
|
47
|
+
|
|
48
|
+
#
|
|
49
|
+
# TODO #11162 : turn this class into a mixin
|
|
50
|
+
#
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# A wrapper for a Store[Participant] that includes a lock system.
|
|
55
|
+
#
|
|
56
|
+
class StoreWithLocks
|
|
57
|
+
include Contextual
|
|
58
|
+
|
|
59
|
+
DEFAULT_LOCK_MAX_AGE = "1h"
|
|
60
|
+
|
|
61
|
+
attr_accessor :lock_max_age
|
|
62
|
+
attr_reader :store
|
|
63
|
+
|
|
64
|
+
#
|
|
65
|
+
# Builds a new store with a lock system wrapping a 'real_store'.
|
|
66
|
+
#
|
|
67
|
+
# This parameter 'real_store' may be a Class, like in
|
|
68
|
+
#
|
|
69
|
+
# store = StoreWithLocks.new(HashParticipant)
|
|
70
|
+
#
|
|
71
|
+
# You can retrieve the 'real store' with
|
|
72
|
+
#
|
|
73
|
+
# real_store = store.store
|
|
74
|
+
#
|
|
75
|
+
# By default, a lock is kept for one hour. You can change that
|
|
76
|
+
# value with, for example :
|
|
77
|
+
#
|
|
78
|
+
# store = StoreWithLocks.new(HashParticipant, :lock_max_age => "30m10s"
|
|
79
|
+
#
|
|
80
|
+
# (setting the lock maximum age to thirty minutes and 10 seconds).
|
|
81
|
+
#
|
|
82
|
+
def initialize (real_store, application_context=nil, params={})
|
|
83
|
+
|
|
84
|
+
@store = real_store
|
|
85
|
+
@store = @store.new if @store.kind_of?(Class)
|
|
86
|
+
|
|
87
|
+
self.application_context = application_context
|
|
88
|
+
|
|
89
|
+
@lock_max_age = params[:lock_max_age] || DEFAULT_LOCK_MAX_AGE
|
|
90
|
+
@lock_max_age = Rufus::parse_time_string @lock_max_age
|
|
91
|
+
|
|
92
|
+
@locks = {}
|
|
93
|
+
@lock_mutex = Mutex.new
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
#
|
|
97
|
+
# Sets the application context of this store lock and of the
|
|
98
|
+
# real store behind.
|
|
99
|
+
#
|
|
100
|
+
def application_context= (ac)
|
|
101
|
+
|
|
102
|
+
@application_context = ac
|
|
103
|
+
|
|
104
|
+
if @store.respond_to?(:application_context=) and \
|
|
105
|
+
not store.application_context
|
|
106
|
+
|
|
107
|
+
@store.application_context = @application_context
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#
|
|
112
|
+
# Get a workitem, lock it and then return it. Ensures that no other
|
|
113
|
+
# 'locker' can lock it meanwhile.
|
|
114
|
+
#
|
|
115
|
+
def get_and_lock (locker, key)
|
|
116
|
+
|
|
117
|
+
@lock_mutex.synchronize do
|
|
118
|
+
|
|
119
|
+
object = @store[key]
|
|
120
|
+
|
|
121
|
+
return nil unless object
|
|
122
|
+
|
|
123
|
+
not_locked?(key)
|
|
124
|
+
|
|
125
|
+
@locks[key] = [ locker, Time.now.to_i ]
|
|
126
|
+
object
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
alias :lock :get_and_lock
|
|
131
|
+
|
|
132
|
+
#
|
|
133
|
+
# Gets a workitem without locking it.
|
|
134
|
+
#
|
|
135
|
+
def get (key)
|
|
136
|
+
|
|
137
|
+
@store[key]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
#
|
|
141
|
+
# Removes a lock set on an item.
|
|
142
|
+
# If the item was locked by some other locker, will raise an exception.
|
|
143
|
+
# If the item was not locked, will simply exit silently.
|
|
144
|
+
#
|
|
145
|
+
def release (locker, key)
|
|
146
|
+
|
|
147
|
+
@lock_mutex.synchronize do
|
|
148
|
+
holding_lock? locker, key
|
|
149
|
+
@locks.delete key
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
# Returns the locker currently holding a given object
|
|
155
|
+
# (known by its key).
|
|
156
|
+
# Will return nil if the object is not locked (or doesn't exist).
|
|
157
|
+
#
|
|
158
|
+
def get_locker (key)
|
|
159
|
+
|
|
160
|
+
lock = get_lock key
|
|
161
|
+
return nil unless lock
|
|
162
|
+
lock[0]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
#
|
|
166
|
+
# Saves the workitem and releases the lock on it.
|
|
167
|
+
#
|
|
168
|
+
def save (locker, workitem)
|
|
169
|
+
|
|
170
|
+
save_or_forward :save, locker, workitem
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
#
|
|
174
|
+
# Forwards the workitem (to the engine) and releases the lock on
|
|
175
|
+
# it (of course, it's not in the store anymore).
|
|
176
|
+
#
|
|
177
|
+
def forward (locker, workitem)
|
|
178
|
+
|
|
179
|
+
save_or_forward :forward, locker, workitem
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
alias :proceed :forward
|
|
183
|
+
|
|
184
|
+
#
|
|
185
|
+
# Directly forwards the list_workitems() call to the wrapped store.
|
|
186
|
+
#
|
|
187
|
+
def list_workitems (workflow_instance_id=nil)
|
|
188
|
+
|
|
189
|
+
@store.list_workitems(workflow_instance_id)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
#
|
|
193
|
+
# Returns the count of workitems in the store.
|
|
194
|
+
#
|
|
195
|
+
def size
|
|
196
|
+
|
|
197
|
+
@store.size
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
#
|
|
201
|
+
# Just calls the consume method of the underlying store.
|
|
202
|
+
#
|
|
203
|
+
def consume (workitem)
|
|
204
|
+
|
|
205
|
+
@store.consume workitem
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
#
|
|
209
|
+
# Iterates over the workitems in the store.
|
|
210
|
+
#
|
|
211
|
+
# Doesn't care about any order for now.
|
|
212
|
+
#
|
|
213
|
+
def each (&block) # :yields: workitem, locked
|
|
214
|
+
|
|
215
|
+
@store.each do |fei, workitem|
|
|
216
|
+
block.call workitem, locked?(fei)
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
protected
|
|
221
|
+
|
|
222
|
+
def save_or_forward (method, locker, workitem)
|
|
223
|
+
|
|
224
|
+
@lock_mutex.synchronize do
|
|
225
|
+
holding_lock? locker, workitem.fei
|
|
226
|
+
@locks.delete workitem.fei
|
|
227
|
+
@store.send method, workitem
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
#
|
|
232
|
+
# Returns the lock info (else nil) for the given key.
|
|
233
|
+
#
|
|
234
|
+
def get_lock (key)
|
|
235
|
+
|
|
236
|
+
lock = @locks[key]
|
|
237
|
+
|
|
238
|
+
return nil unless lock
|
|
239
|
+
|
|
240
|
+
l, lt = lock
|
|
241
|
+
|
|
242
|
+
if (Time.now.to_i - lt) > @lock_max_age
|
|
243
|
+
@locks.delete key
|
|
244
|
+
return nil
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
[ l, lt ]
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
#
|
|
251
|
+
# Returns true if the object is locked
|
|
252
|
+
#
|
|
253
|
+
def locked? (key)
|
|
254
|
+
|
|
255
|
+
@locks[key] != nil
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
#
|
|
259
|
+
# Will raise an exception if the object (designated via its key)
|
|
260
|
+
# is already locked.
|
|
261
|
+
#
|
|
262
|
+
def not_locked? (key)
|
|
263
|
+
|
|
264
|
+
raise "already locked" if get_lock key
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
#
|
|
268
|
+
# Will raise an exception if the locker is not holding a lock
|
|
269
|
+
# for the given key.
|
|
270
|
+
#
|
|
271
|
+
def holding_lock? (locker, key)
|
|
272
|
+
|
|
273
|
+
lock = get_lock key
|
|
274
|
+
raise "not locked" unless lock
|
|
275
|
+
l, lt = lock
|
|
276
|
+
raise "locked by someone else" if (l != locker)
|
|
277
|
+
# else, simply end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
#--
|
|
281
|
+
# Sets the lock on a given key to 'now'.
|
|
282
|
+
#
|
|
283
|
+
#def touch_lock (key)
|
|
284
|
+
# lock = @locks[key]
|
|
285
|
+
# return false unless lock
|
|
286
|
+
# locker, lock_time = lock
|
|
287
|
+
# @locks[key] = [ locker, Time.now.to_i ]
|
|
288
|
+
# true
|
|
289
|
+
#end
|
|
290
|
+
#++
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|