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,1144 @@
|
|
|
1
|
+
#
|
|
2
|
+
#--
|
|
3
|
+
# Copyright (c) 2006-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
|
+
# "made in Japan"
|
|
36
|
+
#
|
|
37
|
+
# John Mettraux at openwfe.org
|
|
38
|
+
#
|
|
39
|
+
|
|
40
|
+
require 'uri'
|
|
41
|
+
|
|
42
|
+
require 'openwfe/utils'
|
|
43
|
+
require 'openwfe/service'
|
|
44
|
+
require 'openwfe/logging'
|
|
45
|
+
require 'openwfe/omixins'
|
|
46
|
+
require 'openwfe/rudefinitions'
|
|
47
|
+
require 'openwfe/flowexpressionid'
|
|
48
|
+
require 'openwfe/util/observable'
|
|
49
|
+
require 'openwfe/expool/parser'
|
|
50
|
+
require 'openwfe/expool/representation'
|
|
51
|
+
require 'openwfe/expressions/environment'
|
|
52
|
+
require 'openwfe/expressions/raw'
|
|
53
|
+
|
|
54
|
+
require 'rufus/lru' # gem 'rufus-lru'
|
|
55
|
+
require 'rufus/verbs' # gem 'rufus-lru'
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
module OpenWFE
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# The ExpressionPool stores expressions (pieces of workflow instance).
|
|
62
|
+
# It's the core of the workflow engine.
|
|
63
|
+
# It relies on an expression storage for actual persistence of the
|
|
64
|
+
# expressions.
|
|
65
|
+
#
|
|
66
|
+
class ExpressionPool
|
|
67
|
+
include ServiceMixin
|
|
68
|
+
include OwfeServiceLocator
|
|
69
|
+
include OwfeObservable
|
|
70
|
+
include FeiMixin
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
# The hash containing the wfid of the process instances currently
|
|
74
|
+
# paused.
|
|
75
|
+
#
|
|
76
|
+
attr_reader :paused_instances
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# The constructor for the expression pool.
|
|
80
|
+
#
|
|
81
|
+
def initialize (service_name, application_context)
|
|
82
|
+
|
|
83
|
+
super()
|
|
84
|
+
|
|
85
|
+
service_init service_name, application_context
|
|
86
|
+
|
|
87
|
+
@paused_instances = {}
|
|
88
|
+
|
|
89
|
+
#@monitors = MonitorProvider.new(application_context)
|
|
90
|
+
|
|
91
|
+
@observers = {}
|
|
92
|
+
|
|
93
|
+
@stopped = false
|
|
94
|
+
|
|
95
|
+
engine_environment_id
|
|
96
|
+
# makes sure it's called now
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#
|
|
100
|
+
# Stops this expression pool (especially its workqueue).
|
|
101
|
+
#
|
|
102
|
+
def stop
|
|
103
|
+
|
|
104
|
+
@stopped = true
|
|
105
|
+
|
|
106
|
+
onotify :stop
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
#--
|
|
110
|
+
# Obtains a unique monitor for an expression.
|
|
111
|
+
# It avoids the need for the FlowExpression instances to include
|
|
112
|
+
# the monitor mixin by themselves
|
|
113
|
+
#
|
|
114
|
+
#def get_monitor (fei)
|
|
115
|
+
# @monitors[fei]
|
|
116
|
+
#end
|
|
117
|
+
#++
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
# This method is called by the launch method. It's actually the first
|
|
121
|
+
# stage of that method.
|
|
122
|
+
# It may be interessant to use to 'validate' a launchitem and its
|
|
123
|
+
# process definition, as it will raise an exception in case
|
|
124
|
+
# of 'parameter' mismatch.
|
|
125
|
+
#
|
|
126
|
+
# There is a 'pre_launch_check' alias for this method in the
|
|
127
|
+
# Engine class.
|
|
128
|
+
#
|
|
129
|
+
def prepare_raw_expression (launchitem)
|
|
130
|
+
|
|
131
|
+
wfdurl = launchitem.workflow_definition_url
|
|
132
|
+
|
|
133
|
+
raise "launchitem.workflow_definition_url not set, cannot launch" \
|
|
134
|
+
unless wfdurl
|
|
135
|
+
|
|
136
|
+
definition = if wfdurl.match "^field:"
|
|
137
|
+
|
|
138
|
+
raise(
|
|
139
|
+
":definition_in_launchitem_allowed not set to true, "+
|
|
140
|
+
"cannot launch"
|
|
141
|
+
) if ac[:definition_in_launchitem_allowed] != true
|
|
142
|
+
|
|
143
|
+
wfdfield = wfdurl[6..-1]
|
|
144
|
+
launchitem.attributes.delete wfdfield
|
|
145
|
+
else
|
|
146
|
+
|
|
147
|
+
read_uri wfdurl
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
raise "didn't find process definition at '#{wfdurl}'" \
|
|
151
|
+
unless definition
|
|
152
|
+
|
|
153
|
+
raw_expression = build_raw_expression launchitem, definition
|
|
154
|
+
|
|
155
|
+
raw_expression.check_parameters launchitem
|
|
156
|
+
#
|
|
157
|
+
# will raise an exception if there are requirements
|
|
158
|
+
# and one of them is not met
|
|
159
|
+
|
|
160
|
+
raw_expression
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
#
|
|
164
|
+
# Instantiates a workflow definition and launches it.
|
|
165
|
+
#
|
|
166
|
+
# This method call will return immediately, it could even return
|
|
167
|
+
# before the actual launch is completely over.
|
|
168
|
+
#
|
|
169
|
+
# Returns the FlowExpressionId instance of the root expression of
|
|
170
|
+
# the newly launched flow.
|
|
171
|
+
#
|
|
172
|
+
def launch (launchitem, options={})
|
|
173
|
+
|
|
174
|
+
#
|
|
175
|
+
# prepare raw expression
|
|
176
|
+
|
|
177
|
+
raw_expression = prepare_raw_expression launchitem
|
|
178
|
+
#
|
|
179
|
+
# will raise an exception if there are requirements
|
|
180
|
+
# and one of them is not met
|
|
181
|
+
|
|
182
|
+
raw_expression = wrap_in_schedule(raw_expression, options) \
|
|
183
|
+
if options.size > 0
|
|
184
|
+
|
|
185
|
+
raw_expression.new_environment
|
|
186
|
+
#
|
|
187
|
+
# as this expression is the root of a new process instance,
|
|
188
|
+
# it has to have an environment for all the variables of
|
|
189
|
+
# the process instance
|
|
190
|
+
|
|
191
|
+
fei = raw_expression.fei
|
|
192
|
+
|
|
193
|
+
#
|
|
194
|
+
# apply prepared raw expression
|
|
195
|
+
|
|
196
|
+
wi = build_workitem launchitem
|
|
197
|
+
|
|
198
|
+
onotify :launch, fei, launchitem
|
|
199
|
+
|
|
200
|
+
apply raw_expression, wi
|
|
201
|
+
|
|
202
|
+
fei
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
#
|
|
206
|
+
# This is the first stage of the tlaunch_child() method.
|
|
207
|
+
#
|
|
208
|
+
# (it's used by the concurrent iterator when preparing all its
|
|
209
|
+
# iteration children)
|
|
210
|
+
#
|
|
211
|
+
def tprepare_child (
|
|
212
|
+
parent_exp, template, sub_id, register_child, vars)
|
|
213
|
+
|
|
214
|
+
return fetch_expression(template) \
|
|
215
|
+
if template.is_a?(FlowExpressionId)
|
|
216
|
+
|
|
217
|
+
fei = parent_exp.fei.dup
|
|
218
|
+
fei.expression_name = template.first
|
|
219
|
+
fei.expression_id = "#{fei.expid}.#{sub_id}"
|
|
220
|
+
|
|
221
|
+
raw_exp = RawExpression.new_raw(
|
|
222
|
+
fei, nil, nil, @application_context, template)
|
|
223
|
+
|
|
224
|
+
raw_exp.parent_id = parent_exp.fei
|
|
225
|
+
|
|
226
|
+
if vars
|
|
227
|
+
raw_exp.new_environment vars
|
|
228
|
+
else
|
|
229
|
+
raw_exp.environment_id = parent_exp.environment_id
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
#workitem.fei = raw_exp.fei
|
|
233
|
+
# done in do_apply...
|
|
234
|
+
|
|
235
|
+
if register_child
|
|
236
|
+
(parent_exp.children ||= []) << raw_exp.fei
|
|
237
|
+
update raw_exp
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
raw_exp
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
#
|
|
244
|
+
# Launches the given template (sexp) as the child of its
|
|
245
|
+
# parent expression.
|
|
246
|
+
#
|
|
247
|
+
# If the last, register_child, is set to true, this method will
|
|
248
|
+
# take care of adding the new child to the parent expression.
|
|
249
|
+
#
|
|
250
|
+
# (used by 'cron' and more)
|
|
251
|
+
#
|
|
252
|
+
def tlaunch_child (
|
|
253
|
+
parent_exp, template, sub_id, workitem, register_child, vars=nil)
|
|
254
|
+
|
|
255
|
+
raw_exp = tprepare_child(
|
|
256
|
+
parent_exp, template, sub_id, register_child, vars)
|
|
257
|
+
|
|
258
|
+
onotify :tlaunch_child, raw_exp.fei, workitem
|
|
259
|
+
|
|
260
|
+
apply raw_exp, workitem
|
|
261
|
+
|
|
262
|
+
raw_exp.fei
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
#
|
|
266
|
+
# Launches a template, but makes sure the new expression has no
|
|
267
|
+
# parent.
|
|
268
|
+
#
|
|
269
|
+
# (used by 'listen')
|
|
270
|
+
#
|
|
271
|
+
def tlaunch_orphan (
|
|
272
|
+
firing_exp, template, sub_id, workitem, register_child)
|
|
273
|
+
|
|
274
|
+
fei = firing_exp.fei.dup
|
|
275
|
+
fei.expression_id = "#{fei.expid}.#{sub_id}"
|
|
276
|
+
fei.expression_name = template.first
|
|
277
|
+
|
|
278
|
+
raw_exp = RawExpression.new_raw(
|
|
279
|
+
fei, nil, nil, @application_context, template)
|
|
280
|
+
|
|
281
|
+
#raw_exp.parent_id = GONE_PARENT_ID
|
|
282
|
+
raw_exp.parent_id = nil
|
|
283
|
+
# it's an orphan, no parent
|
|
284
|
+
|
|
285
|
+
raw_exp.environment_id = firing_exp.environment_id
|
|
286
|
+
# tapping anyway into the firer's environment
|
|
287
|
+
|
|
288
|
+
(firing_exp.children ||= []) << raw_exp.fei \
|
|
289
|
+
if register_child
|
|
290
|
+
|
|
291
|
+
onotify :tlaunch_orphan, raw_exp.fei, workitem
|
|
292
|
+
|
|
293
|
+
apply raw_exp, workitem
|
|
294
|
+
|
|
295
|
+
raw_exp.fei
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
#
|
|
299
|
+
# Launches a subprocess.
|
|
300
|
+
# The resulting wfid is a subid for the wfid of the firing expression.
|
|
301
|
+
#
|
|
302
|
+
# (used by 'subprocess')
|
|
303
|
+
#
|
|
304
|
+
def launch_subprocess (
|
|
305
|
+
firing_exp, template, forget, workitem, params)
|
|
306
|
+
|
|
307
|
+
raw_exp = if template.is_a?(FlowExpressionId)
|
|
308
|
+
|
|
309
|
+
fetch_expression template
|
|
310
|
+
|
|
311
|
+
elsif template.is_a?(RawExpression)
|
|
312
|
+
|
|
313
|
+
template.application_context = @application_context
|
|
314
|
+
template
|
|
315
|
+
|
|
316
|
+
else # probably an URI
|
|
317
|
+
|
|
318
|
+
build_raw_expression nil, template
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
raw_exp = raw_exp.dup
|
|
322
|
+
raw_exp.fei = raw_exp.fei.dup
|
|
323
|
+
|
|
324
|
+
if forget
|
|
325
|
+
raw_exp.parent_id = nil
|
|
326
|
+
else
|
|
327
|
+
raw_exp.parent_id = firing_exp.fei
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
#raw_exp.fei.wfid = get_wfid_generator.generate
|
|
331
|
+
#raw_exp.fei.wfid =
|
|
332
|
+
# "#{firing_exp.fei.wfid}.#{firing_exp.get_next_sub_id}"
|
|
333
|
+
raw_exp.fei.wfid =
|
|
334
|
+
"#{firing_exp.fei.parent_wfid}.#{firing_exp.get_next_sub_id}"
|
|
335
|
+
|
|
336
|
+
raw_exp.new_environment params
|
|
337
|
+
|
|
338
|
+
raw_exp.store_itself
|
|
339
|
+
|
|
340
|
+
apply raw_exp, workitem
|
|
341
|
+
|
|
342
|
+
raw_exp.fei
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
#
|
|
346
|
+
# Replaces the flow expression with a raw expression that has
|
|
347
|
+
# the same fei, same parent and points to the same env.
|
|
348
|
+
# The raw_representation will be the template.
|
|
349
|
+
# Stores and then apply the "cuckoo" expression.
|
|
350
|
+
#
|
|
351
|
+
def substitute_and_apply (fexp, template, workitem)
|
|
352
|
+
|
|
353
|
+
re = RawExpression.new_raw(
|
|
354
|
+
fexp.fei,
|
|
355
|
+
fexp.parent_id,
|
|
356
|
+
fexp.environment_id,
|
|
357
|
+
application_context,
|
|
358
|
+
template)
|
|
359
|
+
|
|
360
|
+
update re
|
|
361
|
+
|
|
362
|
+
apply re, workitem
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
#
|
|
366
|
+
# Applies a given expression (id or expression)
|
|
367
|
+
#
|
|
368
|
+
def apply (exp_or_fei, workitem)
|
|
369
|
+
|
|
370
|
+
get_workqueue.push(
|
|
371
|
+
self, :do_apply_reply, :apply, exp_or_fei, workitem)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
#
|
|
375
|
+
# Replies to a given expression
|
|
376
|
+
#
|
|
377
|
+
def reply (exp_or_fei, workitem)
|
|
378
|
+
|
|
379
|
+
get_workqueue.push(
|
|
380
|
+
self, :do_apply_reply, :reply, exp_or_fei, workitem)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
#
|
|
384
|
+
# Cancels the given expression.
|
|
385
|
+
# The param might be an expression instance or a FlowExpressionId
|
|
386
|
+
# instance.
|
|
387
|
+
#
|
|
388
|
+
def cancel (exp)
|
|
389
|
+
|
|
390
|
+
exp, fei = fetch exp
|
|
391
|
+
|
|
392
|
+
unless exp
|
|
393
|
+
linfo { "cancel() cannot cancel missing #{fei.to_debug_s}" }
|
|
394
|
+
return nil
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
ldebug { "cancel() for #{fei.to_debug_s}" }
|
|
398
|
+
|
|
399
|
+
onotify :cancel, exp
|
|
400
|
+
|
|
401
|
+
wi = exp.cancel
|
|
402
|
+
|
|
403
|
+
remove exp
|
|
404
|
+
|
|
405
|
+
wi
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
#
|
|
409
|
+
# Cancels the given expression and makes sure to resume the flow
|
|
410
|
+
# if the expression or one of its children were active.
|
|
411
|
+
#
|
|
412
|
+
# If the cancelled branch was not active, this method will take
|
|
413
|
+
# care of removing the cancelled expression from the parent
|
|
414
|
+
# expression.
|
|
415
|
+
#
|
|
416
|
+
def cancel_expression (exp)
|
|
417
|
+
|
|
418
|
+
exp = fetch_expression exp
|
|
419
|
+
|
|
420
|
+
wi = cancel exp
|
|
421
|
+
|
|
422
|
+
# ( remember that in case of error, no wi could get returned...)
|
|
423
|
+
|
|
424
|
+
if wi
|
|
425
|
+
|
|
426
|
+
reply_to_parent exp, wi, false
|
|
427
|
+
|
|
428
|
+
elsif exp.parent_id
|
|
429
|
+
|
|
430
|
+
parent_exp = fetch_expression exp.parent_id
|
|
431
|
+
parent_exp.remove_child(exp.fei) if parent_exp
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
#
|
|
436
|
+
# Given any expression of a process, cancels the complete process
|
|
437
|
+
# instance.
|
|
438
|
+
#
|
|
439
|
+
def cancel_process (exp_or_wfid)
|
|
440
|
+
|
|
441
|
+
wfid = extract_wfid exp_or_wfid, false
|
|
442
|
+
|
|
443
|
+
ldebug { "cancel_process() '#{wfid}'" }
|
|
444
|
+
|
|
445
|
+
root = fetch_root wfid
|
|
446
|
+
|
|
447
|
+
raise "no process to cancel '#{wfid}'" unless root
|
|
448
|
+
|
|
449
|
+
cancel root
|
|
450
|
+
end
|
|
451
|
+
alias :cancel_flow :cancel_process
|
|
452
|
+
#
|
|
453
|
+
# Forgets the given expression (make it an orphan).
|
|
454
|
+
#
|
|
455
|
+
def forget (parent_exp, exp)
|
|
456
|
+
|
|
457
|
+
exp, fei = fetch exp
|
|
458
|
+
|
|
459
|
+
#ldebug { "forget() forgetting #{fei}" }
|
|
460
|
+
|
|
461
|
+
return if not exp
|
|
462
|
+
|
|
463
|
+
onotify :forget, exp
|
|
464
|
+
|
|
465
|
+
parent_exp.children.delete(fei)
|
|
466
|
+
|
|
467
|
+
#exp.parent_id = GONE_PARENT_ID
|
|
468
|
+
exp.parent_id = nil
|
|
469
|
+
|
|
470
|
+
exp.dup_environment
|
|
471
|
+
exp.store_itself()
|
|
472
|
+
|
|
473
|
+
ldebug { "forget() forgot #{fei}" }
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
#
|
|
477
|
+
# Replies to the parent of the given expression.
|
|
478
|
+
#
|
|
479
|
+
def reply_to_parent (exp, workitem, remove=true)
|
|
480
|
+
|
|
481
|
+
ldebug { "reply_to_parent() for #{exp.fei.to_debug_s}" }
|
|
482
|
+
|
|
483
|
+
workitem.last_expression_id = exp.fei
|
|
484
|
+
|
|
485
|
+
onotify :reply_to_parent, exp, workitem
|
|
486
|
+
|
|
487
|
+
if remove
|
|
488
|
+
|
|
489
|
+
remove exp
|
|
490
|
+
#
|
|
491
|
+
# remove the expression itself
|
|
492
|
+
|
|
493
|
+
exp.clean_children
|
|
494
|
+
#
|
|
495
|
+
# remove all the children of the expression
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
#
|
|
499
|
+
# manage tag, have to remove it so it can get 'redone' or 'undone'
|
|
500
|
+
# (preventing abuse)
|
|
501
|
+
|
|
502
|
+
tagname = exp.attributes["tag"] if exp.attributes
|
|
503
|
+
|
|
504
|
+
exp.delete_variable(tagname) if tagname
|
|
505
|
+
|
|
506
|
+
#
|
|
507
|
+
# has raw_expression been updated ?
|
|
508
|
+
|
|
509
|
+
track_child_raw_representation exp
|
|
510
|
+
|
|
511
|
+
#
|
|
512
|
+
# flow terminated ?
|
|
513
|
+
|
|
514
|
+
#if not exp.parent_id
|
|
515
|
+
if (not exp.parent_id) and (exp.fei.expid == '0')
|
|
516
|
+
|
|
517
|
+
ldebug do
|
|
518
|
+
"reply_to_parent() process " +
|
|
519
|
+
"#{exp.fei.workflow_instance_id} terminated"
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
onotify :terminate, exp, workitem
|
|
523
|
+
|
|
524
|
+
return
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
#
|
|
528
|
+
# else, gone parent ?
|
|
529
|
+
|
|
530
|
+
#if exp.parent_id == GONE_PARENT_ID
|
|
531
|
+
if (not exp.parent_id) or (exp.parent_id.expname == 'gone')
|
|
532
|
+
# this 'gone' is kept for some level of 'backward compatibility'
|
|
533
|
+
|
|
534
|
+
ldebug do
|
|
535
|
+
"reply_to_parent() parent is gone for " +
|
|
536
|
+
exp.fei.to_debug_s
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
return
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
#
|
|
543
|
+
# parent still present, reply to it
|
|
544
|
+
|
|
545
|
+
reply exp.parent_id, workitem
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
#
|
|
549
|
+
# Adds or updates a flow expression in this pool
|
|
550
|
+
#
|
|
551
|
+
def update (flow_expression)
|
|
552
|
+
|
|
553
|
+
ldebug { "update() for #{flow_expression.fei.to_debug_s}" }
|
|
554
|
+
|
|
555
|
+
#t = Timer.new
|
|
556
|
+
|
|
557
|
+
onotify :update, flow_expression.fei, flow_expression
|
|
558
|
+
|
|
559
|
+
#ldebug do
|
|
560
|
+
# "update() took #{t.duration} ms " +
|
|
561
|
+
# "#{flow_expression.fei.to_debug_s}"
|
|
562
|
+
#end
|
|
563
|
+
|
|
564
|
+
flow_expression
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
#
|
|
568
|
+
# Fetches a FlowExpression from the pool.
|
|
569
|
+
# Returns a tuple : the FlowExpression plus its FlowExpressionId.
|
|
570
|
+
#
|
|
571
|
+
# The param 'exp' may be a FlowExpressionId or a FlowExpression that
|
|
572
|
+
# has to be reloaded.
|
|
573
|
+
#
|
|
574
|
+
def fetch (exp)
|
|
575
|
+
#synchronize do
|
|
576
|
+
|
|
577
|
+
#ldebug { "fetch() exp is of kind #{exp.class}" }
|
|
578
|
+
|
|
579
|
+
fei = if exp.is_a?(FlowExpression)
|
|
580
|
+
|
|
581
|
+
exp.fei
|
|
582
|
+
|
|
583
|
+
elsif not exp.is_a?(FlowExpressionId)
|
|
584
|
+
|
|
585
|
+
raise \
|
|
586
|
+
"Cannot fetch expression with key : "+
|
|
587
|
+
"'#{fei}' (#{fei.class})"
|
|
588
|
+
|
|
589
|
+
else
|
|
590
|
+
|
|
591
|
+
exp
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
#ldebug { "fetch() for #{fei.to_debug_s}" }
|
|
595
|
+
|
|
596
|
+
[ get_expression_storage[fei], fei ]
|
|
597
|
+
#end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
#
|
|
601
|
+
# Fetches a FlowExpression (returns only the FlowExpression instance)
|
|
602
|
+
#
|
|
603
|
+
# The param 'exp' may be a FlowExpressionId or a FlowExpression that
|
|
604
|
+
# has to be reloaded.
|
|
605
|
+
#
|
|
606
|
+
def fetch_expression (exp)
|
|
607
|
+
|
|
608
|
+
exp, fei = fetch exp
|
|
609
|
+
exp
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
#
|
|
613
|
+
# Returns the engine environment (the top level environment)
|
|
614
|
+
#
|
|
615
|
+
def fetch_engine_environment
|
|
616
|
+
#synchronize do
|
|
617
|
+
#
|
|
618
|
+
# synchronize to ensure that there's 1! engine env
|
|
619
|
+
|
|
620
|
+
eei = engine_environment_id
|
|
621
|
+
ee, fei = fetch eei
|
|
622
|
+
|
|
623
|
+
return ee if ee
|
|
624
|
+
|
|
625
|
+
ee = Environment.new_env(
|
|
626
|
+
eei, nil, nil, @application_context, nil)
|
|
627
|
+
|
|
628
|
+
ee.store_itself
|
|
629
|
+
|
|
630
|
+
ee
|
|
631
|
+
#end
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
#
|
|
635
|
+
# Fetches the root expression of a process (or a subprocess).
|
|
636
|
+
#
|
|
637
|
+
def fetch_root (wfid)
|
|
638
|
+
|
|
639
|
+
get_expression_storage.fetch_root wfid
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
#
|
|
643
|
+
# Removes a flow expression from the pool
|
|
644
|
+
# (This method is mainly called from the pool itself)
|
|
645
|
+
#
|
|
646
|
+
def remove (exp)
|
|
647
|
+
|
|
648
|
+
exp, _fei = fetch(exp) \
|
|
649
|
+
if exp.is_a?(FlowExpressionId)
|
|
650
|
+
|
|
651
|
+
return unless exp
|
|
652
|
+
|
|
653
|
+
ldebug { "remove() fe #{exp.fei.to_debug_s}" }
|
|
654
|
+
|
|
655
|
+
onotify :remove, exp.fei
|
|
656
|
+
|
|
657
|
+
#synchronize do
|
|
658
|
+
#@monitors.delete(exp.fei)
|
|
659
|
+
|
|
660
|
+
remove_environment(exp.environment_id) \
|
|
661
|
+
if exp.owns_its_environment?
|
|
662
|
+
#end
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
#
|
|
666
|
+
# This method is called at each expool (engine) [re]start.
|
|
667
|
+
# It roams through the previously saved (persisted) expressions
|
|
668
|
+
# to reschedule ones like 'sleep' or 'cron'.
|
|
669
|
+
#
|
|
670
|
+
def reschedule
|
|
671
|
+
|
|
672
|
+
return if @stopped
|
|
673
|
+
|
|
674
|
+
#synchronize do
|
|
675
|
+
|
|
676
|
+
t = OpenWFE::Timer.new
|
|
677
|
+
|
|
678
|
+
linfo { "reschedule() initiating..." }
|
|
679
|
+
|
|
680
|
+
options = { :include_classes => Rufus::Schedulable }
|
|
681
|
+
|
|
682
|
+
get_expression_storage.find_expressions(options).each do |fexp|
|
|
683
|
+
|
|
684
|
+
linfo { "reschedule() for #{fexp.fei.to_s}..." }
|
|
685
|
+
|
|
686
|
+
onotify :reschedule, fexp.fei
|
|
687
|
+
|
|
688
|
+
fexp.reschedule get_scheduler
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
linfo { "reschedule() done. (took #{t.duration} ms)" }
|
|
692
|
+
#end
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
#
|
|
696
|
+
# Returns the unique engine_environment FlowExpressionId instance.
|
|
697
|
+
# There is only one such environment in an engine, hence this
|
|
698
|
+
# 'singleton' method.
|
|
699
|
+
#
|
|
700
|
+
def engine_environment_id
|
|
701
|
+
#synchronize do
|
|
702
|
+
# no need, it's been already called at initialization
|
|
703
|
+
|
|
704
|
+
return @eei if @eei
|
|
705
|
+
|
|
706
|
+
@eei = FlowExpressionId.new
|
|
707
|
+
@eei.owfe_version = OPENWFERU_VERSION
|
|
708
|
+
@eei.engine_id = get_engine.engine_name
|
|
709
|
+
@eei.initial_engine_id = @eei.engine_id
|
|
710
|
+
@eei.workflow_definition_url = 'ee'
|
|
711
|
+
@eei.workflow_definition_name = 'ee'
|
|
712
|
+
@eei.workflow_definition_revision = '0'
|
|
713
|
+
@eei.workflow_instance_id = '0'
|
|
714
|
+
@eei.expression_name = EN_ENVIRONMENT
|
|
715
|
+
@eei.expression_id = '0'
|
|
716
|
+
@eei
|
|
717
|
+
#end
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
#
|
|
721
|
+
# Returns the list of applied expressions belonging to a given
|
|
722
|
+
# workflow instance.
|
|
723
|
+
#
|
|
724
|
+
# If the unapplied optional parameter is set to true, all the
|
|
725
|
+
# expressions (even those not yet applied) that compose the process
|
|
726
|
+
# instance will be returned. Environments will be returned as well.
|
|
727
|
+
#
|
|
728
|
+
def process_stack (wfid, unapplied=false)
|
|
729
|
+
|
|
730
|
+
#raise "please provide a non-nil workflow instance id" \
|
|
731
|
+
# unless wfid
|
|
732
|
+
|
|
733
|
+
wfid = extract_wfid wfid, true
|
|
734
|
+
|
|
735
|
+
params = {
|
|
736
|
+
#:exclude_classes => [ Environment, RawExpression ],
|
|
737
|
+
#:exclude_classes => [ Environment ],
|
|
738
|
+
:parent_wfid => wfid
|
|
739
|
+
}
|
|
740
|
+
params[:applied] = true if (not unapplied)
|
|
741
|
+
|
|
742
|
+
stack = get_expression_storage.find_expressions params
|
|
743
|
+
|
|
744
|
+
stack.extend(RepresentationMixin) if unapplied
|
|
745
|
+
|
|
746
|
+
stack
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
#
|
|
750
|
+
# Lists all workflows (processes) currently in the expool (in
|
|
751
|
+
# the engine).
|
|
752
|
+
# This method will return a list of "process-definition" expressions
|
|
753
|
+
# (root of flows).
|
|
754
|
+
#
|
|
755
|
+
def list_processes (options={})
|
|
756
|
+
|
|
757
|
+
options[:include_classes] = DefineExpression
|
|
758
|
+
#
|
|
759
|
+
# Maybe it would be better to list root expressions instead
|
|
760
|
+
# so that expressions like 'sequence' can be used
|
|
761
|
+
# as root expressions. Later...
|
|
762
|
+
|
|
763
|
+
get_expression_storage.find_expressions options
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
#
|
|
767
|
+
# This method is called when apply() or reply() failed for
|
|
768
|
+
# an expression.
|
|
769
|
+
# There are currently only two 'users', the ParticipantExpression
|
|
770
|
+
# class and the do_process_workelement method of this ExpressionPool
|
|
771
|
+
# class.
|
|
772
|
+
#
|
|
773
|
+
def notify_error (error, fei, message, workitem)
|
|
774
|
+
|
|
775
|
+
fei = extract_fei fei
|
|
776
|
+
# densha requires that... :(
|
|
777
|
+
|
|
778
|
+
se = OpenWFE::exception_to_s error
|
|
779
|
+
|
|
780
|
+
onotify :error, fei, message, workitem, error.class.name, se
|
|
781
|
+
|
|
782
|
+
#fei = extract_fei fei
|
|
783
|
+
|
|
784
|
+
if error.is_a?(PausedError)
|
|
785
|
+
lwarn do
|
|
786
|
+
"#{self.service_name} " +
|
|
787
|
+
"operation :#{message.to_s} on #{fei.to_s} " +
|
|
788
|
+
"delayed because process '#{fei.wfid}' is in pause"
|
|
789
|
+
end
|
|
790
|
+
else
|
|
791
|
+
lwarn do
|
|
792
|
+
"#{self.service_name} " +
|
|
793
|
+
"operation :#{message.to_s} on #{fei.to_s} " +
|
|
794
|
+
"failed with\n" + se
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
#
|
|
800
|
+
# Gets the process definition (if necessary) and turns into
|
|
801
|
+
# into an expression tree (for storing into a RawExpression).
|
|
802
|
+
#
|
|
803
|
+
def determine_rep (param)
|
|
804
|
+
|
|
805
|
+
param = read_uri(param) if param.is_a?(URI)
|
|
806
|
+
|
|
807
|
+
DefParser.parse param
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
#
|
|
811
|
+
# Returns true if the process instance to which the expression
|
|
812
|
+
# belongs is currently paused.
|
|
813
|
+
#
|
|
814
|
+
def is_paused? (expression)
|
|
815
|
+
|
|
816
|
+
(@paused_instances[expression.fei.parent_wfid] != nil)
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
protected
|
|
820
|
+
|
|
821
|
+
#
|
|
822
|
+
# This is the only point in the expression pool where an URI
|
|
823
|
+
# is read, so this is where the :remote_definitions_allowed
|
|
824
|
+
# security check is enforced.
|
|
825
|
+
#
|
|
826
|
+
def read_uri (uri)
|
|
827
|
+
|
|
828
|
+
uri = URI.parse uri.to_s
|
|
829
|
+
|
|
830
|
+
raise ":remote_definitions_allowed is set to false" \
|
|
831
|
+
if (ac[:remote_definitions_allowed] != true and
|
|
832
|
+
uri.scheme and
|
|
833
|
+
uri.scheme != 'file')
|
|
834
|
+
|
|
835
|
+
#open(uri.to_s).read
|
|
836
|
+
|
|
837
|
+
f = Rufus::Verbs.fopen uri
|
|
838
|
+
result = f.read
|
|
839
|
+
f.close if f.respond_to?(:close)
|
|
840
|
+
|
|
841
|
+
result
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
#
|
|
845
|
+
# This is the method called [asynchronously] by the WorkQueue
|
|
846
|
+
# upon apply/reply.
|
|
847
|
+
#
|
|
848
|
+
def do_apply_reply (direction, exp_or_fei, workitem)
|
|
849
|
+
|
|
850
|
+
fei = nil
|
|
851
|
+
|
|
852
|
+
begin
|
|
853
|
+
|
|
854
|
+
exp, fei = if exp_or_fei.is_a?(FlowExpressionId)
|
|
855
|
+
fetch exp_or_fei
|
|
856
|
+
else
|
|
857
|
+
[ exp_or_fei, exp_or_fei.fei ]
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
#p [ direction, fei.wfid, fei.expid, fei.expname ]
|
|
861
|
+
#
|
|
862
|
+
# I uncomment that sometimes to see how the stack
|
|
863
|
+
# grows (wfids and expids)
|
|
864
|
+
|
|
865
|
+
ldebug {
|
|
866
|
+
":#{direction} "+
|
|
867
|
+
"target #{fei.to_debug_s}" }
|
|
868
|
+
|
|
869
|
+
if not exp
|
|
870
|
+
|
|
871
|
+
#raise "apply() cannot apply missing #{_fei.to_debug_s}"
|
|
872
|
+
# not very helpful anyway
|
|
873
|
+
|
|
874
|
+
lwarn { "do_apply_reply() cannot find >#{fei}" }
|
|
875
|
+
|
|
876
|
+
return
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
check_if_paused exp
|
|
880
|
+
|
|
881
|
+
workitem.fei = exp.fei if direction == :apply
|
|
882
|
+
|
|
883
|
+
onotify direction, exp, workitem
|
|
884
|
+
|
|
885
|
+
exp.send direction, workitem
|
|
886
|
+
|
|
887
|
+
rescue Exception => e
|
|
888
|
+
|
|
889
|
+
notify_error e, fei, direction, workitem
|
|
890
|
+
end
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
#
|
|
894
|
+
# Will raise an exception if the expression belongs to a paused
|
|
895
|
+
# process.
|
|
896
|
+
#
|
|
897
|
+
def check_if_paused (expression)
|
|
898
|
+
|
|
899
|
+
wfid = expression.fei.parent_wfid
|
|
900
|
+
|
|
901
|
+
raise PausedError.new(wfid) if @paused_instances[wfid]
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
#
|
|
905
|
+
# if the launch method is called with a schedule option
|
|
906
|
+
# (like :at, :in, :cron and :every), this method takes care of
|
|
907
|
+
# wrapping the process with a sleep or a cron.
|
|
908
|
+
#
|
|
909
|
+
def wrap_in_schedule (raw_expression, options)
|
|
910
|
+
|
|
911
|
+
oat = options[:at]
|
|
912
|
+
oin = options[:in]
|
|
913
|
+
ocron = options[:cron]
|
|
914
|
+
oevery = options[:every]
|
|
915
|
+
|
|
916
|
+
fei = new_fei nil, "schedlaunch", "0", "sequence"
|
|
917
|
+
|
|
918
|
+
# not very happy with this code, it builds custom
|
|
919
|
+
# wrapping processes manually, maybe there is
|
|
920
|
+
# a more elegant way, but for now, it's ok.
|
|
921
|
+
|
|
922
|
+
template = if oat or oin
|
|
923
|
+
|
|
924
|
+
sleep_atts = if oat
|
|
925
|
+
{ "until" => oat }
|
|
926
|
+
else #oin
|
|
927
|
+
{ "for" => oin }
|
|
928
|
+
end
|
|
929
|
+
sleep_atts["scheduler-tags"] = "scheduled-launch"
|
|
930
|
+
|
|
931
|
+
raw_expression.new_environment
|
|
932
|
+
raw_expression.store_itself
|
|
933
|
+
|
|
934
|
+
[
|
|
935
|
+
"sequence", {}, [
|
|
936
|
+
[ "sleep", sleep_atts, [] ],
|
|
937
|
+
raw_expression.fei
|
|
938
|
+
]
|
|
939
|
+
]
|
|
940
|
+
|
|
941
|
+
elsif ocron or oevery
|
|
942
|
+
|
|
943
|
+
fei.expression_name = "cron"
|
|
944
|
+
|
|
945
|
+
cron_atts = if ocron
|
|
946
|
+
{ "tab" => ocron }
|
|
947
|
+
else #oevery
|
|
948
|
+
{ "every" => oevery }
|
|
949
|
+
end
|
|
950
|
+
cron_atts["name"] = "//cron_launch__#{fei.wfid}"
|
|
951
|
+
cron_atts["scheduler-tags"] = "scheduled-launch"
|
|
952
|
+
|
|
953
|
+
template = raw_expression.raw_representation
|
|
954
|
+
remove raw_expression
|
|
955
|
+
|
|
956
|
+
[ "cron", cron_atts, [ template ] ]
|
|
957
|
+
|
|
958
|
+
else
|
|
959
|
+
|
|
960
|
+
nil # don't schedule at all
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
if template
|
|
964
|
+
|
|
965
|
+
raw_exp = RawExpression.new_raw(
|
|
966
|
+
fei, nil, nil, @application_context, template)
|
|
967
|
+
|
|
968
|
+
raw_exp.store_itself
|
|
969
|
+
|
|
970
|
+
raw_exp
|
|
971
|
+
else
|
|
972
|
+
|
|
973
|
+
raw_expression
|
|
974
|
+
end
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
#
|
|
978
|
+
# Removes an environment, especially takes care of unbinding
|
|
979
|
+
# any special value it may contain.
|
|
980
|
+
#
|
|
981
|
+
def remove_environment (environment_id)
|
|
982
|
+
|
|
983
|
+
ldebug { "remove_environment() #{environment_id.to_debug_s}" }
|
|
984
|
+
|
|
985
|
+
env, fei = fetch(environment_id)
|
|
986
|
+
|
|
987
|
+
return unless env
|
|
988
|
+
#
|
|
989
|
+
# env already unbound and removed
|
|
990
|
+
|
|
991
|
+
env.unbind
|
|
992
|
+
|
|
993
|
+
#get_expression_storage().delete(environment_id)
|
|
994
|
+
|
|
995
|
+
onotify :remove, environment_id
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
#
|
|
999
|
+
# Prepares a new instance of InFlowWorkItem from a LaunchItem
|
|
1000
|
+
# instance.
|
|
1001
|
+
#
|
|
1002
|
+
def build_workitem (launchitem)
|
|
1003
|
+
|
|
1004
|
+
wi = InFlowWorkItem.new
|
|
1005
|
+
|
|
1006
|
+
wi.attributes = launchitem.attributes.dup
|
|
1007
|
+
|
|
1008
|
+
wi
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
#
|
|
1012
|
+
# Builds a FlowExpressionId instance for a process being
|
|
1013
|
+
# launched.
|
|
1014
|
+
#
|
|
1015
|
+
def new_fei (launchitem, flow_name, flow_revision, exp_name)
|
|
1016
|
+
|
|
1017
|
+
url = if launchitem
|
|
1018
|
+
launchitem.workflow_definition_url
|
|
1019
|
+
else
|
|
1020
|
+
"no-url"
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
fei = FlowExpressionId.new
|
|
1024
|
+
|
|
1025
|
+
fei.owfe_version = OPENWFERU_VERSION
|
|
1026
|
+
fei.engine_id = OpenWFE::stu get_engine.service_name
|
|
1027
|
+
fei.initial_engine_id = OpenWFE::stu fei.engine_id
|
|
1028
|
+
fei.workflow_definition_url = OpenWFE::stu url
|
|
1029
|
+
fei.workflow_definition_name = OpenWFE::stu flow_name
|
|
1030
|
+
fei.workflow_definition_revision = OpenWFE::stu flow_revision
|
|
1031
|
+
fei.wfid = get_wfid_generator.generate launchitem
|
|
1032
|
+
fei.expression_id = "0"
|
|
1033
|
+
fei.expression_name = exp_name
|
|
1034
|
+
|
|
1035
|
+
fei
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
#
|
|
1039
|
+
# Builds the RawExpression instance at the root of the flow
|
|
1040
|
+
# being launched.
|
|
1041
|
+
#
|
|
1042
|
+
# The param can be a template or a definition (anything
|
|
1043
|
+
# accepted by the determine_representation() method).
|
|
1044
|
+
#
|
|
1045
|
+
def build_raw_expression (launchitem, param)
|
|
1046
|
+
|
|
1047
|
+
procdef = determine_rep param
|
|
1048
|
+
|
|
1049
|
+
atts = procdef[1]
|
|
1050
|
+
flow_name = atts['name'] || "noname"
|
|
1051
|
+
flow_revision = atts['revision'] || "0"
|
|
1052
|
+
exp_name = procdef.first
|
|
1053
|
+
|
|
1054
|
+
fei = new_fei launchitem, flow_name, flow_revision, exp_name
|
|
1055
|
+
|
|
1056
|
+
RawExpression.new_raw(
|
|
1057
|
+
fei, nil, nil, @application_context, procdef)
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
#
|
|
1061
|
+
# Given a [replying] child flow expression, will update its parent
|
|
1062
|
+
# raw expression if the child raw_expression changed.
|
|
1063
|
+
#
|
|
1064
|
+
# This is used to keep track of in-flight modification to running
|
|
1065
|
+
# process instances.
|
|
1066
|
+
#
|
|
1067
|
+
def track_child_raw_representation (fexp)
|
|
1068
|
+
|
|
1069
|
+
return unless fexp.raw_rep_updated == true
|
|
1070
|
+
|
|
1071
|
+
parent = fetch_expression fexp.parent_id
|
|
1072
|
+
|
|
1073
|
+
return if parent.class.uses_template?
|
|
1074
|
+
|
|
1075
|
+
parent.raw_children[fexp.fei.child_id.to_i] =
|
|
1076
|
+
fexp.raw_representation
|
|
1077
|
+
|
|
1078
|
+
parent.store_itself
|
|
1079
|
+
end
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
#
|
|
1083
|
+
# This error is raised when an expression belonging to a paused
|
|
1084
|
+
# process is applied or replied to.
|
|
1085
|
+
#
|
|
1086
|
+
class PausedError < RuntimeError
|
|
1087
|
+
|
|
1088
|
+
attr_reader :wfid
|
|
1089
|
+
|
|
1090
|
+
def initialize (wfid)
|
|
1091
|
+
|
|
1092
|
+
super "process '#{wfid}' is paused"
|
|
1093
|
+
@wfid = wfid
|
|
1094
|
+
end
|
|
1095
|
+
|
|
1096
|
+
#
|
|
1097
|
+
# Returns a hash for this PausedError instance.
|
|
1098
|
+
# (simply returns the hash of the paused process' wfid).
|
|
1099
|
+
#
|
|
1100
|
+
def hash
|
|
1101
|
+
|
|
1102
|
+
@wfid.hash
|
|
1103
|
+
end
|
|
1104
|
+
|
|
1105
|
+
#
|
|
1106
|
+
# Returns true if the other is a PausedError issued for the
|
|
1107
|
+
# same process instance (wfid).
|
|
1108
|
+
#
|
|
1109
|
+
def == (other)
|
|
1110
|
+
|
|
1111
|
+
return false unless other.is_a?(PausedError)
|
|
1112
|
+
|
|
1113
|
+
(@wfid == other.wfid)
|
|
1114
|
+
end
|
|
1115
|
+
end
|
|
1116
|
+
|
|
1117
|
+
#--
|
|
1118
|
+
# a small help class for storing monitors provided on demand
|
|
1119
|
+
# to expressions that need them
|
|
1120
|
+
#
|
|
1121
|
+
#class MonitorProvider
|
|
1122
|
+
# include MonitorMixin, Logging
|
|
1123
|
+
# MAX_MONITORS = 10000
|
|
1124
|
+
# def initialize (application_context=nil)
|
|
1125
|
+
# super()
|
|
1126
|
+
# @application_context = application_context
|
|
1127
|
+
# @monitors = LruHash.new(MAX_MONITORS)
|
|
1128
|
+
# end
|
|
1129
|
+
# def [] (key)
|
|
1130
|
+
# synchronize do
|
|
1131
|
+
# (@monitors[key] ||= Monitor.new)
|
|
1132
|
+
# end
|
|
1133
|
+
# end
|
|
1134
|
+
# def delete (key)
|
|
1135
|
+
# synchronize do
|
|
1136
|
+
# #ldebug { "delete() removing Monitor for #{key}" }
|
|
1137
|
+
# @monitors.delete(key)
|
|
1138
|
+
# end
|
|
1139
|
+
# end
|
|
1140
|
+
#end
|
|
1141
|
+
#++
|
|
1142
|
+
|
|
1143
|
+
end
|
|
1144
|
+
|