openwferu 0.9.1 → 0.9.2

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.
Files changed (104) hide show
  1. data/{README → README.txt} +16 -13
  2. data/bin/validate-workflow.rb +46 -22
  3. data/examples/README.txt +8 -0
  4. data/examples/homeworkreview.rb +66 -0
  5. data/examples/quotereporter.rb +154 -0
  6. data/lib/{openwferu.rb → openwfe.rb} +6 -8
  7. data/lib/{ru → openwfe}/contextual.rb +11 -3
  8. data/lib/{ru → openwfe/engine}/engine.rb +50 -36
  9. data/lib/{ru/participant.rb → openwfe/engine/file_persisted_engine.rb} +21 -22
  10. data/lib/openwfe/expool/expressionpool.rb +534 -0
  11. data/lib/openwfe/expool/expstorage.rb +184 -0
  12. data/lib/openwfe/expool/journalexpstorage.rb +312 -0
  13. data/lib/openwfe/expool/yamlexpstorage.rb +127 -0
  14. data/lib/{ru → openwfe/expressions}/environment.rb +19 -14
  15. data/lib/{ru → openwfe/expressions}/expressionmap.rb +48 -21
  16. data/lib/{ru → openwfe/expressions}/fe_concurrence.rb +111 -35
  17. data/lib/openwfe/expressions/fe_cursor.rb +236 -0
  18. data/lib/{ru → openwfe/expressions}/fe_define.rb +5 -5
  19. data/lib/openwfe/expressions/fe_fqv.rb +99 -0
  20. data/lib/openwfe/expressions/fe_iterator.rb +182 -0
  21. data/lib/{ru/fe_misc.rb → openwfe/expressions/fe_losfor.rb} +14 -56
  22. data/lib/openwfe/expressions/fe_misc.rb +102 -0
  23. data/lib/{ru → openwfe/expressions}/fe_participant.rb +25 -14
  24. data/lib/{ru → openwfe/expressions}/fe_raw.rb +39 -75
  25. data/lib/{ru/fe_base.rb → openwfe/expressions/fe_sequence.rb} +40 -35
  26. data/lib/{ru → openwfe/expressions}/fe_subprocess.rb +30 -14
  27. data/lib/{ru → openwfe/expressions}/fe_time.rb +59 -31
  28. data/lib/{ru → openwfe/expressions}/fe_utils.rb +42 -26
  29. data/lib/{ru → openwfe/expressions}/fe_value.rb +20 -14
  30. data/lib/openwfe/expressions/flowexpression.rb +434 -0
  31. data/lib/openwfe/expressions/raw_prog.rb +391 -0
  32. data/lib/openwfe/expressions/raw_xml.rb +128 -0
  33. data/lib/openwfe/flowexpressionid.rb +148 -0
  34. data/lib/{ru → openwfe}/logging.rb +10 -6
  35. data/lib/{osocket.rb → openwfe/osocket.rb} +36 -35
  36. data/lib/{otime.rb → openwfe/otime.rb} +71 -21
  37. data/lib/openwfe/participants/atomparticipants.rb +144 -0
  38. data/lib/openwfe/participants/enoparticipant.rb +73 -0
  39. data/lib/openwfe/participants/participant.rb +85 -0
  40. data/lib/{ru → openwfe/participants}/participantmap.rb +40 -12
  41. data/lib/{ru → openwfe/participants}/participants.rb +41 -12
  42. data/lib/openwfe/participants/soapparticipants.rb +96 -0
  43. data/lib/{controlclient.rb → openwfe/rest/controlclient.rb} +12 -13
  44. data/lib/{definitions.rb → openwfe/rest/definitions.rb} +3 -3
  45. data/lib/{exception.rb → openwfe/rest/exception.rb} +3 -3
  46. data/lib/{restclient.rb → openwfe/rest/restclient.rb} +13 -22
  47. data/lib/{worklistclient.rb → openwfe/rest/worklistclient.rb} +33 -46
  48. data/lib/openwfe/rest/xmlcodec.rb +575 -0
  49. data/lib/{ru → openwfe}/rudefinitions.rb +32 -4
  50. data/lib/{ru → openwfe}/service.rb +20 -8
  51. data/lib/openwfe/storage/yamlfilestorage.rb +159 -0
  52. data/lib/{ru → openwfe/util}/dollar.rb +10 -8
  53. data/lib/openwfe/util/lru_cache.rb +149 -0
  54. data/lib/{ru → openwfe/util}/scheduler.rb +18 -10
  55. data/lib/{ru → openwfe/util}/schedulers.rb +7 -7
  56. data/lib/{utils.rb → openwfe/utils.rb} +93 -9
  57. data/lib/openwfe/workitem.rb +366 -0
  58. data/lib/openwfe/worklist/worklists.rb +175 -0
  59. data/test/README.txt +27 -0
  60. data/test/atomtest.rb +99 -0
  61. data/test/crontest.rb +58 -0
  62. data/test/dollartest.rb +3 -3
  63. data/test/feitest.rb +42 -14
  64. data/test/file_persistence_test.rb +93 -0
  65. data/test/flowtestbase.rb +72 -26
  66. data/test/ft_0.rb +1 -97
  67. data/test/ft_0b_sequence.rb +33 -0
  68. data/test/ft_0c_testname.rb +29 -0
  69. data/test/ft_10_loop.rb +48 -0
  70. data/test/ft_11_ppd.rb +292 -0
  71. data/test/ft_12_blockparticipant.rb +45 -0
  72. data/test/ft_13_eno.rb +51 -0
  73. data/test/ft_14_subprocess.rb +90 -0
  74. data/test/ft_14b_subprocess.rb +40 -0
  75. data/test/ft_15_iterator.rb +70 -0
  76. data/test/ft_16_fqv.rb +57 -0
  77. data/test/ft_1_unset.rb +25 -1
  78. data/test/ft_2_concurrence.rb +10 -5
  79. data/test/ft_3_equals.rb +35 -1
  80. data/test/ft_4_misc.rb +16 -1
  81. data/test/ft_5_time.rb +26 -1
  82. data/test/ft_6_lambda.rb +2 -1
  83. data/test/{ft_7_losfor.rb → ft_7_lose.rb} +41 -35
  84. data/test/ft_8_forget.rb +46 -0
  85. data/test/ft_9_cursor.rb +94 -0
  86. data/test/journal_persistence_test.rb +147 -0
  87. data/test/misctest.rb +13 -9
  88. data/test/rake_ptest.rb +18 -0
  89. data/test/rake_qtest.rb +43 -0
  90. data/test/{fulltest.rb → rake_test.rb} +2 -2
  91. data/test/raw_prog_test.rb +236 -0
  92. data/test/rest_test.rb +189 -0
  93. data/test/rutest_utils.rb +1 -1
  94. data/test/timetest.rb +42 -34
  95. metadata +125 -82
  96. data/lib/codec.rb +0 -573
  97. data/lib/flowexpressionid.rb +0 -139
  98. data/lib/ru/expressionpool.rb +0 -382
  99. data/lib/ru/expressionstorage.rb +0 -99
  100. data/lib/ru/flowexpression.rb +0 -272
  101. data/lib/ru/ruutils.rb +0 -70
  102. data/lib/test.rb +0 -222
  103. data/lib/workitem.rb +0 -249
  104. data/test/quicktest.rb +0 -21
@@ -1,6 +1,6 @@
1
1
  #
2
2
  #--
3
- # Copyright (c) 2006, John Mettraux, OpenWFE.org
3
+ # Copyright (c) 2006-2007, John Mettraux, Nicolas Modrzyk OpenWFE.org
4
4
  # All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without
@@ -37,45 +37,50 @@
37
37
  # "made in Japan"
38
38
  #
39
39
  # John Mettraux at openwfe.org
40
- #
41
-
42
- require 'rexml/document'
40
+ # Nicolas Modrzyk at openwfe.org
41
+ #
43
42
 
44
- require 'workitem'
45
- require 'ru/rudefinitions'
46
- require 'ru/service'
47
- require 'ru/expressionmap'
48
- require 'ru/expressionpool'
49
- require 'ru/expressionstorage'
50
- require 'ru/participantmap'
51
- require 'ru/schedulers'
43
+ require 'openwfe/workitem'
44
+ require 'openwfe/rudefinitions'
45
+ require 'openwfe/service'
46
+ require 'openwfe/util/schedulers'
47
+ require 'openwfe/expool/expressionpool'
48
+ require 'openwfe/expool/expstorage'
49
+ require 'openwfe/expressions/expressionmap'
50
+ require 'openwfe/participants/participantmap'
52
51
 
53
52
 
54
- module OpenWFEru
53
+ module OpenWFE
55
54
 
55
+ #
56
+ # The simplest implementation of the OpenWFE workflow engine.
57
+ # No persistence is used, everything is stored in memory.
58
+ #
56
59
  class Engine < Service
60
+ include OwfeServiceLocator
57
61
 
58
- #attr_accessor \
59
- # :application_context
62
+ def initialize ()
60
63
 
61
- def initialize()
62
-
63
- super('engine', {})
64
+ super(S_ENGINE, {})
64
65
 
65
66
  @application_context[@service_name] = self
66
67
 
67
- @application_context[S_EXPRESSION_MAP] = build_expression_map()
68
- @application_context[S_EXPRESSION_POOL] = build_expression_pool()
69
- @application_context[S_EXPRESSION_STORAGE] = build_expression_storage()
70
- @application_context[S_PARTICIPANT_MAP] = build_participant_map()
71
-
72
- @application_context[S_SCHEDULER] = \
73
- SchedulerService.new(S_SCHEDULER, @application_context)
68
+ build_expression_map()
69
+ build_expression_pool()
70
+ build_expression_storage()
71
+ build_participant_map()
72
+ build_scheduler()
74
73
 
75
74
  init_default_logging('engine.log')
76
75
  end
77
76
 
78
- def launch(object)
77
+ #
78
+ # Launches a [business] process.
79
+ # The 'object' param may contain either a LaunchItem instance,
80
+ # either a String containing the URL of the process definition
81
+ # to launch (with an empty LaunchItem created on the fly).
82
+ #
83
+ def launch (object)
79
84
 
80
85
  launchitem = nil
81
86
 
@@ -95,35 +100,44 @@ module OpenWFEru
95
100
  end
96
101
  end
97
102
 
98
- return @application_context[S_EXPRESSION_POOL].launch(launchitem)
103
+ get_expression_pool.launch(launchitem)
99
104
  end
100
105
 
101
106
  #
102
- # registers a participant in this [embedded] engine
107
+ # Registers a participant in this [embedded] engine.
108
+ # This method is a shortcut to the ParticipantMap method
109
+ # with the same name.
103
110
  #
104
- def register_participant (regex, participant)
111
+ def register_participant (regex, participant=nil, &block)
105
112
 
106
- @application_context[S_PARTICIPANT_MAP]\
107
- .register_participant(regex, participant)
113
+ get_participant_map.register_participant(regex, participant, &block)
108
114
  end
109
115
 
110
116
  protected
111
117
 
118
+ #
119
+ # the following methods may get overridden upon extension
120
+ # see for example file_persisted_engine.rb
121
+ #
122
+
112
123
  def build_expression_map ()
113
- ExpressionMap.new(S_EXPRESSION_MAP, @application_context)
124
+ init_service(S_EXPRESSION_MAP, ExpressionMap)
114
125
  end
115
126
 
116
127
  def build_expression_pool ()
117
- ExpressionPool.new(S_EXPRESSION_POOL, @application_context)
128
+ init_service(S_EXPRESSION_POOL, ExpressionPool)
118
129
  end
119
130
 
120
131
  def build_expression_storage ()
121
- InMemoryExpressionStorage \
122
- .new(S_EXPRESSION_STORAGE, @application_context)
132
+ init_service(S_EXPRESSION_STORAGE, InMemoryExpressionStorage)
123
133
  end
124
134
 
125
135
  def build_participant_map ()
126
- ParticipantMap.new(S_PARTICIPANT_MAP, @application_context)
136
+ init_service(S_PARTICIPANT_MAP, ParticipantMap)
137
+ end
138
+
139
+ def build_scheduler ()
140
+ init_service(S_SCHEDULER, SchedulerService)
127
141
  end
128
142
 
129
143
  end
@@ -1,6 +1,6 @@
1
1
  #
2
- #<tt>
3
- # Copyright (c) 2006, John Mettraux, OpenWFE.org
2
+ #--
3
+ # Copyright (c) 2006-2007, Nicolas Modryzk, OpenWFE.org
4
4
  # All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
28
28
  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
29
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
- #</tt>
31
+ #++
32
32
  #
33
33
  # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
34
  #
@@ -36,34 +36,33 @@
36
36
  #
37
37
  # "made in Japan"
38
38
  #
39
+ # Nicolas Modrzyk at openwfe.org
39
40
  # John Mettraux at openwfe.org
40
41
  #
41
42
 
42
- require 'ru/contextual'
43
+ require 'openwfe/engine/engine'
44
+ require 'openwfe/expool/yamlexpstorage'
43
45
 
44
46
 
45
- module OpenWFEru
47
+ module OpenWFE
46
48
 
47
49
  #
48
- # The 'participant' concept is displayed as a module, so that
49
- # other pieces of code may easily 'mix it in'.
50
+ # An engine persisted to a tree of yaml files
50
51
  #
51
- module Participant
52
- include Contextual
52
+ class FilePersistedEngine < Engine
53
53
 
54
- #
55
- # a participant will be receiving workitems via this method
56
- #
57
- def consume (workitem)
58
- end
54
+ #
55
+ # overrides the method already found in Engine with a persisted
56
+ # expression storage
57
+ #
58
+ def build_expression_storage ()
59
+ #FileExpressionStorage \
60
+ # .new(S_EXPRESSION_STORAGE, @application_context, ENV['HOME'])
59
61
 
60
- #
61
- # when the workflow engine is cancelling a workflow branch, the
62
- # already activated participants are notified via this method
63
- #
64
- def cancel (cancelitem)
65
- end
66
- end
62
+ @application_context[:file_expression_storage_path] = "./work"
67
63
 
64
+ init_service(S_EXPRESSION_STORAGE, YamlFileExpressionStorage)
65
+ end
66
+
67
+ end
68
68
  end
69
-
@@ -0,0 +1,534 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2006-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
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
+ #
35
+
36
+ #
37
+ # "made in Japan"
38
+ #
39
+ # John Mettraux at openwfe.org
40
+ #
41
+
42
+ require 'uri'
43
+ require 'monitor'
44
+ require 'net/http'
45
+ require 'rexml/document'
46
+
47
+ require 'openwfe/utils'
48
+ require 'openwfe/service'
49
+ require 'openwfe/logging'
50
+ require 'openwfe/rudefinitions'
51
+ require 'openwfe/flowexpressionid'
52
+ require 'openwfe/util/lru_cache'
53
+ require 'openwfe/expressions/environment'
54
+ require 'openwfe/expressions/raw_xml'
55
+
56
+ include OpenWFE
57
+
58
+
59
+ module OpenWFE
60
+
61
+ #
62
+ # a small help class for storing monitors provided on demand
63
+ # to expressions that need them
64
+ #
65
+ class MonitorProvider
66
+ include MonitorMixin, Logging
67
+
68
+ MAX_MONITORS = 10000
69
+
70
+ def initialize (application_context=nil)
71
+ super()
72
+ @application_context = application_context
73
+ @monitors = LRUCache.new(MAX_MONITORS)
74
+ end
75
+
76
+ def [] (key)
77
+ synchronize do
78
+ #ldebug { "[] caller :\n" + OpenWFE::caller_to_s(8) }
79
+ mon = @monitors[key]
80
+ if not mon
81
+ #ldebug { "[] creating new Monitor for #{key}" }
82
+ mon = Monitor.new
83
+ @monitors[key] = mon
84
+ else
85
+ #ldebug { "[] already had Monitor for #{key}" }
86
+ end
87
+ return mon
88
+ end
89
+ end
90
+
91
+ def delete (key)
92
+ synchronize do
93
+ #ldebug { "delete() removing Monitor for #{key}" }
94
+ @monitors.delete(key)
95
+ end
96
+ end
97
+ end
98
+
99
+ GONE = "gone"
100
+
101
+ #
102
+ # This special flow expression id is used by the forget() method
103
+ # (which is used by the forget expression and the concurrence
104
+ # synchronization expressions)
105
+ #
106
+ GONE_PARENT_ID = FlowExpressionId.new
107
+ GONE_PARENT_ID.engine_id = GONE
108
+ GONE_PARENT_ID.initial_engine_id = GONE
109
+ GONE_PARENT_ID.workflow_definition_url = GONE
110
+ GONE_PARENT_ID.workflow_definition_name = GONE
111
+ GONE_PARENT_ID.workflow_definition_revision = GONE
112
+ GONE_PARENT_ID.workflow_instance_id = "-1"
113
+ GONE_PARENT_ID.expression_name = GONE
114
+ GONE_PARENT_ID.expression_id = "-1"
115
+ GONE_PARENT_ID.freeze
116
+
117
+ #
118
+ # The ExpressionPool stores expressions (pieces of workflow instance).
119
+ # It's the core of the workflow engine.
120
+ # It relies on an expression storage for actual persistence of the
121
+ # expressions.
122
+ #
123
+ class ExpressionPool < Service
124
+ include MonitorMixin, OwfeServiceLocator
125
+
126
+ @@last_given_instance_id = -1
127
+ #
128
+ # storing at class level the last workflow instance id given
129
+
130
+ def initialize (serviceName, applicationContext)
131
+ super(serviceName, applicationContext)
132
+ @monitors = MonitorProvider.new(application_context)
133
+ end
134
+
135
+ #
136
+ # Obtains a unique monitor for an expression.
137
+ # It avoids the need for the FlowExpression instances to include
138
+ # the monitor mixin by themselves
139
+ #
140
+ def get_monitor (fei)
141
+ return @monitors[fei]
142
+ end
143
+
144
+ #
145
+ # Instantiates a workflow definition and launches it.
146
+ #
147
+ def launch (launchitem)
148
+
149
+ rawExpression = buildRawExpression(launchitem)
150
+
151
+ wi = build_workitem(launchitem)
152
+
153
+ rawExpression.apply(wi)
154
+ end
155
+
156
+ #
157
+ # launches a subprocess
158
+ #
159
+ def launch_template \
160
+ (requesting_expression, template_fei, workitem, params=nil)
161
+
162
+ ldebug { "launch() request for #{template_fei.to_debug_s}" }
163
+
164
+ rawexp, fei = fetch(template_fei)
165
+ rawexp = rawexp.dup()
166
+ rawexp.fei = rawexp.fei.dup()
167
+
168
+ if requesting_expression.kind_of? FlowExpressionId
169
+ rawexp.parent_id = requesting_expression
170
+ rawexp.fei.workflow_instance_id = \
171
+ "#{requesting_expression.workflow_instance_id}.0"
172
+ elsif requesting_expression.kind_of? String
173
+ rawexp.parent_id = nil
174
+ rawexp.fei.workflow_instance_id = \
175
+ "#{requesting_expression}.0"
176
+ else # kind is FlowExpression
177
+ rawexp.parent_id = requesting_expression.fei
178
+ rawexp.fei.workflow_instance_id = \
179
+ "#{requesting_expression.fei.workflow_instance_id}.0"
180
+ end
181
+
182
+ #ldebug do
183
+ # "launch_template() spawning wfid " +
184
+ # "#{rawexp.fei.workflow_instance_id.to_s}"
185
+ #end
186
+
187
+ env = rawexp.new_environment()
188
+
189
+ params.each { |k, v| env[k] = v } if params
190
+ #
191
+ # the new scope gets its own environment
192
+
193
+ rawexp.store_itself()
194
+
195
+ rawexp.apply(workitem)
196
+ end
197
+
198
+ #
199
+ # Evaluates a raw definition expression and
200
+ # returns its body fei
201
+ #
202
+ def evaluate (rawExpression, workitem)
203
+ exp = rawExpression.instantiate_real_expression(workitem)
204
+ fei = exp.evaluate(workitem)
205
+ remove(rawExpression)
206
+ return fei
207
+ end
208
+
209
+ #
210
+ # Applies a given expression (id or expression)
211
+ #
212
+ def apply (exp, workitem)
213
+
214
+ exp, fei = fetch(exp)
215
+
216
+ ldebug { "apply() '#{fei}' (#{fei.class})" }
217
+
218
+ if not exp
219
+ lwarn { "apply() cannot apply missing #{fei.to_debug_s}" }
220
+ return
221
+ end
222
+
223
+ ldebug { "apply() #{fei.to_debug_s}" }
224
+
225
+ workitem.last_expression_id = exp.fei
226
+
227
+ exp.apply(workitem)
228
+ end
229
+
230
+ #
231
+ # Cancels the given expression
232
+ #
233
+ def cancel (exp)
234
+
235
+ exp, fei = fetch(exp)
236
+
237
+ if not exp
238
+ ldebug { "cancel() cannot cancel missing #{fei.to_debug_s}" }
239
+ return nil
240
+ end
241
+
242
+ ldebug { "cancel() for #{fei.to_debug_s}" }
243
+
244
+ inflowitem = exp.cancel()
245
+ remove(exp)
246
+
247
+ return inflowitem
248
+ end
249
+
250
+ #
251
+ # Forgets the given expression (makes sure to substitute its
252
+ # parent_id with the GONE_PARENT_ID constant)
253
+ #
254
+ def forget (exp)
255
+
256
+ exp, fei = fetch(exp)
257
+
258
+ return if not exp
259
+
260
+ exp.parent_id = GONE_PARENT_ID
261
+ exp.store_itself()
262
+ end
263
+
264
+ #
265
+ # Replies to the parent of the given expression.
266
+ #
267
+ def reply_to_parent (exp, workitem)
268
+
269
+ exp, fei = fetch(exp)
270
+
271
+ workitem.last_expression_id = fei
272
+
273
+ remove(exp, workitem)
274
+
275
+ if not exp.parent_id
276
+ ldebug do
277
+ "reply_to_parent() process " +
278
+ "#{exp.fei.workflow_instance_id} terminated"
279
+ end
280
+ else
281
+ if exp.parent_id == GONE_PARENT_ID
282
+ ldebug do
283
+ "reply_to_parent() parent is gone for " +
284
+ exp.fei.to_debug_s
285
+ end
286
+ else
287
+ reply(exp.parent_id, workitem)
288
+ end
289
+ end
290
+ end
291
+
292
+ #
293
+ # Triggers the reply expression of the expression given by its id.
294
+ #
295
+ def reply (exp, workitem)
296
+
297
+ exp, fei = fetch(exp)
298
+
299
+ ldebug { "reply() to #{fei.to_debug_s}" }
300
+ ldebug { "reply() from #{workitem.last_expression_id}" }
301
+
302
+ if not exp
303
+ #raise "cannot reply to missing #{fei.to_debug_s}"
304
+ lwarn { "reply() cannot reply to missing #{fei.to_debug_s}" }
305
+ return
306
+ end
307
+
308
+ exp.reply(workitem)
309
+ end
310
+
311
+ #
312
+ # Adds or updates a flow expression in this pool
313
+ #
314
+ def update (flowExpression)
315
+
316
+ get_expression_storage()[flowExpression.fei] = flowExpression
317
+ end
318
+
319
+ #
320
+ # Fetches a FlowExpression from the pool.
321
+ # Returns a tuple : the FlowExpression plus its FlowExpressionId.
322
+ #
323
+ # The param 'exp' may be a FlowExpressionId or a FlowExpression that
324
+ # has to be reloaded.
325
+ #
326
+ def fetch (exp)
327
+ synchronize do
328
+ fei = exp
329
+ if exp.kind_of? FlowExpression
330
+ fei = exp.fei
331
+ elsif not exp.kind_of? FlowExpressionId
332
+ raise \
333
+ "Cannot fetch expression with key : "+
334
+ "'#{fei}' (#{fei.class})"
335
+ end
336
+ return get_expression_storage()[fei], fei
337
+ end
338
+ end
339
+
340
+ #
341
+ # Fetches a FlowExpression (returns only the FlowExpression instance)
342
+ #
343
+ # The param 'exp' may be a FlowExpressionId or a FlowExpression that
344
+ # has to be reloaded.
345
+ #
346
+ def fetch_expression (exp)
347
+ exp, _fei = fetch(exp)
348
+ return exp
349
+ end
350
+
351
+ def fetch_engine_environment ()
352
+ synchronize do
353
+
354
+ eei = engine_environment_id
355
+ ee, fei = fetch(eei)
356
+
357
+ if not ee
358
+ ee = Environment\
359
+ .new(eei, nil, nil, @application_context, nil)
360
+ ee.store_itself()
361
+ end
362
+
363
+ ldebug { "fetch_engine_environment() stored new ee" }
364
+
365
+ return ee
366
+ end
367
+ end
368
+
369
+ #
370
+ # Removes a flow expression from the pool
371
+ # (This method is mainly called from the pool itself)
372
+ #
373
+ def remove (exp, workitem=nil)
374
+
375
+ exp, fei = fetch(exp)
376
+
377
+ return if not exp
378
+
379
+ ldebug { "remove() fe #{fei.to_debug_s}" }
380
+
381
+ synchronize do
382
+
383
+ @monitors.delete(fei)
384
+
385
+ #get_expression_storage().delete(fei)
386
+ get_expression_storage().remove(fei, workitem)
387
+
388
+ if exp.owns_its_environment?
389
+ remove_environment(exp.environment_id)
390
+ end
391
+
392
+ end
393
+ end
394
+
395
+ def engine_environment_id ()
396
+ synchronize do
397
+ return @eei if @eei
398
+ @eei = FlowExpressionId.new
399
+ @eei.owfe_version = OPENWFE_VERSION
400
+ @eei.engine_id = get_engine.service_name
401
+ @eei.initial_engine_id = @eei.engine_id
402
+ @eei.workflow_definition_url = 'ee'
403
+ @eei.workflow_definition_name = 'ee'
404
+ @eei.workflow_definition_revision = '0'
405
+ @eei.workflow_instance_id = '0'
406
+ @eei.expression_name = EN_ENVIRONMENT
407
+ @eei.expression_id = '0'
408
+ return @eei
409
+ end
410
+ end
411
+
412
+ protected
413
+
414
+ def evaluate_definition (raw_definition, workitem)
415
+ expression = raw_definition.instantiate(workitem)
416
+ end
417
+
418
+ def remove_environment (environment_id)
419
+ env, fei = fetch(environment_id)
420
+ env.unbind()
421
+ get_expression_storage().remove(environment_id, nil)
422
+ end
423
+
424
+ def build_workitem (launchitem)
425
+
426
+ wi = InFlowWorkItem.new()
427
+
428
+ wi.attributes = launchitem.attributes.dup()
429
+
430
+ return wi
431
+ end
432
+
433
+ def fetch_definition (launchitem)
434
+
435
+ wfdUrl = launchitem.workflow_definition_url
436
+
437
+ #ldebug { "wfdUrl is '#{wfdUrl}'" }
438
+
439
+ sDefinition = nil
440
+ wfdField = nil
441
+
442
+ if wfdUrl[0..5] == 'field:'
443
+ wfdField = wfdUrl[6..-1]
444
+ sDefinition = launchitem.attributes[wfdField]
445
+ else
446
+ sDefinition = NET::HTTP.get(URI.parse(wfdUrl))
447
+ end
448
+
449
+ #ldebug { "sDefinition is \n#{sDefinition}" }
450
+
451
+ launchitem.attributes.delete(wfdField) if wfdField
452
+
453
+ if sDefinition.kind_of? String
454
+
455
+ xmlRoot = REXML::Document.new(sDefinition).root
456
+ class << xmlRoot
457
+ def rawExpressionClass
458
+ XmlRawExpression
459
+ end
460
+ end
461
+ return xmlRoot
462
+ end
463
+
464
+ if sDefinition.kind_of? ProgExpRepresentation
465
+
466
+ return sDefinition
467
+ end
468
+
469
+ if sDefinition.kind_of? ProcessDefinition
470
+
471
+ return sDefinition.make()
472
+ end
473
+
474
+ if sDefinition.kind_of? Class
475
+
476
+ return sDefinition.do_make(get_expression_map)
477
+ end
478
+
479
+ raise \
480
+ "Cannot deduce process definition " +
481
+ "out of instance of class #{sDefinition.class}"
482
+ end
483
+
484
+ def new_fei (flow_url, flow_name, flow_revision, exp_name)
485
+
486
+ fei = FlowExpressionId.new
487
+
488
+ fei.owfe_version = OPENWFE_VERSION
489
+ fei.engine_id = get_engine.service_name
490
+ fei.initial_engine_id = fei.engine_id
491
+ fei.workflow_definition_url = flow_url
492
+ fei.workflow_definition_name = flow_name
493
+ fei.workflow_definition_revision = flow_revision
494
+ fei.workflow_instance_id = new_workflow_instance_id()
495
+ fei.expression_id = "0"
496
+ fei.expression_name = exp_name
497
+ return fei
498
+ end
499
+
500
+ def new_workflow_instance_id ()
501
+ synchronize do
502
+ wfid = OpenWFE::current_time_millis()
503
+ wfid = wfid + 1 if wfid == @@last_given_instance_id
504
+ @@last_given_instance_id = wfid
505
+ return wfid.to_s
506
+ end
507
+ end
508
+
509
+ #
510
+ # Builds the RawExpression instance at the root of the flow
511
+ # being launched.
512
+ #
513
+ def buildRawExpression (launchitem)
514
+
515
+ procdef = fetch_definition(launchitem)
516
+
517
+ flow_url = launchitem.workflow_definition_url
518
+ flow_name = procdef.attributes['name']
519
+ flow_revision = procdef.attributes['revision']
520
+ exp_name = procdef.name
521
+
522
+ fei = new_fei(flow_url, flow_name, flow_revision, exp_name)
523
+
524
+ #puts procdef.rawExpressionClass
525
+ #puts procdef.rawExpressionClass.public_methods
526
+
527
+ return procdef.rawExpressionClass\
528
+ .new(fei, nil, nil, @application_context, procdef)
529
+ end
530
+
531
+ end
532
+
533
+ end
534
+