openwferu 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/examples/mano_tracker.rb +11 -13
  2. data/lib/openwfe.rb +2 -4
  3. data/lib/openwfe/contextual.rb +8 -2
  4. data/lib/openwfe/engine/engine.rb +118 -2
  5. data/lib/openwfe/expool/expressionpool.rb +148 -53
  6. data/lib/openwfe/expool/expstorage.rb +36 -4
  7. data/lib/openwfe/expool/yamlexpstorage.rb +18 -0
  8. data/lib/openwfe/expressions/environment.rb +1 -1
  9. data/lib/openwfe/expressions/fe_misc.rb +14 -2
  10. data/lib/openwfe/expressions/fe_raw.rb +27 -11
  11. data/lib/openwfe/expressions/fe_subprocess.rb +45 -12
  12. data/lib/openwfe/expressions/fe_utils.rb +1 -1
  13. data/lib/openwfe/expressions/flowexpression.rb +5 -1
  14. data/lib/openwfe/expressions/raw_prog.rb +80 -32
  15. data/lib/openwfe/expressions/raw_xml.rb +10 -0
  16. data/lib/openwfe/flowexpressionid.rb +28 -7
  17. data/lib/openwfe/listeners/listener.rb +106 -0
  18. data/lib/openwfe/listeners/listeners.rb +140 -0
  19. data/lib/openwfe/listeners/socketlisteners.rb +239 -0
  20. data/lib/openwfe/listeners/sqslisteners.rb +145 -0
  21. data/lib/openwfe/participants/{csvparticipant.rb → csvparticipants.rb} +0 -0
  22. data/lib/openwfe/participants/{enoparticipant.rb → enoparticipants.rb} +1 -1
  23. data/lib/openwfe/participants/participantmap.rb +33 -1
  24. data/lib/openwfe/participants/participants.rb +99 -11
  25. data/lib/openwfe/participants/soapparticipants.rb +28 -8
  26. data/lib/openwfe/participants/socketparticipants.rb +172 -0
  27. data/lib/openwfe/participants/sqsparticipants.rb +121 -0
  28. data/lib/openwfe/rest/definitions.rb +1 -1
  29. data/lib/openwfe/{osocket.rb → rest/osocket.rb} +16 -8
  30. data/lib/openwfe/rest/xmlcodec.rb +41 -5
  31. data/lib/openwfe/storage/yamlfilestorage.rb +10 -13
  32. data/lib/openwfe/util/dollar.rb +23 -2
  33. data/lib/openwfe/util/otime.rb +1 -1
  34. data/lib/openwfe/util/safe.rb +149 -0
  35. data/lib/openwfe/util/scheduler.rb +47 -5
  36. data/lib/openwfe/util/sqs.rb +582 -0
  37. data/lib/openwfe/utils.rb +23 -0
  38. data/lib/openwfe/version.rb +1 -1
  39. data/lib/openwfe/workitem.rb +86 -3
  40. data/lib/openwfe/worklist/storeparticipant.rb +44 -4
  41. data/test/csv_test.rb +1 -1
  42. data/test/eno_test.rb +1 -1
  43. data/test/fei_test.rb +2 -15
  44. data/test/flowtestbase.rb +6 -2
  45. data/test/ft_11_ppd.rb +31 -0
  46. data/test/ft_13_eno.rb +1 -1
  47. data/test/ft_14b_subprocess.rb +74 -0
  48. data/test/ft_15_iterator.rb +0 -1
  49. data/test/ft_19_csv.rb +1 -1
  50. data/test/ft_20_cron.rb +1 -1
  51. data/test/ft_21_cron.rb +1 -1
  52. data/test/ft_27_getflowpos.rb +89 -0
  53. data/test/ft_28_fileparticipant.rb +65 -0
  54. data/test/ft_29_httprb.rb +95 -0
  55. data/test/ft_30_socketlistener.rb +197 -0
  56. data/test/ft_4_misc.rb +2 -1
  57. data/test/hash_test.rb +75 -0
  58. data/test/rake_qtest.rb +5 -4
  59. data/test/raw_prog_test.rb +205 -0
  60. data/test/rutest_utils.rb +16 -0
  61. data/test/safely_test.rb +89 -0
  62. data/test/scheduler_test.rb +71 -0
  63. data/test/sqs_test.rb +103 -0
  64. metadata +21 -6
  65. data/test/journal_persistence_test.rb +0 -147
@@ -48,7 +48,7 @@
48
48
  #require 'openwfe/engine/engine'
49
49
  require 'openwfe/engine/file_persisted_engine'
50
50
  require 'openwfe/expressions/raw_prog'
51
- require 'openwfe/participants/storeparticipant'
51
+ require 'openwfe/worklist/storeparticipant'
52
52
 
53
53
 
54
54
  #
@@ -58,21 +58,19 @@ require 'openwfe/participants/storeparticipant'
58
58
  class TrackerDefinition < OpenWFE::ProcessDefinition
59
59
  def make
60
60
 
61
- process_definition :name => "mano_tracker", :revision => "0.2" do
62
- _loop do
63
- participant "${f:creative}"
64
- participant "${f:analyst}"
61
+ _loop do
62
+ participant "${f:creative}"
63
+ participant "${f:analyst}"
65
64
 
66
- _break :if => "${f:done}"
67
- #
68
- # loops until the analyst sets the value of the field
69
- # 'done' to true.
70
- end
65
+ _break :if => "${f:done}"
71
66
  #
72
- # 'loop' and 'break' are ruby keywords, they have to be
73
- # preceded by an underscore '_' to be used in their
74
- # OpenWFEru sense.
67
+ # loops until the analyst sets the value of the field
68
+ # 'done' to true.
75
69
  end
70
+ #
71
+ # 'loop' and 'break' are ruby keywords, they have to be
72
+ # preceded by an underscore '_' to be used in their
73
+ # OpenWFEru sense.
76
74
  end
77
75
  end
78
76
 
@@ -36,8 +36,6 @@
36
36
  # referenced as a library via a require statement.
37
37
  #
38
38
 
39
- require 'openwfe/workitem'
40
- require 'openwfe/engine'
41
- require 'openwfe/rudefinitions'
42
- require 'openwfe/participants'
39
+ require 'openwfe/engine/engine'
40
+ #require 'openwfe/engine/file_persisted_engine'
43
41
 
@@ -73,8 +73,14 @@ module OpenWFE
73
73
  #
74
74
  def init_service (service_name, service_class)
75
75
 
76
- @application_context[service_name.to_s] =
77
- service_class.new(service_name, @application_context)
76
+ s = service_class.new(service_name, @application_context)
77
+
78
+ s.service_name = "#{service_class.name}::#{s.object_id}" \
79
+ unless service_name
80
+
81
+ @application_context[s.service_name.to_s] = s
82
+
83
+ return s
78
84
  end
79
85
 
80
86
  end
@@ -45,6 +45,7 @@ require 'logger'
45
45
  require 'openwfe/workitem'
46
46
  require 'openwfe/rudefinitions'
47
47
  require 'openwfe/service'
48
+ require 'openwfe/util/scheduler'
48
49
  require 'openwfe/util/schedulers'
49
50
  require 'openwfe/expool/expressionpool'
50
51
  require 'openwfe/expool/expstorage'
@@ -61,6 +62,9 @@ module OpenWFE
61
62
  class Engine < Service
62
63
  include OwfeServiceLocator
63
64
 
65
+ #
66
+ # Builds an OpenWFEru engine.
67
+ #
64
68
  def initialize ()
65
69
 
66
70
  super(S_ENGINE, {})
@@ -111,11 +115,17 @@ module OpenWFE
111
115
  launchitem = nil
112
116
 
113
117
  if launch_object.kind_of? OpenWFE::LaunchItem
118
+
114
119
  launchitem = launch_object
120
+
115
121
  elsif launch_object.kind_of? Class
122
+
116
123
  launchitem = LaunchItem.new(launch_object)
124
+
117
125
  elsif launch_object.kind_of? String
126
+
118
127
  launchitem = OpenWFE::LaunchItem.new
128
+
119
129
  if launch_object[0] == '<'
120
130
  launchitem.workflowDefinitionUrl = "field:__definition"
121
131
  launchitem['definition'] = launch_object
@@ -127,14 +137,39 @@ module OpenWFE
127
137
  get_expression_pool.launch(launchitem, async)
128
138
  end
129
139
 
140
+ #
141
+ # Returns the list of applied expressions belonging to a given
142
+ # workflow instance.
143
+ # May be used to determine where a process instance currently is.
144
+ #
145
+ def get_flow_position (workflow_instance_id)
146
+
147
+ get_expression_pool.get_flow_position(workflow_instance_id)
148
+ end
149
+
130
150
  #
131
151
  # This method is used to feed a workitem back to the engine (after
132
152
  # it got sent to a worklist or wherever by a participant).
133
153
  # Participant implementations themselves do call this method usually.
134
154
  #
155
+ # This method also accepts LaunchItem instances.
156
+ #
135
157
  def reply (workitem)
136
158
 
137
- get_expression_pool.reply(workitem.flow_expression_id, workitem)
159
+ if workitem.kind_of? InFlowWorkItem
160
+
161
+ get_expression_pool.reply(workitem.flow_expression_id, workitem)
162
+
163
+ elsif workitem.kind_of? LaunchItem
164
+
165
+ get_expression_pool.launch(workitem, false)
166
+
167
+ else
168
+
169
+ raise \
170
+ "engine.reply() " +
171
+ "cannot handle instances of #{workitem.class}"
172
+ end
138
173
  end
139
174
 
140
175
  #
@@ -161,6 +196,83 @@ module OpenWFE
161
196
  get_participant_map.lookup_participant(participant_name)
162
197
  end
163
198
 
199
+ #
200
+ # Removes the first participant matching the given name from the
201
+ # participant map kept by the engine.
202
+ #
203
+ def unregister_participant (participant_name)
204
+
205
+ get_participant_map.unregister_participant(participant_name)
206
+ end
207
+
208
+ #
209
+ # Adds a workitem listener to this engine.
210
+ #
211
+ # The 'freq' parameters if present might indicate how frequently
212
+ # the resource should be polled for incoming workitems.
213
+ #
214
+ # engine.add_workitem_listener(listener, "3m10s")
215
+ # # every 3 minutes and 10 seconds
216
+ #
217
+ # engine.add_workitem_listener(listener, "0 22 * * 1-5")
218
+ # # every weekday at 10pm
219
+ #
220
+ # TODO : block handling...
221
+ #
222
+ def add_workitem_listener (listener, freq=nil)
223
+
224
+ name = nil
225
+
226
+ if listener.kind_of? Class
227
+
228
+ listener = init_service(nil, listener)
229
+
230
+ name = listener.service_name
231
+ else
232
+
233
+ name = listener.name if listener.respond_to? :name
234
+ name = "#{listener.class}::#{listener.object_id}" unless name
235
+
236
+ @application_context[name] = listener
237
+ end
238
+
239
+ result = nil
240
+
241
+ if freq
242
+
243
+ freq = freq.to_s.strip
244
+
245
+ result = if Scheduler.is_cron_string(freq)
246
+
247
+ get_scheduler.schedule(freq, nil, listener, nil)
248
+ else
249
+
250
+ get_scheduler.schedule_every(freq, listener, nil)
251
+ end
252
+ end
253
+
254
+ linfo { "add_workitem_listener() added '#{name}'" }
255
+
256
+ result
257
+ end
258
+
259
+ #
260
+ # Makes the current thread join the engine's scheduler thread
261
+ #
262
+ # You can thus make an engine standalone with something like :
263
+ #
264
+ # require 'openwfe/engine/engine'
265
+ #
266
+ # the_engine = OpenWFE::Engine.new
267
+ # the_engine.join
268
+ #
269
+ # And you'll have to hit CTRL-C to make it stop.
270
+ #
271
+ def join
272
+
273
+ get_scheduler.join
274
+ end
275
+
164
276
  #
165
277
  # Stopping the engine will stop all the services in the
166
278
  # application context.
@@ -190,23 +302,27 @@ module OpenWFE
190
302
  #
191
303
 
192
304
  def build_expression_map ()
305
+
193
306
  init_service(S_EXPRESSION_MAP, ExpressionMap)
194
307
  end
195
308
 
196
309
  def build_expression_pool ()
310
+
197
311
  init_service(S_EXPRESSION_POOL, ExpressionPool)
198
312
  end
199
313
 
200
314
  def build_expression_storage ()
315
+
201
316
  init_service(S_EXPRESSION_STORAGE, InMemoryExpressionStorage)
202
317
  end
203
318
 
204
319
  def build_participant_map ()
320
+
205
321
  init_service(S_PARTICIPANT_MAP, ParticipantMap)
206
322
  end
207
323
 
208
324
  def build_scheduler ()
209
- #ldebug { "build_scheduler()" }
325
+
210
326
  init_service(S_SCHEDULER, SchedulerService)
211
327
  end
212
328
 
@@ -41,7 +41,7 @@
41
41
 
42
42
  require 'uri'
43
43
  require 'monitor'
44
- require 'net/http'
44
+ require 'open-uri'
45
45
  require 'rexml/document'
46
46
 
47
47
  require 'openwfe/utils'
@@ -50,6 +50,7 @@ require 'openwfe/logging'
50
50
  require 'openwfe/rudefinitions'
51
51
  require 'openwfe/flowexpressionid'
52
52
  require 'openwfe/util/lru'
53
+ require 'openwfe/util/safe'
53
54
  require 'openwfe/util/observable'
54
55
  require 'openwfe/expressions/environment'
55
56
  require 'openwfe/expressions/raw_xml'
@@ -128,6 +129,11 @@ module OpenWFE
128
129
  OwfeServiceLocator,
129
130
  Observable
130
131
 
132
+ SAFETY_LEVEL = 2
133
+ #
134
+ # code loaded from a remote URI will get evaluated with
135
+ # that security level
136
+
131
137
  @@last_given_instance_id = -1
132
138
  #
133
139
  # storing at class level the last workflow instance id given
@@ -176,7 +182,16 @@ module OpenWFE
176
182
 
177
183
  onotify :launch, launchitem.workflow_definition_url
178
184
 
179
- raw_expression = buildRawExpression(launchitem)
185
+ procdef = fetch_definition(launchitem)
186
+
187
+ raw_expression = build_raw_expression(
188
+ launchitem.workflow_definition_url, procdef)
189
+
190
+ raw_expression.new_environment()
191
+ #
192
+ # as this expression is the root of a new process instance,
193
+ # it has to have an environment for all the variables of
194
+ # the process instance
180
195
 
181
196
  wi = build_workitem(launchitem)
182
197
 
@@ -185,13 +200,13 @@ module OpenWFE
185
200
  if async
186
201
 
187
202
  t = OpenWFE::call_in_thread "launch()", self do
188
- raw_expression.apply(wi)
203
+ apply(raw_expression, wi)
189
204
  end
190
205
 
191
206
  return fei, t
192
207
  end
193
208
 
194
- raw_expression.apply(wi)
209
+ apply(raw_expression, wi)
195
210
 
196
211
  return fei
197
212
  end
@@ -207,8 +222,15 @@ module OpenWFE
207
222
  rawexp = nil
208
223
 
209
224
  if template.kind_of? FlowExpressionId
225
+
210
226
  rawexp, fei = fetch(template)
227
+
228
+ elsif template.kind_of? URI
229
+
230
+ rawexp = load_rawexp_from_uri(template)
231
+
211
232
  else # template is of kind RawExpression
233
+
212
234
  rawexp = template
213
235
  end
214
236
 
@@ -257,7 +279,7 @@ module OpenWFE
257
279
  #end
258
280
 
259
281
  env = rawexp.new_environment()
260
-
282
+ #
261
283
  params.each { |k, v| env[k] = v } if params
262
284
  #
263
285
  # the new scope gets its own environment
@@ -268,7 +290,7 @@ module OpenWFE
268
290
 
269
291
  fei = rawexp.fei
270
292
 
271
- rawexp.apply(workitem)
293
+ apply(rawexp, workitem)
272
294
 
273
295
  return fei
274
296
  end
@@ -295,7 +317,7 @@ module OpenWFE
295
317
  #
296
318
  def apply (exp, workitem)
297
319
 
298
- exp, fei = fetch(exp)
320
+ exp, fei = fetch(exp) if exp.kind_of? FlowExpressionId
299
321
 
300
322
  #ldebug { "apply() '#{fei}' (#{fei.class})" }
301
323
 
@@ -306,10 +328,14 @@ module OpenWFE
306
328
 
307
329
  #ldebug { "apply() #{fei.to_debug_s}" }
308
330
 
309
- onotify :apply, fei, workitem
331
+ #exp.apply_time = OpenWFE::now()
332
+ #
333
+ # this is done in RawExpression
310
334
 
311
335
  workitem.flow_expression_id = exp.fei
312
336
 
337
+ onotify :apply, exp.fei, workitem
338
+
313
339
  exp.apply(workitem)
314
340
  end
315
341
 
@@ -510,15 +536,12 @@ module OpenWFE
510
536
  #
511
537
  def remove (exp)
512
538
 
513
- #exp, fei = fetch(exp)
514
-
515
- if exp.kind_of? FlowExpressionId
516
- exp, _fei = fetch(exp)
517
- end
539
+ exp, _fei = fetch(exp) \
540
+ if exp.kind_of? FlowExpressionId
518
541
 
519
542
  return if not exp
520
543
 
521
- ldebug { "remove() fe #{exp.fei.to_debug_s}" }
544
+ ldebug { "remove() fe #{exp.fei.to_debug_s}" }
522
545
 
523
546
  onotify :remove, exp.fei
524
547
 
@@ -526,13 +549,8 @@ module OpenWFE
526
549
 
527
550
  @monitors.delete(exp.fei)
528
551
 
529
- #get_expression_storage().delete(fei)
530
-
531
- if exp.owns_its_environment?
532
-
533
- remove_environment(exp.environment_id)
534
- end
535
-
552
+ remove_environment(exp.environment_id) \
553
+ if exp.owns_its_environment?
536
554
  end
537
555
  end
538
556
 
@@ -586,12 +604,59 @@ module OpenWFE
586
604
  end
587
605
  end
588
606
 
607
+ #
608
+ # Returns the list of applied expressions belonging to a given
609
+ # workflow instance.
610
+ #
611
+ def get_flow_position (wfid)
612
+
613
+ raise "please provide a non-nil workflow instance id" \
614
+ unless wfid
615
+
616
+ result = []
617
+
618
+ get_expression_storage.real_each do |fei, fexp|
619
+
620
+ next if fexp.kind_of? Environment
621
+ next if fexp.kind_of? RawExpression
622
+ next unless fexp.apply_time
623
+
624
+ pi = fei.parent_wfid
625
+
626
+ next if pi != wfid
627
+
628
+ result << fexp
629
+ end
630
+
631
+ ldebug do
632
+ "get_flow_position() " +
633
+ "found #{result.size} exps for flow #{wfid}"
634
+ end
635
+
636
+ return result
637
+ end
638
+
589
639
  protected
590
640
 
591
- def evaluate_definition (raw_definition, workitem)
592
- expression = raw_definition.instantiate(workitem)
641
+ #def evaluate_definition (raw_definition, workitem)
642
+ # expression = raw_definition.instantiate(workitem)
643
+ #end
644
+
645
+ #
646
+ # Prepares the RawExpression for a 'remote' process definition
647
+ # (a process definition pointed at via a URI).
648
+ #
649
+ def load_rawexp_from_uri (uri)
650
+
651
+ procdef = determine_representation(uri.read)
652
+
653
+ build_raw_expression(uri.to_s, procdef)
593
654
  end
594
655
 
656
+ #
657
+ # Removes an environment, especially takes care of unbinding
658
+ # any special value it may contain.
659
+ #
595
660
  def remove_environment (environment_id)
596
661
 
597
662
  ldebug { "remove_environment() #{environment_id.to_debug_s}" }
@@ -605,6 +670,10 @@ module OpenWFE
605
670
  onotify :remove, environment_id
606
671
  end
607
672
 
673
+ #
674
+ # Prepares a new instance of InFlowWorkItem from a LaunchItem
675
+ # instance.
676
+ #
608
677
  def build_workitem (launchitem)
609
678
 
610
679
  wi = InFlowWorkItem.new()
@@ -614,6 +683,40 @@ module OpenWFE
614
683
  return wi
615
684
  end
616
685
 
686
+ #
687
+ # Given a string that contains either an XML process
688
+ # definition, either a Ruby process definition
689
+ # will return a 'representation' (what is used to build
690
+ # a RawExpression instance).
691
+ #
692
+ def determine_representation (string_definition)
693
+
694
+ if string_definition[0, 1] == "<"
695
+
696
+ xmlRoot = REXML::Document.new(string_definition).root
697
+ class << xmlRoot
698
+ def raw_expression_class
699
+ XmlRawExpression
700
+ end
701
+ end
702
+ return xmlRoot
703
+ end
704
+
705
+ # else
706
+
707
+ #o = eval(string_definition)
708
+ o = OpenWFE::eval_safely(string_definition, SAFETY_LEVEL)
709
+ #o = OpenWFE::load_eval_safely(string_definition, SAFETY_LEVEL)
710
+ #o = OpenWFE::eval_r_safely(string_definition, SAFETY_LEVEL)
711
+
712
+ return o.do_make if o.kind_of? Class
713
+
714
+ return o
715
+ end
716
+
717
+ #
718
+ # Extracts the process definition that a launchitem points at.
719
+ #
617
720
  def fetch_definition (launchitem)
618
721
 
619
722
  wfdUrl = launchitem.workflow_definition_url
@@ -627,44 +730,36 @@ module OpenWFE
627
730
  wfdField = wfdUrl[6..-1]
628
731
  sDefinition = launchitem.attributes[wfdField]
629
732
  else
630
- sDefinition = NET::HTTP.get(URI.parse(wfdUrl))
733
+ sDefinition = URI.parse(wfdUrl).read
631
734
  end
632
735
 
633
736
  #ldebug { "sDefinition is \n#{sDefinition}" }
634
737
 
635
738
  launchitem.attributes.delete(wfdField) if wfdField
636
739
 
637
- if sDefinition.kind_of? String
638
-
639
- xmlRoot = REXML::Document.new(sDefinition).root
640
- class << xmlRoot
641
- def rawExpressionClass
642
- XmlRawExpression
643
- end
644
- end
645
- return xmlRoot
646
- end
647
-
648
- if sDefinition.kind_of? ProgExpRepresentation
740
+ return determine_representation(sDefinition) \
741
+ if sDefinition.kind_of? String
649
742
 
650
- return sDefinition
651
- end
743
+ return sDefinition \
744
+ if sDefinition.kind_of? ProgExpRepresentation
652
745
 
653
- if sDefinition.kind_of? ProcessDefinition
746
+ return sDefinition.make \
747
+ if sDefinition.kind_of? ProcessDefinition
654
748
 
655
- return sDefinition.make()
656
- end
749
+ return sDefinition.do_make \
750
+ if sDefinition.kind_of? Class
657
751
 
658
- if sDefinition.kind_of? Class
659
-
660
- return sDefinition.do_make()
661
- end
752
+ # else...
662
753
 
663
754
  raise \
664
755
  "Cannot deduce process definition " +
665
756
  "out of instance of class #{sDefinition.class}"
666
757
  end
667
758
 
759
+ #
760
+ # Builds a FlowExpressionId instance for process being
761
+ # launched.
762
+ #
668
763
  def new_fei (flow_url, flow_name, flow_revision, exp_name)
669
764
 
670
765
  fei = FlowExpressionId.new
@@ -681,6 +776,9 @@ module OpenWFE
681
776
  return fei
682
777
  end
683
778
 
779
+ #
780
+ # Returns a new unique workflow instance id
781
+ #
684
782
  def new_workflow_instance_id ()
685
783
 
686
784
  synchronize do
@@ -700,21 +798,18 @@ module OpenWFE
700
798
  # Builds the RawExpression instance at the root of the flow
701
799
  # being launched.
702
800
  #
703
- def buildRawExpression (launchitem)
704
-
705
- procdef = fetch_definition(launchitem)
801
+ def build_raw_expression (url, procdef)
706
802
 
707
- flow_url = launchitem.workflow_definition_url
708
803
  flow_name = procdef.attributes['name']
709
804
  flow_revision = procdef.attributes['revision']
710
805
  exp_name = procdef.name
711
806
 
712
- fei = new_fei(flow_url, flow_name, flow_revision, exp_name)
807
+ fei = new_fei(url, flow_name, flow_revision, exp_name)
713
808
 
714
- #puts procdef.rawExpressionClass
715
- #puts procdef.rawExpressionClass.public_methods
809
+ #puts procdef.raw_expression_class
810
+ #puts procdef.raw_expression_class.public_methods
716
811
 
717
- return procdef.rawExpressionClass\
812
+ return procdef.raw_expression_class\
718
813
  .new(fei, nil, nil, @application_context, procdef)
719
814
  end
720
815