openwferu 0.9.2 → 0.9.3

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 (63) hide show
  1. data/examples/mano_tracker.rb +165 -0
  2. data/examples/scheduler_cron_usage.rb +46 -0
  3. data/examples/scheduler_usage.rb +54 -0
  4. data/lib/openwfe/contextual.rb +7 -1
  5. data/lib/openwfe/engine/engine.rb +58 -15
  6. data/lib/openwfe/expool/expressionpool.rb +116 -14
  7. data/lib/openwfe/expool/expstorage.rb +12 -12
  8. data/lib/openwfe/expool/journalexpstorage.rb +1 -1
  9. data/lib/openwfe/expool/yamlexpstorage.rb +58 -22
  10. data/lib/openwfe/expressions/environment.rb +32 -2
  11. data/lib/openwfe/expressions/expressionmap.rb +17 -0
  12. data/lib/openwfe/expressions/fe_condition.rb +122 -0
  13. data/lib/openwfe/expressions/fe_cursor.rb +14 -5
  14. data/lib/openwfe/expressions/fe_participant.rb +55 -4
  15. data/lib/openwfe/expressions/fe_raw.rb +43 -12
  16. data/lib/openwfe/expressions/fe_subprocess.rb +10 -0
  17. data/lib/openwfe/expressions/fe_time.rb +117 -22
  18. data/lib/openwfe/expressions/fe_value.rb +27 -8
  19. data/lib/openwfe/expressions/flowexpression.rb +13 -6
  20. data/lib/openwfe/expressions/raw_prog.rb +13 -11
  21. data/lib/openwfe/expressions/timeout.rb +94 -0
  22. data/lib/openwfe/flowexpressionid.rb +17 -19
  23. data/lib/openwfe/logging.rb +35 -16
  24. data/lib/openwfe/participants/atomparticipants.rb +31 -7
  25. data/lib/openwfe/participants/enoparticipant.rb +43 -3
  26. data/lib/openwfe/participants/participant.rb +21 -1
  27. data/lib/openwfe/participants/participantmap.rb +4 -2
  28. data/lib/openwfe/participants/participants.rb +12 -17
  29. data/lib/openwfe/participants/soapparticipants.rb +15 -3
  30. data/lib/openwfe/rudefinitions.rb +3 -0
  31. data/lib/openwfe/service.rb +8 -0
  32. data/lib/openwfe/storage/yamlfilestorage.rb +85 -47
  33. data/lib/openwfe/{otime.rb → util/otime.rb} +0 -0
  34. data/lib/openwfe/util/scheduler.rb +415 -231
  35. data/lib/openwfe/util/schedulers.rb +11 -3
  36. data/lib/openwfe/util/stoppable.rb +69 -0
  37. data/lib/openwfe/utils.rb +14 -25
  38. data/lib/openwfe/workitem.rb +12 -6
  39. data/lib/openwfe/worklist/storeparticipant.rb +145 -0
  40. data/test/{atomtest.rb → atom_test.rb} +0 -0
  41. data/test/{crontest.rb → cron_test.rb} +7 -6
  42. data/test/cronline_test.rb +51 -0
  43. data/test/{dollartest.rb → dollar_test.rb} +0 -0
  44. data/test/{feitest.rb → fei_test.rb} +0 -0
  45. data/test/file_persistence_test.rb +15 -9
  46. data/test/flowtestbase.rb +11 -5
  47. data/test/ft_0.rb +8 -0
  48. data/test/ft_10_loop.rb +72 -10
  49. data/test/ft_11_ppd.rb +49 -0
  50. data/test/ft_17_condition.rb +83 -0
  51. data/test/ft_18_pname.rb +59 -0
  52. data/test/hparticipant_test.rb +96 -0
  53. data/test/{misctest.rb → misc_test.rb} +1 -1
  54. data/test/rake_qtest.rb +10 -4
  55. data/test/rake_test.rb +12 -1
  56. data/test/raw_prog_test.rb +1 -1
  57. data/test/restart_cron_test.rb +78 -0
  58. data/test/restart_test.rb +79 -0
  59. data/test/scheduler_test.rb +92 -0
  60. data/test/{timetest.rb → time_test.rb} +3 -38
  61. data/test/timeout_test.rb +73 -0
  62. metadata +26 -11
  63. data/lib/openwfe/worklist/worklists.rb +0 -175
@@ -71,6 +71,7 @@ module OpenWFE
71
71
 
72
72
  #
73
73
  # call the add method for each registered storage
74
+ #
74
75
  def []= (fei, flowExpression)
75
76
  @journal[fei] = flowExpression if @journal
76
77
  @cache[fei] = flowExpression if @cache
@@ -79,10 +80,11 @@ module OpenWFE
79
80
 
80
81
  #
81
82
  # remove the expressionid from each registered storage
82
- def remove (fei, workitem)
83
- @journal.remove(fei, workitem) if @journal
84
- @cache.remove(fei, workitem) if @cache
85
- @persistence.remove(fei,workitem)
83
+ #
84
+ def delete (fei)
85
+ @journal.delete(fei) if @journal
86
+ @cache.delete(fei) if @cache
87
+ @persistence.delete(fei)
86
88
  end
87
89
 
88
90
  #
@@ -119,7 +121,8 @@ module OpenWFE
119
121
 
120
122
  #
121
123
  # interface method to remove an entry for the given expression_id
122
- def remove (fei, workitem)
124
+ #
125
+ def delete (fei)
123
126
  @cache.delete(fei)
124
127
  end
125
128
 
@@ -151,16 +154,13 @@ module OpenWFE
151
154
  include ServiceMixin
152
155
 
153
156
  def initialize (service_name, application_context)
154
- @service_name = service_name
155
- @application_context = application_context
157
+ service_init(service_name, application_context)
156
158
  end
157
159
 
158
- def remove (fei, workitem)
159
- delete(fei)
160
- end
160
+ alias :purge :clear
161
161
 
162
- def purge
163
- self.clear
162
+ def each_of_kind (kind)
163
+ # TODO : implement with a filter
164
164
  end
165
165
 
166
166
  def to_s
@@ -258,7 +258,7 @@ module OpenWFE
258
258
 
259
259
  #
260
260
  # interface method: remove the expressionid and persist the related workitem
261
- def remove (fei, workitem=nil)
261
+ def remove (fei)
262
262
  write_to_journal(JournalEntry.new(:del, fei, nil))
263
263
  end
264
264
 
@@ -40,8 +40,10 @@
40
40
  # John Mettraux at openwfe.org
41
41
  #
42
42
 
43
- require 'find'
43
+ #require 'find'
44
44
 
45
+ require 'openwfe/utils'
46
+ require 'openwfe/rudefinitions'
45
47
  require 'openwfe/storage/yamlfilestorage'
46
48
 
47
49
  require 'openwfe/expressions/flowexpression'
@@ -84,6 +86,7 @@ module OpenWFE
84
86
  # yaml expression storage
85
87
  #
86
88
  class YamlFileExpressionStorage < YamlFileStorage
89
+ include OwfeServiceLocator
87
90
 
88
91
  def initialize (service_name, application_context)
89
92
  path = if (@application_context)
@@ -93,35 +96,68 @@ module OpenWFE
93
96
  end
94
97
  super(service_name, application_context, path + "/expool")
95
98
  end
96
-
97
- def compute_file_path (fei)
98
-
99
- return @basepath + "/engine_env.yaml" \
100
- if fei.workflow_instance_id == "0"
101
-
102
- wfid = fei.parent_workflow_instance_id
103
-
104
- @basepath + "/" +
105
- wfid[-1, 1] + "/" +
106
- wfid[-2, 1] + "/" +
107
- wfid + "/" +
108
- fei.workflow_instance_id + "__" +
109
- fei.expression_id + "_" +
110
- fei.expression_name + ".yaml"
111
- end
99
+
100
+ #
101
+ # Iterates on each expression that is of the given kind.
102
+ # Used for example by the expression pool when rescheduling.
103
+ #
104
+ def each_of_kind (kind, &block)
105
+
106
+ return unless block
107
+
108
+ exp_names = get_expression_map.get_expression_names(kind)
109
+ #require 'pp'
110
+ #pp exp_names
111
+
112
+ each_object_path do |path|
113
+
114
+ #ldebug { "each_of_kind() path is #{path}" }
115
+
116
+ next unless matches(path, exp_names)
117
+
118
+ expression = load_object(path)
119
+ expression.application_context = @application_context
120
+
121
+ block.call expression
122
+ end
123
+ end
112
124
 
113
125
  def to_s
114
126
  s = "\n\n==== #{self.class} ===="
115
127
  s << "\n"
116
- Find.find(@basepath) do |path|
117
- if not File.stat(path).directory?
118
- s << path
119
- s << "\n"
120
- end
128
+ each_expression_path do |path|
129
+ s << path
130
+ s << "\n"
121
131
  end
122
132
  s << "==== . ====\n"
123
133
  return s
124
134
  end
135
+
136
+ protected
137
+
138
+ def compute_file_path (fei)
139
+
140
+ return @basepath + "/engine_environment.yaml" \
141
+ if fei.workflow_instance_id == "0"
142
+
143
+ wfid = fei.parent_workflow_instance_id
144
+
145
+ @basepath + "/" +
146
+ wfid[-1, 1] + "/" +
147
+ wfid[-2, 1] + "/" +
148
+ wfid + "/" +
149
+ fei.workflow_instance_id + "__" +
150
+ fei.expression_id + "_" +
151
+ fei.expression_name + ".yaml"
152
+ end
153
+
154
+ def matches (path, exp_names)
155
+ exp_names.each do |exp_name|
156
+ return true \
157
+ if OpenWFE::ends_with(path, "_#{exp_name}.yaml")
158
+ end
159
+ return false
160
+ end
125
161
 
126
162
  end
127
163
  end
@@ -40,6 +40,7 @@
40
40
  #
41
41
 
42
42
  require 'openwfe/utils'
43
+ require 'openwfe/util/scheduler'
43
44
  require 'openwfe/expressions/flowexpression'
44
45
 
45
46
 
@@ -50,6 +51,7 @@ module OpenWFE
50
51
  # It's an expression as it's storable in the expression pool.
51
52
  #
52
53
  class Environment < FlowExpression
54
+ include Schedulable
53
55
 
54
56
  attr_accessor \
55
57
  :variables
@@ -122,8 +124,11 @@ module OpenWFE
122
124
  def unbind ()
123
125
 
124
126
  @variables.each do |key, value|
125
- get_expression_pool().remove(value) \
126
- if value.kind_of? OpenWFE::FlowExpressionId
127
+ if value.kind_of? FlowExpressionId
128
+ get_expression_pool().remove(value)
129
+ elsif value.kind_of? FlowExpression
130
+ value.cancel
131
+ end
127
132
  end
128
133
  end
129
134
 
@@ -134,6 +139,31 @@ module OpenWFE
134
139
  return @fei == get_expression_pool().engine_environment_id
135
140
  end
136
141
 
142
+ #
143
+ # Should never get used, only the reschedule() method is relevant
144
+ # for the Schedulable aspect of an environment expression.
145
+ #
146
+ def trigger (params)
147
+ raise "an environment should never get directly triggered"
148
+ end
149
+
150
+ #
151
+ # Will reschedule any 'Schedulable' variable found in this environment
152
+ # this method especially targets cron expressions that are stored
153
+ # as variables and need to be rescheduled upon engine restart.
154
+ #
155
+ def reschedule (scheduler)
156
+
157
+ @variables.each do |key, value|
158
+ ldebug { "reschedule() - item of class #{value.class}" }
159
+ next unless value.kind_of? Schedulable
160
+ value.application_context = @application_context
161
+ value.reschedule(scheduler)
162
+ end
163
+
164
+ store_itself()
165
+ end
166
+
137
167
  protected
138
168
 
139
169
  def get_root_environment ()
@@ -40,6 +40,7 @@
40
40
  #
41
41
 
42
42
  require 'openwfe/service'
43
+ require 'openwfe/expressions/environment'
43
44
  require 'openwfe/expressions/fe_define'
44
45
  require 'openwfe/expressions/fe_misc'
45
46
  require 'openwfe/expressions/fe_value'
@@ -113,6 +114,10 @@ module OpenWFE
113
114
  @map["f"] = FqvExpression
114
115
  @map["q"] = FqvExpression
115
116
  @map["v"] = FqvExpression
117
+
118
+ @map["environment"] = Environment
119
+ #
120
+ # only used by get_expression_names()
116
121
  end
117
122
 
118
123
  #
@@ -146,6 +151,18 @@ module OpenWFE
146
151
  return @map.keys
147
152
  end
148
153
 
154
+ #
155
+ # Returns an array of expression names whose class are assignable
156
+ # from the given expression_class.
157
+ #
158
+ def get_expression_names (expression_class)
159
+ names = []
160
+ @map.each do |name, exp_class|
161
+ names << name \
162
+ if exp_class.ancestors.include? expression_class
163
+ end
164
+ return names
165
+ end
149
166
  end
150
167
 
151
168
  end
@@ -0,0 +1,122 @@
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/workitem'
43
+ #require 'openwfe/flowexpressionid'
44
+
45
+
46
+ module OpenWFE
47
+
48
+ #
49
+ # A ConditionMixin is a mixin for flow expressions like 'if' and 'break' for
50
+ # example.
51
+ # It allows for shorter notations like
52
+ #
53
+ # <if test="${f:approved} == true"/>
54
+ #
55
+ # or
56
+ #
57
+ # _loop do
58
+ # participant :graphical_designer
59
+ # participant :business_analyst
60
+ # _break :if => "${f:approved}"
61
+ # end
62
+ #
63
+ module ConditionMixin
64
+
65
+ def eval_condition (attname, workitem)
66
+
67
+ conditional = lookup_attribute(attname, workitem)
68
+ rconditional = lookup_attribute("r"+attname.to_s, workitem)
69
+
70
+ if rconditional and not conditional
71
+ return instance_eval(rconditional)
72
+ end
73
+
74
+ return nil unless conditional
75
+
76
+ #ldebug { "eval_condition() 0 for '#{conditional}'" }
77
+
78
+ conditional = from_xml(conditional)
79
+
80
+ #ldebug { "eval_condition() 1 for '#{conditional}'" }
81
+
82
+ conditional = do_quote(conditional)
83
+
84
+ ldebug { "eval_condition() 2 for '#{conditional}'" }
85
+
86
+ return true if conditional == '"true"'
87
+ return false if conditional == '"false"'
88
+
89
+ return instance_eval(conditional)
90
+ end
91
+
92
+ private
93
+
94
+ def from_xml (string)
95
+
96
+ s = string
97
+ s.gsub!("&gt;", ">")
98
+ s.gsub!("&lt;", "<")
99
+ s
100
+ end
101
+
102
+ def do_quote (string)
103
+
104
+ i = string.index("==")
105
+ i = string.index("!=") unless i
106
+ i = string.index("<") unless i
107
+ i = string.index(">") unless i
108
+
109
+ return '"' + string + '"' unless i
110
+
111
+ '"' +
112
+ string[0..i-1].strip +
113
+ '" ' +
114
+ string[i..i+2] +
115
+ ' "' +
116
+ string[i+2..-1].strip +
117
+ '"'
118
+ end
119
+ end
120
+
121
+ end
122
+
@@ -40,6 +40,7 @@
40
40
  #
41
41
 
42
42
  require 'openwfe/expressions/flowexpression'
43
+ require 'openwfe/expressions/fe_condition'
43
44
 
44
45
 
45
46
  #
@@ -216,17 +217,25 @@ module OpenWFE
216
217
  # 'skip', 'continue', and the like
217
218
  #
218
219
  class CursorCommandExpression < FlowExpression
220
+ include ConditionMixin
219
221
 
220
222
  def apply (workitem)
221
223
 
222
- command = @fei.expression_name
224
+ conditional = eval_condition(:if, workitem)
225
+ #
226
+ # for example : <break if="${approved} == true"/>
227
+
228
+ if conditional == nil or conditional
223
229
 
224
- step = lookup_attribute(A_STEP, workitem, "1")
225
- step = Integer(step)
230
+ command = @fei.expression_name
226
231
 
227
- command = "#{command} #{step}" if step != 1
232
+ step = lookup_attribute(A_STEP, workitem, "1")
233
+ step = Integer(step)
228
234
 
229
- workitem.attributes[F_COMMAND] = command
235
+ command = "#{command} #{step}" if step != 1
236
+
237
+ workitem.attributes[F_COMMAND] = command
238
+ end
230
239
 
231
240
  reply_to_parent(workitem)
232
241
  end
@@ -39,7 +39,9 @@
39
39
  # John Mettraux at openwfe.org
40
40
  #
41
41
 
42
+ require 'openwfe/utils'
42
43
  require 'openwfe/rudefinitions'
44
+ require 'openwfe/expressions/timeout'
43
45
  require 'openwfe/expressions/fe_utils'
44
46
 
45
47
 
@@ -56,6 +58,7 @@ module OpenWFE
56
58
  # tied to the engine.
57
59
  #
58
60
  class ParticipantExpression < FlowExpression
61
+ include TimeoutMixin
59
62
 
60
63
  attr_accessor \
61
64
  :participant_name,
@@ -66,22 +69,70 @@ module OpenWFE
66
69
 
67
70
  def apply (workitem)
68
71
 
69
- @applied_workitem = workitem
70
- #puts "apply() \n#{@applied_workitem}"
71
- #ldebug { "apply() \n#{@applied_workitem}" }
72
+ @applied_workitem = workitem.dup
72
73
 
73
74
  @participant_name = OpenWFE::lookup_ref(self, workitem)
74
75
 
75
76
  @participant_name = OpenWFE::fetch_text_content(self, workitem) \
76
77
  unless @participant_name
77
78
 
79
+ determine_timeout()
80
+
78
81
  store_itself()
79
82
 
80
- get_participant_map.dispatch(participant_name, workitem)
83
+ get_participant_map.dispatch(@participant_name, workitem)
81
84
  end
82
85
 
83
86
  #def reply (workitem)
84
87
  #end
88
+
89
+ #
90
+ # The cancel() method of a ParticipantExpression is particular : it
91
+ # will emit a CancelItem instance towards the participant itself
92
+ # to notify it of the cancellation.
93
+ #
94
+ def cancel
95
+
96
+ wi = super()
97
+
98
+ if @scheduler_job_id
99
+ get_scheduler.unschedule(@scheduler_job_id)
100
+ end
101
+
102
+ return wi unless @applied_workitem
103
+
104
+ #
105
+ # have to cancel the workitem on the participant side
106
+
107
+ cancelitem = OpenWFE::CancelItem.new(@applied_workitem)
108
+ get_participant_map.dispatch(@participant_name, cancelitem)
109
+
110
+ return nil
111
+ end
112
+
113
+ #
114
+ # Upon timeout, the ParticipantExpression will cancel itself and
115
+ # the flow will resume.
116
+ #
117
+ def trigger (scheduler)
118
+
119
+ ldebug { "trigger() timeout requested for #{@fei.to_debug_s}" }
120
+
121
+ begin
122
+
123
+ @scheduler_job_id = nil
124
+ #
125
+ # so that cancel won't unschedule without need
126
+
127
+ cancel()
128
+ reply_to_parent(@applied_workitem)
129
+ rescue
130
+ lerror do
131
+ "trigger() problem while timing out\n"+
132
+ OpenWFE::exception_to_s($!)
133
+ end
134
+ end
135
+ end
85
136
  end
86
137
 
87
138
  end