openwferu 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/examples/mano_tracker.rb +13 -6
  2. data/examples/quotereporter.rb +3 -2
  3. data/lib/openwfe/engine/engine.rb +31 -4
  4. data/lib/openwfe/engine/file_persisted_engine.rb +35 -9
  5. data/lib/openwfe/expool/expressionpool.rb +116 -67
  6. data/lib/openwfe/expool/expstorage.rb +142 -101
  7. data/lib/openwfe/expool/history.rb +7 -2
  8. data/lib/openwfe/expool/yamlexpstorage.rb +150 -6
  9. data/lib/openwfe/expressions/{fe_condition.rb → condition.rb} +4 -6
  10. data/lib/openwfe/expressions/expressionmap.rb +8 -0
  11. data/lib/openwfe/expressions/fe_cancel.rb +109 -0
  12. data/lib/openwfe/expressions/fe_concurrence.rb +252 -16
  13. data/lib/openwfe/expressions/fe_cursor.rb +8 -3
  14. data/lib/openwfe/{util/stoppable.rb → expressions/fe_do.rb} +42 -11
  15. data/lib/openwfe/expressions/fe_iterator.rb +4 -3
  16. data/lib/openwfe/expressions/fe_misc.rb +3 -2
  17. data/lib/openwfe/expressions/fe_participant.rb +5 -0
  18. data/lib/openwfe/expressions/fe_raw.rb +10 -2
  19. data/lib/openwfe/expressions/fe_subprocess.rb +1 -1
  20. data/lib/openwfe/expressions/fe_time.rb +43 -23
  21. data/lib/openwfe/expressions/fe_value.rb +1 -1
  22. data/lib/openwfe/expressions/flowexpression.rb +22 -22
  23. data/lib/openwfe/expressions/raw_prog.rb +20 -39
  24. data/lib/openwfe/expressions/raw_xml.rb +6 -6
  25. data/lib/openwfe/expressions/timeout.rb +8 -3
  26. data/lib/openwfe/expressions/wtemplate.rb +67 -0
  27. data/lib/openwfe/flowexpressionid.rb +4 -1
  28. data/lib/openwfe/participants/atomparticipants.rb +13 -1
  29. data/lib/openwfe/participants/enoparticipant.rb +66 -5
  30. data/lib/openwfe/participants/participantmap.rb +12 -0
  31. data/lib/openwfe/rudefinitions.rb +15 -3
  32. data/lib/openwfe/service.rb +4 -5
  33. data/lib/openwfe/storage/yamlfilestorage.rb +72 -45
  34. data/lib/openwfe/util/dollar.rb +17 -4
  35. data/lib/openwfe/util/lru.rb +154 -0
  36. data/lib/openwfe/util/otime.rb +26 -5
  37. data/lib/openwfe/util/scheduler.rb +44 -36
  38. data/lib/openwfe/util/schedulers.rb +4 -2
  39. data/lib/openwfe/utils.rb +62 -0
  40. data/lib/openwfe/version.rb +1 -1
  41. data/lib/openwfe/worklist/storeparticipant.rb +34 -5
  42. data/test/eno_test.rb +69 -0
  43. data/test/file_persistence_test.rb +13 -11
  44. data/test/flowtestbase.rb +29 -15
  45. data/test/ft_0.rb +2 -1
  46. data/test/ft_0b_sequence.rb +2 -1
  47. data/test/ft_0c_testname.rb +6 -5
  48. data/test/ft_0d_participant.rb +2 -1
  49. data/test/ft_10_loop.rb +11 -6
  50. data/test/ft_10b_loop2.rb +63 -0
  51. data/test/ft_11_ppd.rb +39 -13
  52. data/test/ft_12_blockparticipant.rb +2 -1
  53. data/test/ft_13_eno.rb +3 -2
  54. data/test/ft_14_subprocess.rb +2 -1
  55. data/test/ft_14b_subprocess.rb +2 -1
  56. data/test/ft_15_iterator.rb +2 -1
  57. data/test/ft_16_fqv.rb +2 -1
  58. data/test/ft_17_condition.rb +2 -1
  59. data/test/ft_18_pname.rb +2 -1
  60. data/test/ft_19_csv.rb +2 -1
  61. data/test/ft_1_unset.rb +14 -18
  62. data/test/ft_1b_unset.rb +39 -0
  63. data/test/ft_20_cron.rb +2 -1
  64. data/test/ft_21_cron.rb +2 -1
  65. data/test/ft_22_history.rb +7 -5
  66. data/test/ft_23_when.rb +2 -1
  67. data/test/ft_23b_when.rb +2 -1
  68. data/test/ft_24_def.rb +2 -1
  69. data/test/ft_25_cancel.rb +79 -0
  70. data/test/ft_26_load.rb +197 -0
  71. data/test/ft_2_concurrence.rb +89 -15
  72. data/test/ft_2b_concurrence.rb +152 -0
  73. data/test/ft_2c_concurrence.rb +39 -0
  74. data/test/ft_3_equals.rb +4 -3
  75. data/test/ft_4_misc.rb +4 -3
  76. data/test/ft_5_time.rb +2 -1
  77. data/test/ft_6_lambda.rb +2 -1
  78. data/test/ft_7_lose.rb +53 -17
  79. data/test/ft_8_forget.rb +7 -6
  80. data/test/ft_9_cursor.rb +8 -7
  81. data/test/hparticipant_test.rb +37 -14
  82. data/test/lru_test.rb +79 -0
  83. data/test/misc_test.rb +16 -0
  84. data/test/rake_qtest.rb +7 -0
  85. data/test/raw_prog_test.rb +0 -13
  86. data/test/rutest_utils.rb +15 -2
  87. data/test/scheduler_test.rb +31 -4
  88. data/test/timeout_test.rb +6 -2
  89. data/test/wfid_test.rb +68 -0
  90. metadata +169 -158
  91. data/lib/openwfe/expool/journalexpstorage.rb +0 -312
  92. data/lib/openwfe/util/lru_cache.rb +0 -149
@@ -40,110 +40,123 @@
40
40
  # John Mettraux at openwfe.org
41
41
  #
42
42
 
43
+ #require 'monitor'
43
44
  require 'fileutils'
44
45
 
45
46
  require 'openwfe/service'
46
- require 'openwfe/util/lru_cache'
47
+ require 'openwfe/util/lru'
47
48
  require 'openwfe/flowexpressionid'
48
49
 
49
50
  module OpenWFE
50
51
 
51
52
  #
52
- # Create a composite expression storage.
53
- # This will take parameters from the application context to create
54
- # the resulting composite storage
55
- class CompositeExpressionStorage
56
- include ServiceMixin
57
-
58
- attr_accessor \
59
- :persistence, \
60
- :cache, \
61
- :journal
62
-
63
- def initialize (serviceName, applicationContext)
64
-
65
- service_init(serviceName, applicationContext)
66
-
67
- @cache = @application_context[:cached_expression_storage]
68
- @journal = @application_context[:journalized_expression_storage]
69
- @persistence = @application_context[:file_expression_storage]
70
- end
71
-
72
- #
73
- # call the add method for each registered storage
74
- #
75
- def []= (fei, flowExpression)
76
- @journal[fei] = flowExpression if @journal
77
- @cache[fei] = flowExpression if @cache
78
- @persistence[fei] = flowExpression
79
- end
80
-
81
- #
82
- # remove the expressionid from each registered storage
83
- #
84
- def delete (fei)
85
- @journal.delete(fei) if @journal
86
- @cache.delete(fei) if @cache
87
- @persistence.delete(fei)
88
- end
89
-
90
- #
91
- # slightly different method. Try to get the value from the cache storage if one
92
- # if not retrieve it, and then add it to the cache.
93
- def [] (fei)
94
- return @cache[fei] if @cache
95
- flow_expression = @persistence[fei]
96
- @cache[fei] = flow_expression if @cache
97
- return flow_expression
98
- end
99
- end
100
-
101
- #
102
- # implementation of a LRU caching storage.
103
- class LruCachedExpressionStorage
104
- include ServiceMixin
105
-
106
- DEFAULT_LRU_SIZE = 10
107
-
53
+ # This cache uses a LruHash (Least Recently Used) to store expressions.
54
+ # If an expression is not cached, the 'real storage' is consulted.
55
+ # The real storage is supposed to be the service named
56
+ # "expressionStorage.1"
57
+ #
58
+ class CacheExpressionStorage
59
+ include ServiceMixin, OwfeServiceLocator
60
+
61
+ DEFAULT_SIZE = 5000
62
+
108
63
  def initialize (service_name, application_context)
64
+
65
+ super()
66
+
109
67
  service_init(service_name, application_context)
110
- size = if (@application_context)
111
- @application_context[:lru_storage_size]
112
- else
113
- DEFAULT_LRU_SIZE
68
+
69
+ size = @application_context[:expression_cache_size]
70
+ size = DEFAULT_SIZE unless size
71
+
72
+ linfo { "new() size is #{size}" }
73
+
74
+ @cache = LruHash.new(size)
75
+
76
+ @real_storage = nil
77
+
78
+ #
79
+ # expstorage observes expool :
80
+
81
+ get_expression_pool.add_observer(:update) do |channel, fei, fe|
82
+ ldebug { ":update for #{fei}" }
83
+ self[fei] = fe
84
+ end
85
+ get_expression_pool.add_observer(:remove) do |channel, fei|
86
+ ldebug { ":delete for #{fei}" }
87
+ self.delete(fei)
114
88
  end
115
- @cache = LRUCache.new(size)
116
89
  end
117
-
118
- def []= (fei, flowExpression)
119
- @cache[fei]=flowExpression
90
+
91
+ def [] (fei)
92
+
93
+ #ldebug { "[] size is #{@cache.size}" }
94
+ ldebug { "[] (sz #{@cache.size}) for #{fei.to_debug_s}" }
95
+
96
+ fe = @cache[fei]
97
+ return fe if fe
98
+
99
+ ldebug { "[] (reload) for #{fei.to_debug_s}" }
100
+
101
+ fe = get_real_storage[fei]
102
+
103
+ return nil unless fe
104
+
105
+ @cache[fei] = fe
106
+
107
+ return fe
120
108
  end
121
-
122
- #
123
- # interface method to remove an entry for the given expression_id
124
- #
109
+
110
+ def []= (fei, fe)
111
+ @cache[fei] = fe
112
+ end
113
+
125
114
  def delete (fei)
126
115
  @cache.delete(fei)
127
116
  end
128
-
129
- #
130
- # check if the value is in the cache
131
- def is_in_cache?(fei)
132
- @cache.include?(fei)
117
+
118
+ def length
119
+ @cache.length
133
120
  end
134
- alias has_key? is_in_cache?
135
-
121
+
122
+ alias :size :length
123
+
124
+ def clear
125
+ @cache.clear
126
+ end
127
+
128
+ alias :purge :clear
129
+
136
130
  #
137
- # interface method, return the value associated with the given id,
138
- # or nil if not in cache.
139
- def [] (fei)
140
- if(@cache.include?(fei))
141
- return @cache[fei]
142
- else
143
- return nil
131
+ # Simply redirects the call to the each_of_kind() method of
132
+ # the 'real storage'.
133
+ #
134
+ def each_of_kind (kind, &block)
135
+
136
+ get_real_storage.each_of_kind(kind, &block)
137
+ end
138
+
139
+ def each (&block)
140
+ @cache.each do |k, v|
141
+ block.call(k, v)
144
142
  end
145
143
  end
146
-
144
+
145
+ def to_s
146
+ expstorage_to_s(self)
147
+ end
148
+
149
+ protected
150
+
151
+ def get_real_storage
152
+
153
+ return @real_storage if @real_storage
154
+
155
+ @real_storage =
156
+ @application_context[S_EXPRESSION_STORAGE + ".1"]
157
+
158
+ return @real_storage
159
+ end
147
160
  end
148
161
 
149
162
  #
@@ -151,34 +164,62 @@ module OpenWFE
151
164
  # No memory limit, puts everything in a Hash
152
165
  #
153
166
  class InMemoryExpressionStorage < Hash
154
- include ServiceMixin
167
+ include ServiceMixin, OwfeServiceLocator
155
168
 
156
169
  def initialize (service_name, application_context)
170
+
157
171
  service_init(service_name, application_context)
172
+
173
+ #
174
+ # expstorage observes expool :
175
+
176
+ get_expression_pool.add_observer(:update) do |channel, fei, fe|
177
+ #ldebug { ":update for #{fei}" }
178
+ self[fei] = fe
179
+ end
180
+ get_expression_pool.add_observer(:remove) do |channel, fei|
181
+ #ldebug { ":delete for #{fei}" }
182
+ self.delete(fei)
183
+ end
158
184
  end
159
185
 
160
186
  alias :purge :clear
161
187
 
162
- def each_of_kind (kind)
163
- # TODO : implement with a filter
188
+ def each_of_kind (kind, &block)
189
+
190
+ return unless block
191
+
192
+ self.each_value do |fexp|
193
+ block.call(fexp) if fexp.kind_of? kind
194
+ end
164
195
  end
165
-
196
+
166
197
  def to_s
167
- s = "\n\n==== #{self.class} ===="
168
- each do |k, v|
169
- s << "\n"
170
- if v.kind_of?(RawExpression)
171
- s << "*raw"
172
- else
173
- s << " "
174
- end
175
- s << v.to_s
176
- s << " key/value mismatch !" if k != v.fei
177
- end
178
- s << "\n==== . ====\n"
179
- return s
198
+ expstorage_to_s(self)
180
199
  end
181
200
 
182
201
  end
183
202
 
203
+ #
204
+ # a small help method for expression storages...
205
+ #
206
+ def expstorage_to_s (expstorage)
207
+
208
+ s = "\n\n==== #{expstorage.class} ===="
209
+
210
+ expstorage.each do |k, v|
211
+ s << "\n"
212
+ if v.kind_of?(RawExpression)
213
+ s << "*raw"
214
+ else
215
+ s << " "
216
+ end
217
+ s << v.to_s
218
+ s << " key/value mismatch !" if k != v.fei
219
+ end
220
+ s << "\n==== . ====\n"
221
+
222
+ return s
223
+ end
224
+
184
225
  end
@@ -39,7 +39,7 @@
39
39
  # John Mettraux at openwfe.org
40
40
  #
41
41
 
42
- #require 'monitor'
42
+ #require 'date'
43
43
 
44
44
  require 'openwfe/service'
45
45
  require 'openwfe/rudefinitions'
@@ -91,7 +91,12 @@ module OpenWFE
91
91
  end
92
92
 
93
93
  def log (event, *args)
94
- msg = ""
94
+
95
+ return if event == :stop
96
+ return if event == :reschedule
97
+
98
+ msg = "#{Time.now.to_s} -- "
99
+
95
100
  msg << event.to_s
96
101
 
97
102
  msg << " #{args[0].to_s}" \
@@ -40,8 +40,6 @@
40
40
  # John Mettraux at openwfe.org
41
41
  #
42
42
 
43
- #require 'find'
44
-
45
43
  require 'openwfe/utils'
46
44
  require 'openwfe/rudefinitions'
47
45
  require 'openwfe/storage/yamlfilestorage'
@@ -109,6 +107,8 @@ module OpenWFE
109
107
  path = path + '/expool'
110
108
 
111
109
  super(service_name, application_context, path)
110
+
111
+ observe_expool()
112
112
  end
113
113
 
114
114
  #
@@ -149,6 +149,24 @@ module OpenWFE
149
149
  end
150
150
 
151
151
  protected
152
+
153
+ #
154
+ # The actual binding of this storage as an observer of the
155
+ # expression pool is done here.
156
+ # It gives the opportunity to override this method with variants
157
+ # (for example for delayed execution)
158
+ #
159
+ def observe_expool
160
+
161
+ get_expression_pool.add_observer(:update) do |channel, fei, fe|
162
+ #ldebug { ":update for #{fei.to_debug_s}" }
163
+ self[fei] = fe
164
+ end
165
+ get_expression_pool.add_observer(:remove) do |channel, fei|
166
+ #ldebug { ":remove for #{fei.to_debug_s}" }
167
+ self.delete(fei)
168
+ end
169
+ end
152
170
 
153
171
  def compute_file_path (fei)
154
172
 
@@ -157,10 +175,10 @@ module OpenWFE
157
175
 
158
176
  wfid = fei.parent_workflow_instance_id
159
177
 
160
- @basepath + "/" +
161
- wfid[-1, 1] + "/" +
178
+ @basepath +
179
+ #wfid[-3, 1] + "/" +
162
180
  wfid[-2, 1] + "/" +
163
- wfid + "/" +
181
+ wfid[-1, 1] + "/" +
164
182
  fei.workflow_instance_id + "__" +
165
183
  fei.expression_id + "_" +
166
184
  fei.expression_name + ".yaml"
@@ -175,6 +193,132 @@ module OpenWFE
175
193
 
176
194
  return false
177
195
  end
178
-
196
+ end
197
+
198
+ #
199
+ # With this extension of YmalFileExpressionStorage, persistence occurs
200
+ # in a separate thread, for a snappier response.
201
+ #
202
+ class ThreadedYamlFileExpressionStorage < YamlFileExpressionStorage
203
+
204
+ def initialize (service_name, application_context)
205
+
206
+ super
207
+
208
+ @events = {}
209
+ @op_count = 0
210
+
211
+ @stopped = false
212
+
213
+ start_processing_thread()
214
+ end
215
+
216
+ #
217
+ # Will take care of stopping the 'queue processing' thread.
218
+ #
219
+ def stop
220
+
221
+ @stopped = true
222
+
223
+ process_queue()
224
+ #
225
+ # flush every remaining events (especially the :delete ones)
226
+ end
227
+
228
+ #
229
+ # calls process_queue() before the call the super class each_of_kind()
230
+ # method
231
+ #
232
+ def each_of_kind (kind, &block)
233
+
234
+ #ldebug { "each_of_kind()" }
235
+
236
+ process_queue()
237
+ super
238
+ end
239
+
240
+ protected
241
+
242
+ def start_processing_thread
243
+ Thread.new do
244
+ while true
245
+ sleep(0.33)
246
+ break if @stopped
247
+ process_queue()
248
+ end
249
+ end
250
+ end
251
+
252
+ def queue (event, fei, fe=nil)
253
+ synchronize do
254
+
255
+ old_size = @events.size
256
+ @op_count += 1
257
+
258
+ @events[fei] = [ event, fei, fe ]
259
+
260
+ ldebug do
261
+ "queue() ops #{@op_count} "+
262
+ "size #{old_size} -> #{@events.size}"
263
+ end
264
+ end
265
+ end
266
+
267
+ def process_queue ()
268
+
269
+ return unless @events.size > 0
270
+ #
271
+ # trying to exit as quickly as possible
272
+
273
+ ldebug do
274
+ "process_queue() #{@events.size} events #{@op_count} ops"
275
+ end
276
+
277
+ synchronize do
278
+ @events.each_value do |v|
279
+ event = v[0]
280
+ begin
281
+ if event == :update
282
+ self[v[1]] = v[2]
283
+ else
284
+ safe_delete(v[1])
285
+ end
286
+ rescue Exception => e
287
+ lwarn do
288
+ "process_queue() ':#{event}' exception\n" +
289
+ OpenWFE::exception_to_s(e)
290
+ end
291
+ end
292
+ end
293
+ @op_count = 0
294
+ @events.clear
295
+ end
296
+ end
297
+
298
+ #
299
+ # a call to delete that tolerates missing .yaml files
300
+ #
301
+ def safe_delete (fei)
302
+ begin
303
+ self.delete(fei)
304
+ rescue Exception => e
305
+ # lwarn do
306
+ # "safe_delete() exception\n" +
307
+ # OpenWFE::exception_to_s(e)
308
+ # end
309
+ end
310
+ end
311
+
312
+ def observe_expool
313
+
314
+ get_expression_pool.add_observer(:update) do |event, fei, fe|
315
+ ldebug { ":update for #{fei.to_debug_s}" }
316
+ queue(event, fei, fe)
317
+ end
318
+ get_expression_pool.add_observer(:remove) do |event, fei|
319
+ ldebug { ":remove for #{fei.to_debug_s}" }
320
+ queue(event, fei)
321
+ end
322
+ end
179
323
  end
180
324
  end
@@ -39,9 +39,6 @@
39
39
  # John Mettraux at openwfe.org
40
40
  #
41
41
 
42
- #require 'openwfe/workitem'
43
- #require 'openwfe/flowexpressionid'
44
-
45
42
 
46
43
  module OpenWFE
47
44
 
@@ -83,10 +80,11 @@ module OpenWFE
83
80
 
84
81
  ldebug { "eval_condition() 2 for '#{conditional}'" }
85
82
 
86
- return true if conditional == '"true"'
87
- return false if conditional == '"false"'
83
+ result = instance_eval(conditional)
84
+
85
+ ldebug { "eval_condition() 3 result is '#{result}'" }
88
86
 
89
- return instance_eval(conditional)
87
+ return (result == "true" or result == true)
90
88
  end
91
89
 
92
90
  private
@@ -53,6 +53,7 @@ require 'openwfe/expressions/fe_losfor'
53
53
  require 'openwfe/expressions/fe_cursor'
54
54
  require 'openwfe/expressions/fe_iterator'
55
55
  require 'openwfe/expressions/fe_fqv'
56
+ require 'openwfe/expressions/fe_cancel'
56
57
 
57
58
 
58
59
  module OpenWFE
@@ -116,6 +117,13 @@ module OpenWFE
116
117
  @map["q"] = FqvExpression
117
118
  @map["v"] = FqvExpression
118
119
 
120
+ #@map["do"] = DoExpression
121
+ #@map["undo"] = UndoExpression
122
+ #@map["redo"] = RedoExpression
123
+
124
+ @map["cancel-process"] = CancelProcessExpression
125
+ #@map["cancel"] = CancelExpression
126
+
119
127
  @map["environment"] = Environment
120
128
  #
121
129
  # only used by get_expression_names()
@@ -0,0 +1,109 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2007, John Mettraux, OpenWFE.org
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # . Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # . Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
17
+ # used to endorse or promote products derived from this software without
18
+ # specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #++
32
+ #
33
+ # $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 'openwfe/expressions/condition'
43
+ require 'openwfe/expressions/flowexpression'
44
+
45
+
46
+ module OpenWFE
47
+
48
+ #
49
+ # This expression cancels the current process instance. Use with care.
50
+ #
51
+ # <sequence>
52
+ # <participant ref="before" />
53
+ # <cancel-process />
54
+ # <participant ref="after" />
55
+ # </sequence>
56
+ #
57
+ # the message "after" will never get printed.
58
+ #
59
+ # Use rather in scenarii like that one :
60
+ #
61
+ # class TestDefinition1 < ProcessDefinition
62
+ # def make
63
+ # process_definition :name => "25_cancel", :revision => "1" do
64
+ # sequence do
65
+ # participant "customer"
66
+ # _cancel_process :if => "${f:no_thanks} == true"
67
+ # concurrence do
68
+ # participant "accounting"
69
+ # participant "logistics"
70
+ # end
71
+ # end
72
+ # end
73
+ # end
74
+ # end
75
+ #
76
+ # Note that the expression accepts an "if" attribute.
77
+ #
78
+ class CancelProcessExpression < FlowExpression
79
+ include ConditionMixin
80
+
81
+ #
82
+ # apply / reply
83
+
84
+ def apply (workitem)
85
+
86
+ conditional = eval_condition(:if, workitem)
87
+ #
88
+ # for example : <cancel-process if="${approved} == false"/>
89
+
90
+ if conditional == false
91
+ reply_to_parent(workitem)
92
+ return
93
+ end
94
+
95
+ #
96
+ # else, do cancel the process
97
+
98
+ get_expression_pool.cancel_process(self)
99
+
100
+ # no need to reply to parent
101
+ end
102
+
103
+ #def reply (workitem)
104
+ #end
105
+
106
+ end
107
+
108
+ end
109
+