openwferu 0.9.8 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +4 -5
- data/lib/openwfe/engine/engine.rb +14 -14
- data/lib/openwfe/expool/expressionpool.rb +60 -45
- data/lib/openwfe/expool/expstorage.rb +1 -1
- data/lib/openwfe/expressions/condition.rb +47 -34
- data/lib/openwfe/expressions/environment.rb +29 -7
- data/lib/openwfe/expressions/expressionmap.rb +16 -1
- data/lib/openwfe/expressions/fe_concurrence.rb +142 -55
- data/lib/openwfe/expressions/fe_cursor.rb +146 -41
- data/lib/openwfe/expressions/fe_define.rb +52 -35
- data/lib/openwfe/expressions/fe_filter.rb +129 -0
- data/lib/openwfe/expressions/fe_filter_definition.rb +170 -0
- data/lib/openwfe/expressions/fe_iterator.rb +23 -10
- data/lib/openwfe/expressions/fe_losfor.rb +7 -6
- data/lib/openwfe/expressions/fe_participant.rb +19 -9
- data/lib/openwfe/expressions/fe_raw.rb +11 -16
- data/lib/openwfe/expressions/fe_save.rb +225 -0
- data/lib/openwfe/expressions/fe_sequence.rb +15 -10
- data/lib/openwfe/expressions/fe_subprocess.rb +0 -6
- data/lib/openwfe/expressions/fe_value.rb +7 -19
- data/lib/openwfe/expressions/filter.rb +104 -0
- data/lib/openwfe/expressions/flowexpression.rb +102 -36
- data/lib/openwfe/expressions/merge.rb +80 -0
- data/lib/openwfe/expressions/raw_prog.rb +21 -18
- data/lib/openwfe/filterdef.rb +259 -0
- data/lib/openwfe/flowexpressionid.rb +36 -3
- data/lib/openwfe/participants/participants.rb +7 -1
- data/lib/openwfe/rest/xmlcodec.rb +1 -1
- data/lib/openwfe/util/dollar.rb +4 -2
- data/lib/openwfe/util/scheduler.rb +3 -1
- data/lib/openwfe/util/sqs.rb +1 -2
- data/lib/openwfe/utils.rb +13 -0
- data/lib/openwfe/version.rb +1 -1
- data/lib/openwfe/workitem.rb +1 -1
- data/test/filter_test.rb +109 -0
- data/test/flowtestbase.rb +12 -1
- data/test/ft_11_ppd.rb +13 -1
- data/test/ft_11b_ppd.rb +45 -0
- data/test/ft_17_condition.rb +1 -1
- data/test/ft_2b_concurrence.rb +24 -0
- data/test/ft_2c_concurrence.rb +22 -1
- data/test/ft_3_equals.rb +26 -0
- data/test/ft_42_environments.rb +78 -0
- data/test/ft_43_pat10.rb +109 -0
- data/test/ft_44_save.rb +81 -0
- data/test/ft_44b_restore.rb +159 -0
- data/test/ft_45_citerator.rb +104 -0
- data/test/ft_46_pparams.rb +62 -0
- data/test/ft_47_filter.rb +165 -0
- data/test/ft_48_fe_filter.rb +91 -0
- data/test/ft_49_condition.rb +65 -0
- data/test/ft_50_xml_attribute.rb +89 -0
- data/test/ft_9_cursor.rb +36 -6
- data/test/ft_tests.rb +11 -1
- data/test/misc_test.rb +8 -0
- data/test/rake_qtest.rb +2 -2
- data/test/rutest_utils.rb +6 -1
- data/test/sec_test.rb +2 -2
- metadata +20 -2
@@ -59,9 +59,9 @@ module OpenWFE
|
|
59
59
|
:variables
|
60
60
|
|
61
61
|
def initialize \
|
62
|
-
(
|
62
|
+
(fei, parent, environment_id, application_context, attributes)
|
63
63
|
|
64
|
-
super(
|
64
|
+
super(fei, parent, environment_id, application_context, attributes)
|
65
65
|
|
66
66
|
@variables = {}
|
67
67
|
end
|
@@ -147,14 +147,36 @@ module OpenWFE
|
|
147
147
|
end
|
148
148
|
|
149
149
|
#
|
150
|
-
# Returns the top environment for the process instance
|
150
|
+
# Returns the top environment for the process instance (the
|
151
|
+
# environment just before the engine environment).
|
151
152
|
#
|
152
|
-
def get_root_environment
|
153
|
+
def get_root_environment
|
154
|
+
#ldebug { "get_root_environment\n#{self}" }
|
155
|
+
return self if not @parent_id
|
156
|
+
get_parent.get_root_environment
|
157
|
+
end
|
153
158
|
|
154
|
-
|
159
|
+
#def get_subprocess_environment
|
160
|
+
# return self if not @parent_id
|
161
|
+
# return self if @parent_id.sub_instance_id != @fei.sub_instance_id
|
162
|
+
# get_parent.get_subprocess_environment
|
163
|
+
#end
|
155
164
|
|
156
|
-
|
157
|
-
|
165
|
+
#
|
166
|
+
# Returns a deep copy of this environment.
|
167
|
+
#
|
168
|
+
def dup
|
169
|
+
|
170
|
+
env = Environment.new(
|
171
|
+
@fei.dup,
|
172
|
+
@parent_id,
|
173
|
+
@environment_id,
|
174
|
+
@application_context,
|
175
|
+
OpenWFE::fulldup(@attributes))
|
176
|
+
|
177
|
+
env.variables = OpenWFE::fulldup self.variables
|
178
|
+
|
179
|
+
env
|
158
180
|
end
|
159
181
|
end
|
160
182
|
|
@@ -60,6 +60,9 @@ require 'openwfe/expressions/fe_iterator'
|
|
60
60
|
require 'openwfe/expressions/fe_fqv'
|
61
61
|
require 'openwfe/expressions/fe_cancel'
|
62
62
|
require 'openwfe/expressions/fe_do'
|
63
|
+
require 'openwfe/expressions/fe_save'
|
64
|
+
require 'openwfe/expressions/fe_filter_definition'
|
65
|
+
require 'openwfe/expressions/fe_filter'
|
63
66
|
|
64
67
|
|
65
68
|
module OpenWFE
|
@@ -84,6 +87,8 @@ module OpenWFE
|
|
84
87
|
register ConcurrenceExpression
|
85
88
|
register GenericSyncExpression
|
86
89
|
|
90
|
+
register ConcurrentIteratorExpression
|
91
|
+
|
87
92
|
register SubProcessRefExpression
|
88
93
|
|
89
94
|
register SetValueExpression
|
@@ -123,6 +128,12 @@ module OpenWFE
|
|
123
128
|
register UndoExpression
|
124
129
|
register RedoExpression
|
125
130
|
|
131
|
+
register SaveWorkItemExpression
|
132
|
+
register RestoreWorkItemExpression
|
133
|
+
|
134
|
+
register FilterDefinitionExpression
|
135
|
+
register FilterExpression
|
136
|
+
|
126
137
|
register Environment
|
127
138
|
#
|
128
139
|
# only used by get_expression_names()
|
@@ -134,6 +145,9 @@ module OpenWFE
|
|
134
145
|
#
|
135
146
|
def get_class (expression_name)
|
136
147
|
|
148
|
+
expression_name = expression_name.expression_name \
|
149
|
+
if expression_name.kind_of?(RawExpression)
|
150
|
+
|
137
151
|
expression_name = OpenWFE::symbol_to_name(expression_name)
|
138
152
|
|
139
153
|
@expressions[expression_name]
|
@@ -152,7 +166,8 @@ module OpenWFE
|
|
152
166
|
|
153
167
|
c = get_class(expression_name)
|
154
168
|
|
155
|
-
c == DefineExpression
|
169
|
+
#c == DefineExpression
|
170
|
+
(c and c.is_definition?)
|
156
171
|
end
|
157
172
|
|
158
173
|
#
|
@@ -41,8 +41,10 @@
|
|
41
41
|
|
42
42
|
require 'openwfe/utils'
|
43
43
|
require 'openwfe/rudefinitions'
|
44
|
+
require 'openwfe/expressions/merge'
|
44
45
|
require 'openwfe/expressions/condition'
|
45
46
|
require 'openwfe/expressions/flowexpression'
|
47
|
+
require 'openwfe/expressions/fe_iterator'
|
46
48
|
|
47
49
|
|
48
50
|
#
|
@@ -120,12 +122,16 @@ module OpenWFE
|
|
120
122
|
# [override] The default : no mix of values between the workitems do occur
|
121
123
|
# [mix] Priority is given to the 'winning' workitem but their values
|
122
124
|
# get mixed
|
125
|
+
# [isolate] the attributes of the workitem of each branch is placed
|
126
|
+
# in a field in the resulting workitem. For example, the
|
127
|
+
# attributes of the first branch will be stored under the
|
128
|
+
# field named '0' of the resulting workitem.
|
123
129
|
#
|
124
130
|
# The merge occurs are the top level of workitem attributes.
|
125
131
|
#
|
126
132
|
# More complex merge behaviour can be obtained by extending the
|
127
133
|
# GenericSyncExpression class. But the default sync options are already
|
128
|
-
# numerous and powerful.
|
134
|
+
# numerous and powerful by their combinations.
|
129
135
|
#
|
130
136
|
class ConcurrenceExpression < SequenceExpression
|
131
137
|
include ConditionMixin
|
@@ -139,8 +145,8 @@ module OpenWFE
|
|
139
145
|
|
140
146
|
sync = lookup_attribute(:sync, workitem, :generic)
|
141
147
|
|
142
|
-
@sync_expression =
|
143
|
-
get_expression_map
|
148
|
+
@sync_expression =
|
149
|
+
get_expression_map.get_sync_class(sync).new(self, workitem)
|
144
150
|
|
145
151
|
@children.each do |child|
|
146
152
|
@sync_expression.add_child(child)
|
@@ -150,12 +156,16 @@ module OpenWFE
|
|
150
156
|
|
151
157
|
concurrence = self
|
152
158
|
|
153
|
-
@children.
|
159
|
+
@children.each_with_index do |child, index|
|
154
160
|
Thread.new do
|
155
161
|
begin
|
156
162
|
#ldebug { "apply() child : #{child.to_debug_s}" }
|
157
163
|
concurrence.synchronize do
|
158
|
-
|
164
|
+
|
165
|
+
get_expression_pool().apply(
|
166
|
+
child,
|
167
|
+
#workitem.dup)
|
168
|
+
get_workitem(workitem, index))
|
159
169
|
end
|
160
170
|
rescue Exception => e
|
161
171
|
lwarn do
|
@@ -186,6 +196,66 @@ module OpenWFE
|
|
186
196
|
def reply (workitem)
|
187
197
|
@sync_expression.reply(self, workitem)
|
188
198
|
end
|
199
|
+
|
200
|
+
protected
|
201
|
+
|
202
|
+
def get_workitem (workitem, index)
|
203
|
+
workitem.dup
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# This expression is a mix between a 'concurrence' and an 'iterator'.
|
209
|
+
# It understands the same attributes and behaves as an interator that
|
210
|
+
# forks its children concurrently.
|
211
|
+
#
|
212
|
+
# (See ConcurrenceExpression and IteratorExpression).
|
213
|
+
#
|
214
|
+
class ConcurrentIteratorExpression < ConcurrenceExpression
|
215
|
+
|
216
|
+
names :concurrent_iterator
|
217
|
+
|
218
|
+
#attr_accessor :iterator
|
219
|
+
|
220
|
+
def apply (workitem)
|
221
|
+
|
222
|
+
if @children.length < 1
|
223
|
+
reply_to_parent workitem
|
224
|
+
return
|
225
|
+
end
|
226
|
+
|
227
|
+
template = @children[0]
|
228
|
+
|
229
|
+
@children.clear
|
230
|
+
|
231
|
+
@workitems = []
|
232
|
+
|
233
|
+
iterator = Iterator.new(self, workitem)
|
234
|
+
|
235
|
+
while iterator.has_next?
|
236
|
+
|
237
|
+
wi = workitem.dup
|
238
|
+
|
239
|
+
@workitems << wi
|
240
|
+
|
241
|
+
vars = iterator.next self, wi
|
242
|
+
|
243
|
+
rawexp = get_expression_pool.prepare_from_template(
|
244
|
+
self, iterator.index, template, vars)
|
245
|
+
|
246
|
+
@children << rawexp.fei
|
247
|
+
end
|
248
|
+
|
249
|
+
get_expression_pool.remove(template)
|
250
|
+
|
251
|
+
super
|
252
|
+
end
|
253
|
+
|
254
|
+
protected
|
255
|
+
|
256
|
+
def get_workitem (workitem, index)
|
257
|
+
@workitems[index]
|
258
|
+
end
|
189
259
|
end
|
190
260
|
|
191
261
|
#
|
@@ -236,6 +306,8 @@ module OpenWFE
|
|
236
306
|
merge = synchable.lookup_attribute(:merge, workitem, :first)
|
237
307
|
merge_type = synchable.lookup_attribute(:merge_type, workitem, :mix)
|
238
308
|
|
309
|
+
#synchable.ldebug { "new() merge_type is '#{merge_type}'" }
|
310
|
+
|
239
311
|
@merge_array = MergeArray.new(merge, merge_type)
|
240
312
|
|
241
313
|
@unready_queue = []
|
@@ -297,7 +369,7 @@ module OpenWFE
|
|
297
369
|
def do_reply (synchable, workitem)
|
298
370
|
|
299
371
|
synchable.ldebug do
|
300
|
-
"#{self.class}.do_reply()
|
372
|
+
"#{self.class}.do_reply() from"+
|
301
373
|
"#{workitem.last_expression_id.to_debug_s}"
|
302
374
|
end
|
303
375
|
|
@@ -307,6 +379,11 @@ module OpenWFE
|
|
307
379
|
|
308
380
|
@remaining_children.delete(workitem.last_expression_id)
|
309
381
|
|
382
|
+
#synchable.ldebug do
|
383
|
+
# "#{self.class}.do_reply() "+
|
384
|
+
# "remaining children : #{@remaining_children.length}"
|
385
|
+
#end
|
386
|
+
|
310
387
|
if @remaining_children.length <= 0
|
311
388
|
reply_to_parent(synchable)
|
312
389
|
return true
|
@@ -364,8 +441,7 @@ module OpenWFE
|
|
364
441
|
if @cancel_remaining
|
365
442
|
expool.cancel(child)
|
366
443
|
else
|
367
|
-
|
368
|
-
expool.forget(child)
|
444
|
+
expool.forget(synchable, child)
|
369
445
|
end
|
370
446
|
end
|
371
447
|
end
|
@@ -388,11 +464,13 @@ module OpenWFE
|
|
388
464
|
end
|
389
465
|
|
390
466
|
#
|
391
|
-
# This inner class is used to gather workitems before
|
392
|
-
#
|
393
|
-
#
|
467
|
+
# This inner class is used to gather workitems (via push()) before
|
468
|
+
# the final merge
|
469
|
+
# This final merge is triggered by calling the do_merge() method
|
470
|
+
# which will return the resulting, merged workitem.
|
394
471
|
#
|
395
472
|
class MergeArray
|
473
|
+
include MergeMixin
|
396
474
|
|
397
475
|
attr_accessor \
|
398
476
|
:workitem,
|
@@ -403,8 +481,8 @@ module OpenWFE
|
|
403
481
|
|
404
482
|
def initialize (merge, merge_type)
|
405
483
|
|
406
|
-
@merge = merge.downcase
|
407
|
-
@merge_type = merge_type.downcase
|
484
|
+
@merge = merge.strip.downcase.intern
|
485
|
+
@merge_type = merge_type.strip.downcase.intern
|
408
486
|
|
409
487
|
ensure_merge_settings()
|
410
488
|
|
@@ -418,22 +496,48 @@ module OpenWFE
|
|
418
496
|
|
419
497
|
def push (synchable, wi)
|
420
498
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
#
|
425
|
-
source, target = if first?
|
426
|
-
[ @workitem, wi ]
|
427
|
-
else
|
428
|
-
[ wi, @workitem ]
|
429
|
-
end
|
430
|
-
@workitem = merge(target, source)
|
499
|
+
#synchable.ldebug do
|
500
|
+
# "push() isolate? #{isolate?}"
|
501
|
+
#end
|
431
502
|
|
432
|
-
|
503
|
+
if isolate?
|
504
|
+
push_in_isolation wi
|
505
|
+
elsif last? or first?
|
506
|
+
push_by_position wi
|
507
|
+
else
|
508
|
+
push_by_arrival wi
|
433
509
|
end
|
510
|
+
end
|
511
|
+
|
512
|
+
def push_by_position (wi)
|
513
|
+
|
514
|
+
source, target = if first?
|
515
|
+
[ @workitem, wi ]
|
516
|
+
else
|
517
|
+
[ wi, @workitem ]
|
518
|
+
end
|
519
|
+
@workitem = merge_workitems target, source, override?
|
520
|
+
end
|
434
521
|
|
435
|
-
|
436
|
-
|
522
|
+
def push_in_isolation (wi)
|
523
|
+
|
524
|
+
unless @workitem
|
525
|
+
@workitem = wi.dup
|
526
|
+
att = @workitem.attributes
|
527
|
+
@workitem.attributes = {}
|
528
|
+
end
|
529
|
+
|
530
|
+
#key = synchable.children.index wi.last_expression_id
|
531
|
+
key = wi.last_expression_id.child_id
|
532
|
+
|
533
|
+
@workitem.attributes[key.to_s] =
|
534
|
+
OpenWFE::fulldup(wi.attributes)
|
535
|
+
end
|
536
|
+
|
537
|
+
def push_by_arrival (wi)
|
538
|
+
|
539
|
+
#index = synchable.children.index wi.last_expression_id
|
540
|
+
index = Integer(wi.last_expression_id.child_id)
|
437
541
|
|
438
542
|
@workitems_by_arrival << wi
|
439
543
|
@workitems_by_altitude[index] = wi
|
@@ -460,7 +564,7 @@ module OpenWFE
|
|
460
564
|
|
461
565
|
list.each do |wi|
|
462
566
|
next unless wi
|
463
|
-
result =
|
567
|
+
result = merge_workitems result, wi, override?
|
464
568
|
end
|
465
569
|
|
466
570
|
#puts "___ result :"
|
@@ -473,23 +577,26 @@ module OpenWFE
|
|
473
577
|
protected
|
474
578
|
|
475
579
|
def first?
|
476
|
-
@merge ==
|
580
|
+
@merge == :first
|
477
581
|
end
|
478
582
|
def last?
|
479
|
-
@merge ==
|
583
|
+
@merge == :last
|
480
584
|
end
|
481
585
|
def highest?
|
482
|
-
@merge ==
|
586
|
+
@merge == :highest
|
483
587
|
end
|
484
588
|
def lowest?
|
485
|
-
@merge ==
|
589
|
+
@merge == :lowest
|
486
590
|
end
|
487
591
|
|
488
592
|
def mix?
|
489
|
-
@merge_type ==
|
593
|
+
@merge_type == :mix
|
490
594
|
end
|
491
595
|
def override?
|
492
|
-
@merge_type ==
|
596
|
+
@merge_type == :override
|
597
|
+
end
|
598
|
+
def isolate?
|
599
|
+
@merge_type == :isolate
|
493
600
|
end
|
494
601
|
|
495
602
|
#
|
@@ -498,28 +605,8 @@ module OpenWFE
|
|
498
605
|
#
|
499
606
|
def ensure_merge_settings
|
500
607
|
|
501
|
-
@merge_type =
|
502
|
-
@merge =
|
503
|
-
end
|
504
|
-
|
505
|
-
def merge (wiTarget, wiSource)
|
506
|
-
|
507
|
-
return wiSource unless wiTarget
|
508
|
-
return wiTarget unless wiSource
|
509
|
-
|
510
|
-
return wiSource if override?
|
511
|
-
|
512
|
-
wiSource.attributes.each do |k, v|
|
513
|
-
|
514
|
-
#puts "merge() '#{k}' => '#{v}'"
|
515
|
-
|
516
|
-
nk = OpenWFE::fulldup(k)
|
517
|
-
nv = OpenWFE::fulldup(v)
|
518
|
-
|
519
|
-
wiTarget.attributes[nk] = nv
|
520
|
-
end
|
521
|
-
|
522
|
-
wiTarget
|
608
|
+
@merge_type = :mix unless override? or isolate?
|
609
|
+
@merge = :first unless last? or highest? or lowest?
|
523
610
|
end
|
524
611
|
end
|
525
612
|
|
@@ -60,12 +60,37 @@ module OpenWFE
|
|
60
60
|
C_CANCEL = "cancel"
|
61
61
|
C_REWIND = "rewind"
|
62
62
|
C_CONTINUE = "continue"
|
63
|
+
C_JUMP = "jump"
|
63
64
|
|
64
65
|
A_STEP = "step"
|
65
66
|
|
66
67
|
#
|
67
68
|
# The 'cursor' is much like a sequence, but you can go
|
68
|
-
# back and forth within it
|
69
|
+
# back and forth within it, as it reads the field '\_\_cursor_command__' (or
|
70
|
+
# the field specified in the 'command-field' attribute) at each
|
71
|
+
# transition (each time it's supposed to move from one child expression to
|
72
|
+
# the next).
|
73
|
+
#
|
74
|
+
# cursor do
|
75
|
+
# participant "alpha"
|
76
|
+
# skip :step => "2"
|
77
|
+
# participant "bravo"
|
78
|
+
# participant "charly"
|
79
|
+
# set :field => "__cursor_command__", value => "2"
|
80
|
+
# participant "delta"
|
81
|
+
# participant "echo"
|
82
|
+
# skip 2
|
83
|
+
# participant "fox"
|
84
|
+
# #
|
85
|
+
# # in that cursor example, only the participants alpha, charly and
|
86
|
+
# # echo will be handed a workitem
|
87
|
+
# # (notice the last 'skip' with its light syntax)
|
88
|
+
# #
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# As you can see, you can directly set the value of the field
|
92
|
+
# '\_\_cursor_command__' or use a CursorCommandExpression like 'skip' or
|
93
|
+
# 'jump'.
|
69
94
|
#
|
70
95
|
class CursorExpression < WithTemplateExpression
|
71
96
|
|
@@ -100,22 +125,36 @@ module OpenWFE
|
|
100
125
|
return
|
101
126
|
end
|
102
127
|
|
103
|
-
command_field = lookup_command_field
|
104
|
-
|
105
|
-
|
128
|
+
command_field = lookup_command_field workitem
|
129
|
+
|
130
|
+
command, step = lookup_command command_field, workitem
|
131
|
+
|
132
|
+
disallow_list = lookup_disallow workitem
|
106
133
|
|
107
134
|
command = nil \
|
108
|
-
if disallow_list and disallow_list.include?
|
135
|
+
if disallow_list and disallow_list.include?(command)
|
136
|
+
|
137
|
+
ldebug { "reply() command is '#{command} #{step}'" }
|
109
138
|
|
110
139
|
if command == C_BREAK or command == C_CANCEL
|
111
|
-
reply_to_parent
|
140
|
+
reply_to_parent workitem
|
112
141
|
return
|
113
142
|
end
|
114
143
|
|
115
144
|
if command == C_REWIND or command == C_CONTINUE
|
145
|
+
|
116
146
|
@current_child_id = 0
|
117
|
-
|
118
|
-
|
147
|
+
|
148
|
+
elsif command and command.match "^#{C_JUMP}"
|
149
|
+
|
150
|
+
@current_child_id = step
|
151
|
+
@current_child_id = 0 if @current_child_id < 0
|
152
|
+
|
153
|
+
@current_child_id = @children.length - 1 \
|
154
|
+
if @current_child_id >= @children.length
|
155
|
+
|
156
|
+
else # C_SKIP or C_BACK
|
157
|
+
|
119
158
|
@current_child_id = @current_child_id + step
|
120
159
|
|
121
160
|
@current_child_id = 0 if @current_child_id < 0
|
@@ -148,87 +187,151 @@ module OpenWFE
|
|
148
187
|
#
|
149
188
|
# takes care of cancelling the current child if necessary
|
150
189
|
#
|
151
|
-
def cancel
|
190
|
+
def cancel
|
152
191
|
get_expression_pool.cancel(@current_child_fei) \
|
153
192
|
if @current_child_fei
|
154
|
-
super
|
193
|
+
super
|
155
194
|
end
|
156
195
|
|
157
196
|
#
|
158
|
-
#
|
197
|
+
# Returns false, the child class LoopExpression does return true.
|
159
198
|
#
|
160
199
|
def is_loop
|
161
|
-
|
200
|
+
false
|
162
201
|
end
|
163
202
|
|
164
203
|
protected
|
165
204
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
step = 1
|
171
|
-
|
172
|
-
ss = command.split()
|
173
|
-
|
174
|
-
if ss.length > 1
|
175
|
-
step = Integer(ss[1])
|
176
|
-
end
|
177
|
-
|
178
|
-
step = -step if OpenWFE::starts_with(command, C_BACK)
|
179
|
-
|
180
|
-
return step
|
181
|
-
end
|
182
|
-
|
205
|
+
#
|
206
|
+
# Makes sure that only flow expression are left in the cursor
|
207
|
+
# children list (text and comment nodes get discarded).
|
208
|
+
#
|
183
209
|
def clean_children_list
|
184
210
|
|
185
211
|
c = @children
|
186
212
|
@children = []
|
187
213
|
c.each do |child|
|
188
214
|
@children << child \
|
189
|
-
if child.kind_of?
|
215
|
+
if child.kind_of?(OpenWFE::FlowExpressionId)
|
190
216
|
end
|
191
217
|
end
|
192
218
|
|
219
|
+
#
|
220
|
+
# Looks up the value in the command field.
|
221
|
+
#
|
193
222
|
def lookup_command_field (workitem)
|
194
223
|
|
195
|
-
|
224
|
+
lookup_attribute(A_COMMAND_FIELD, workitem, F_COMMAND)
|
196
225
|
end
|
197
226
|
|
227
|
+
#
|
228
|
+
# Returns the command and the step
|
229
|
+
#
|
198
230
|
def lookup_command (command_field, workitem)
|
199
231
|
|
200
232
|
command = workitem.attributes[command_field]
|
201
|
-
command = command.strip() if command
|
202
233
|
|
203
|
-
return command
|
234
|
+
return [ nil, 1 ] unless command
|
235
|
+
#
|
236
|
+
# this corresponds to the "just one step forward" default
|
237
|
+
|
238
|
+
command, step = command.strip.split
|
239
|
+
|
240
|
+
step = if step
|
241
|
+
step.to_i
|
242
|
+
else
|
243
|
+
1
|
244
|
+
end
|
245
|
+
|
246
|
+
step = -step if command == C_BACK
|
247
|
+
|
248
|
+
[ command, step ]
|
204
249
|
end
|
205
250
|
|
251
|
+
#
|
252
|
+
# Fetches the value of the 'disallow' cursor attribute.
|
253
|
+
#
|
206
254
|
def lookup_disallow (workitem)
|
207
255
|
|
208
|
-
|
256
|
+
lookup_comma_list_attribute(A_DISALLOW, workitem)
|
209
257
|
end
|
210
258
|
end
|
211
259
|
|
212
260
|
#
|
213
261
|
# The 'loop' expression is like 'cursor' but it doesn't exit until
|
214
|
-
# it's broken.
|
262
|
+
# it's broken (with 'break' or 'cancel').
|
215
263
|
#
|
216
264
|
class LoopExpression < CursorExpression
|
217
265
|
|
218
266
|
names :loop
|
219
267
|
|
220
268
|
def is_loop
|
221
|
-
|
269
|
+
true
|
222
270
|
end
|
223
271
|
end
|
224
272
|
|
225
273
|
#
|
226
|
-
#
|
274
|
+
# This class implements the following expressions : back, break,
|
275
|
+
# cancel, continue, jump, rewind, skip.
|
276
|
+
#
|
277
|
+
# They are generally used inside of a 'cursor' (CursorExpression) or
|
278
|
+
# a 'loop' (LoopExpression), they can be used outside, but their result
|
279
|
+
# (the value of the field '\_\_cursor_command__' will be used as soon as the
|
280
|
+
# flow enters a cursor or a loop).
|
281
|
+
#
|
282
|
+
# In fact, this expression is only a nice wrapper that sets the
|
283
|
+
# value of the field "\_\_cursor_command__" to its name ('back' for example)
|
284
|
+
# plus to the 'step' attribute value.
|
285
|
+
#
|
286
|
+
# For example <skip step="3"/> simply sets the value of the field
|
287
|
+
# '\_\_cursor_command__' to 'skip 3'.
|
288
|
+
#
|
289
|
+
# (The field \_\_cursor_command__ is, by default, read and
|
290
|
+
# obeyed by the 'cursor' expression).
|
291
|
+
#
|
292
|
+
# With Ruby process definitions, you can directly write :
|
293
|
+
#
|
294
|
+
# skip 2
|
295
|
+
# jump "0"
|
296
|
+
#
|
297
|
+
# instead of
|
298
|
+
#
|
299
|
+
# skip :step => "2"
|
300
|
+
# jump :step => "0"
|
301
|
+
#
|
302
|
+
# Likewise, in an XML process definition, you can write
|
303
|
+
#
|
304
|
+
# <skip>2</skip>
|
305
|
+
#
|
306
|
+
# although that might still look lighter (it's longer though) :
|
307
|
+
#
|
308
|
+
# <skip step="2"/>
|
309
|
+
#
|
310
|
+
#
|
311
|
+
# About the command themselves :
|
312
|
+
#
|
313
|
+
# * back : will go back from the number of given steps, 1 by default
|
314
|
+
# * break : will exit the cursor (or the loop)
|
315
|
+
# * cancel : an alias for 'break'
|
316
|
+
# * continue : will exit the cursor, if in a loop, will get back at step 0
|
317
|
+
# * jump : will move the cursor (or loop) to an absolute given position (count starts at 0)
|
318
|
+
# * rewind : an alias for continue
|
319
|
+
# * skip : skips the given number of steps
|
320
|
+
#
|
321
|
+
#
|
322
|
+
# All those command support an 'if' attribute to restrict their execution :
|
323
|
+
#
|
324
|
+
# cursor do
|
325
|
+
# go_to_shop
|
326
|
+
# check_prices
|
327
|
+
# _break :if => "${price} > ${f:current_cash}"
|
328
|
+
# buy_stuff
|
329
|
+
# end
|
227
330
|
#
|
228
331
|
class CursorCommandExpression < FlowExpression
|
229
332
|
include ConditionMixin
|
230
333
|
|
231
|
-
names :back, :skip, :continue, :break, :cancel, :rewind
|
334
|
+
names :back, :skip, :continue, :break, :cancel, :rewind, :jump
|
232
335
|
|
233
336
|
def apply (workitem)
|
234
337
|
|
@@ -240,15 +343,17 @@ module OpenWFE
|
|
240
343
|
|
241
344
|
command = @fei.expression_name
|
242
345
|
|
243
|
-
step = lookup_attribute(A_STEP, workitem
|
346
|
+
step = lookup_attribute(A_STEP, workitem)
|
347
|
+
step = fetch_text_content(workitem) unless step
|
348
|
+
step = 1 unless step
|
244
349
|
step = Integer(step)
|
245
350
|
|
246
|
-
command = "#{command} #{step}" if step != 1
|
351
|
+
command = "#{command} #{step}" #if step != 1
|
247
352
|
|
248
353
|
workitem.attributes[F_COMMAND] = command
|
249
354
|
end
|
250
355
|
|
251
|
-
reply_to_parent
|
356
|
+
reply_to_parent workitem
|
252
357
|
end
|
253
358
|
end
|
254
359
|
|