Class: OpenWFE::FlowExpression

Inherits:
ObjectWithMeta show all
Includes:
Contextual, Logging, OwfeServiceLocator
Defined in:
lib/openwfe/storage/yamlcustom.rb,
lib/openwfe/expressions/flowexpression.rb

Overview

FlowExpression

The base class for all OpenWFE flow expression classes. It gathers all the methods for attributes and variable lookup.

Instance Attribute Summary collapse

Attributes included from Contextual

#application_context

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Contextual

#get_work_directory, #init_service, #lookup

Methods included from Logging

#ldebug, #ldebug_callstack, #lerror, #lfatal, #linfo, #llog, #lunknown, #lwarn

Methods included from OwfeServiceLocator

#get_engine, #get_error_journal, #get_expool, #get_expression_map, #get_expression_pool, #get_expression_storage, #get_expression_storages, #get_journal, #get_participant_map, #get_scheduler, #get_wfid_generator

Methods inherited from ObjectWithMeta

#class_def, meta_def, meta_eval, metaclass

Constructor Details

#initializeFlowExpression

The classical no-params constructors.



125
126
127
128
129
130
# File 'lib/openwfe/expressions/flowexpression.rb', line 125

def initialize

    super
        #
        # very necessary as this class includes the MonitorMixin
end

Instance Attribute Details

#apply_timeObject

When the FlowExpression instance is applied, this time stamp is set to the current date.



112
113
114
# File 'lib/openwfe/expressions/flowexpression.rb', line 112

def apply_time
  @apply_time
end

#attributesObject

The attributes of the expression, as found in the process definition.

<participant ref='toto' timeout='1d10h' />

The attributes will be ref => “toto” and timeout => “1d10h” (yes, ‘attributes’ contains a hash.



92
93
94
# File 'lib/openwfe/expressions/flowexpression.rb', line 92

def attributes
  @attributes
end

#childrenObject

An array of ‘flow expression id’ instances. These are the ids of the expressions children to this one.

<sequence>
    <participant ref="toto" />
    <participant ref="bert" />
</sequence>

The expression instance for ‘sequence’ will hold the feis of toto and bert in its children array.



106
107
108
# File 'lib/openwfe/expressions/flowexpression.rb', line 106

def children
  @children
end

#environment_idObject

The ‘flow expression id’ of the environment this expression works with.



82
83
84
# File 'lib/openwfe/expressions/flowexpression.rb', line 82

def environment_id
  @environment_id
end

#feiObject

The ‘flow expression id’ the unique identifier within a workflow instance for this expression instance.



69
70
71
# File 'lib/openwfe/expressions/flowexpression.rb', line 69

def fei
  @fei
end

#parent_idObject

The ‘flow expression id’ of the parent expression. Will yield ‘nil’ if this expression is the root of its process instance.



76
77
78
# File 'lib/openwfe/expressions/flowexpression.rb', line 76

def parent_id
  @parent_id
end

#raw_representationObject

Used by raw expressions to store the not yet interpreted branches of a process, used by other expressions to store their representation at ‘eval time’.



119
120
121
# File 'lib/openwfe/expressions/flowexpression.rb', line 119

def raw_representation
  @raw_representation
end

Class Method Details

.is_definitionObject



757
758
759
760
761
# File 'lib/openwfe/expressions/flowexpression.rb', line 757

def self.is_definition
    meta_def :is_definition? do
        true
    end
end

.is_definition?Boolean

Returns:

  • (Boolean)


754
755
756
# File 'lib/openwfe/expressions/flowexpression.rb', line 754

def self.is_definition?
    false
end

.names(*exp_names) ⇒ Object

a nice ‘names’ tag/method for registering the names of the Expression classes.



744
745
746
747
748
749
750
751
752
# File 'lib/openwfe/expressions/flowexpression.rb', line 744

def self.names (*exp_names)

    exp_names = exp_names.collect do |n|
        n.to_s
    end
    meta_def :expression_names do
        exp_names
    end
end

.new_exp(fei, parent_id, env_id, app_context, attributes) ⇒ Object

Builds a new instance of an expression



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/openwfe/expressions/flowexpression.rb', line 135

def self.new_exp (fei, parent_id, env_id, app_context, attributes)

    e = self.new

    e.fei = fei
    e.parent_id = parent_id
    e.environment_id = env_id
    e.application_context = app_context
    e.attributes = attributes

    e.children = []
    e.apply_time = nil

    e
end

Instance Method Details

#apply(workitem) ⇒ Object

this default implementation immediately replies to the parent expression



159
160
161
162
# File 'lib/openwfe/expressions/flowexpression.rb', line 159

def apply (workitem)

    get_parent.reply(workitem) if @parent_id
end

#cancelObject

a default implementation for cancel : cancels all the children Attempts to return an InFlowWorkItem



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/openwfe/expressions/flowexpression.rb', line 189

def cancel

    return nil if not @children

    inflowitem = nil

    @children.each do |child|

        next if child.kind_of?(String)

        i = get_expression_pool.cancel child
        inflowitem ||= i
    end

    inflowitem
end

#clean_childrenObject

Takes care of removing all the children of this expression, if any.



572
573
574
575
576
577
578
579
580
# File 'lib/openwfe/expressions/flowexpression.rb', line 572

def clean_children

    return unless @children

    @children.each do |child_fei|
        get_expression_pool.remove(child_fei) \
            if child_fei.kind_of? FlowExpressionId
    end
end

#delete_variable(varname) ⇒ Object Also known as: unset_variable

Unsets a variable in the current environment.

The variable name may be prefixed by / to indicate process level scope or by // to indicate engine level (global) scope.



352
353
354
355
356
# File 'lib/openwfe/expressions/flowexpression.rb', line 352

def delete_variable (varname)

    env, var = lookup_environment(varname)
    env.delete var
end

#dup_environmentObject

This method is called in expressionpool.forget(). It duplicates the expression’s current environment (deep copy) and attaches it as the expression own environment. Returns the duplicated environment.



558
559
560
561
562
563
564
565
566
567
# File 'lib/openwfe/expressions/flowexpression.rb', line 558

def dup_environment

    env = fetch_environment
    env = env.dup
    env.fei = @fei.dup
    env.fei.expression_name = EN_ENVIRONMENT
    @environment_id = env.fei

    env.store_itself
end

#fetch_environmentObject

Just fetches the environment for this expression.



268
269
270
271
# File 'lib/openwfe/expressions/flowexpression.rb', line 268

def fetch_environment

    get_expression_pool.fetch_expression @environment_id
end

#fetch_text_content(workitem, escape = false) ⇒ Object

Returns the text stored as the children of the given expression



623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
# File 'lib/openwfe/expressions/flowexpression.rb', line 623

def fetch_text_content (workitem, escape=false)

    text = ""

    children.each do |child|

        if child.is_a?(RawExpression)

            text << child.fei.to_s

        elsif child.is_a?(FlowExpressionId)

            text << get_expression_pool\
                .fetch_expression(child).raw_representation.to_s

        else

            text << child.to_s
        end
    end

    return nil if text == ""

    text = OpenWFE::dosub(text, self, workitem) \
        unless escape

    text
end

#get_bindingObject

Currently only used by dollar.rb and its $r:some_ruby_code, returns the binding in this flow expression.



598
599
600
601
# File 'lib/openwfe/expressions/flowexpression.rb', line 598

def get_binding

    binding()
end

#get_environmentObject

Returns the environment instance this expression uses. An environment is a container (a scope) for variables in the process definition. Environments themselves are FlowExpression instances.



241
242
243
244
# File 'lib/openwfe/expressions/flowexpression.rb', line 241

def get_environment

    fetch_environment || get_expression_pool.fetch_engine_environment
end

#get_parentObject

Returns the parent expression (not as a FlowExpressionId but directly as the FlowExpression instance it is).



213
214
215
216
217
218
# File 'lib/openwfe/expressions/flowexpression.rb', line 213

def get_parent

    #parent, parent_fei = get_expression_pool.fetch @parent_id
    #parent
    get_expression_pool.fetch_expression @parent_id
end

#get_root_environmentObject

A shortcut for fetch_environment.get_root_environment

Returns the environment of the top process (the environement just before the engine environment in the hierarchy).



252
253
254
255
# File 'lib/openwfe/expressions/flowexpression.rb', line 252

def get_root_environment

    fetch_environment.get_root_environment
end

#has_attribute(attname) ⇒ Object

Returns true if the expression has the given attribute. The attname parameter can be a String or a Symbol.



449
450
451
452
453
454
455
# File 'lib/openwfe/expressions/flowexpression.rb', line 449

def has_attribute (attname)

    attname = OpenWFE::symbol_to_name(attname) \
        if attname.kind_of?(Symbol)

    (@attributes[attname] != nil)
end

#lookup_attribute(attname, workitem, options = {}) ⇒ Object

Looks up the value for an attribute of this expression.

if the expression is

<participant ref="toto" />

then

participant_expression.lookup_attribute("toto", wi)

will yield “toto”

The various methods for looking up attributes do perform dollar variable substitution. It’s ok to pass a Symbol for the attribute name.



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/openwfe/expressions/flowexpression.rb', line 377

def lookup_attribute (attname, workitem, options={})

    #p attname

    default = options[:default]
    escape = options[:escape]

    attname = OpenWFE::symbol_to_name(attname) \
        if attname.kind_of?(Symbol)

    #ldebug { "lookup_attribute() '#{attname}' in #{@fei.to_debug_s}" }

    text = @attributes[attname]

    return default if text == nil
    return text unless text.is_a?(String)

    return text if escape == true
        # returns text if escape is set and is set to true

    OpenWFE::dosub text, self, workitem
end

#lookup_attributes(workitem, _attributes = nil) ⇒ Object

Returns a hash of all the FlowExpression attributes with their values having undergone dollar variable substitution. If the attributes parameter is set (to an Array instance) then only the attributes named in that list will be looked up.

It’s ok to pass an array of Symbol instances for the attributes parameter.



466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'lib/openwfe/expressions/flowexpression.rb', line 466

def lookup_attributes (workitem, _attributes=nil)

    result = {}

    return result if not @attributes

    _attributes = @attributes.keys if not _attributes

    _attributes.each do |k|
        k = k.to_s
        v = @attributes[k]
        result[k] = OpenWFE::dosub(v, self, workitem)
        #ldebug do 
        #    "lookup_attributes() added '#{k}' -> '#{result[k]}'"
        #end
    end

    result
end

#lookup_boolean_attribute(attname, workitem, default = false) ⇒ Object

A convenience method for looking up a boolean value. It’s ok to pass a Symbol for the attribute name.



437
438
439
440
441
442
443
# File 'lib/openwfe/expressions/flowexpression.rb', line 437

def lookup_boolean_attribute (attname, workitem, default=false)

    result = lookup_downcase_attribute attname, workitem
    return default if result == nil

    (result == 'true')
end

#lookup_comma_list_attribute(attname, workitem, options = {}) ⇒ Object

For an expression like

iterator :on_value => "a, b, c", to-variable => "v0" do
    # ...
end

this call

lookup_comma_list_attribute(:on_value, wi)

will return

[ 'a', 'b', 'c' ]


501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/openwfe/expressions/flowexpression.rb', line 501

def lookup_comma_list_attribute (attname, workitem, options={})

    a = lookup_attribute(attname, workitem, options)

    return nil if not a

    result = []
    a.split(',').each do |elt|
        elt = elt.strip
        result << elt if elt.length > 0
    end

    result
end

#lookup_downcase_attribute(attname, workitem, options = {}) ⇒ Object

Like lookup_attribute() but returns the value downcased [ (and stripped). Returns nil if no such attribute was found.



415
416
417
418
419
420
# File 'lib/openwfe/expressions/flowexpression.rb', line 415

def lookup_downcase_attribute (attname, workitem, options={})

    result = lookup_string_attribute attname, workitem, options
    result = result.strip.downcase if result
    result
end

#lookup_ref(workitem, prefix = '') ⇒ Object

looks up for ‘ref’, ‘variable-ref’ and then for ‘field-ref’ if necessary.



666
667
668
669
670
671
# File 'lib/openwfe/expressions/flowexpression.rb', line 666

def lookup_ref (workitem, prefix='')

    ref = lookup_vf_attribute workitem, 'ref', :prefix => prefix
    return ref.to_s if ref
    nil
end

#lookup_string_attribute(attname, workitem, options = {}) ⇒ Object

Returns the attribute value as a String (or nil if it’s not found).



403
404
405
406
407
408
# File 'lib/openwfe/expressions/flowexpression.rb', line 403

def lookup_string_attribute (attname, workitem, options={})

    result = lookup_attribute attname, workitem, options
    result = result.to_s if result
    result
end

#lookup_sym_attribute(attname, workitem, options = {}) ⇒ Object

Returns the value of the attribute as a Symbol. Returns nil if there is no attribute under the given name.



426
427
428
429
430
431
# File 'lib/openwfe/expressions/flowexpression.rb', line 426

def lookup_sym_attribute (attname, workitem, options={})

    result = lookup_downcase_attribute attname, workitem, options
    result = result.to_sym if result
    result
end

#lookup_value(workitem, options = {}) ⇒ Object

looks up for ‘value’, ‘variable-value’ and then for ‘field-value’ if necessary.



656
657
658
659
660
# File 'lib/openwfe/expressions/flowexpression.rb', line 656

def lookup_value (workitem, options={})

    lookup_vf_attribute(workitem, 'value', options) ||
    lookup_vf_attribute(workitem, 'val', options)
end

#lookup_variable(varname) ⇒ Object

Looks up the value of a variable in the current environment. If not found locally will lookup at the process level and even further in the engine scope.

The variable name may be prefixed by / to indicate process level scope or by // to indicate engine level (global) scope.



337
338
339
340
341
342
343
344
# File 'lib/openwfe/expressions/flowexpression.rb', line 337

def lookup_variable (varname)

    #puts "lv : #{varname}"
    #puts OpenWFE.caller_to_s(0, 5)

    env, var = lookup_environment(varname)
    env[var]
end

#lookup_vf_attribute(workitem, att_name, options = {}) ⇒ Object

Looks up for value attributes like ‘field-ref’ or ‘variable-value’



676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
# File 'lib/openwfe/expressions/flowexpression.rb', line 676

def lookup_vf_attribute (workitem, att_name, options={})

    att_name = att_name.to_s

    prefix = options[:prefix] || ''
    prefix = prefix.to_s

    dash = (att_name.size > 0 and prefix.size > 0) ? "-" : ""

    v = lookup_attribute(
        "#{prefix}#{dash}#{att_name}", workitem, options)

    att_name = "-#{att_name}" if att_name.size > 0
    prefix = "#{prefix}-" if prefix.size > 0

    return v if v

    v = lookup_attribute(
        "#{prefix}variable#{att_name}", workitem, options) ||
        lookup_attribute(
        "#{prefix}var#{att_name}", workitem, options) ||
        lookup_attribute(
        "#{prefix}v#{att_name}", workitem, options)

    return lookup_variable(v) if v

    f = lookup_attribute(
        "#{prefix}field#{att_name}", workitem, options) ||
        lookup_attribute(
        "#{prefix}f#{att_name}", workitem, options)

    #return workitem.attributes[f] if f
    return workitem.attributes[f.to_s] if f

    nil
end

#new_environment(initial_vars = nil) ⇒ Object

creates a new environment just for this expression



519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
# File 'lib/openwfe/expressions/flowexpression.rb', line 519

def new_environment (initial_vars=nil)

    ldebug { "new_environment() for #{@fei.to_debug_s}" }

    @environment_id = @fei.dup
    @environment_id.expression_name = EN_ENVIRONMENT

    parent_fei = nil
    parent = nil

    parent, _fei = get_expression_pool.fetch(@parent_id) \
        if @parent_id

    parent_fei = parent.environment_id if parent

    env = Environment.new_env(
        @environment_id, parent_fei, nil, @application_context, nil)
    
    env.variables.merge! initial_vars if initial_vars

    env[@fei.wfname] = self.raw_representation \
        if (not @parent_id) and (self.is_a?(RawExpression))
            #
            # keeping track of the raw representation
            # of the top expression (for top recursion)

    ldebug { "new_environment() is #{env.fei.to_debug_s}" }

    env.store_itself

    env
end

#owns_its_environment?Boolean

Returns true if the expression’s environment was generated for itself (usually DefineExpression do have such envs)

Returns:

  • (Boolean)


277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/openwfe/expressions/flowexpression.rb', line 277

def owns_its_environment?

    #ldebug do 
    #    "owns_its_environment?()\n" +
    #    "    #{@fei.to_debug_s}\n" +
    #    "    #{@environment_id.to_debug_s}"
    #end

    return false if not @environment_id

    ei = @fei.dup
    vi = @environment_id.dup

    ei.expression_name = "neutral"
    vi.expression_name = "neutral"

    #ldebug do
    #    "owns_its_environment?()\n"+
    #    "   exp  #{ei.to_debug_s}\n"+
    #    "   env  #{vi.to_debug_s}"
    #end

    (ei == vi)
end

#paused?Boolean

Returns true if this expression belongs to a paused flow

Returns:

  • (Boolean)


305
306
307
308
# File 'lib/openwfe/expressions/flowexpression.rb', line 305

def paused?

    (lookup_variable(VAR_PAUSED) == true)
end

#remove_child(child_fei) ⇒ Object

Removes a child from the expression children list.



585
586
587
588
589
590
591
592
# File 'lib/openwfe/expressions/flowexpression.rb', line 585

def remove_child (child_fei)

    fei = @children.delete child_fei

    store_itself if fei
        #
        # store_itself if the child was really removed.
end

#reply(workitem) ⇒ Object

this default implementation immediately replies to the parent expression



168
169
170
171
# File 'lib/openwfe/expressions/flowexpression.rb', line 168

def reply (workitem)

    reply_to_parent workitem
end

#reply_to_parent(workitem) ⇒ Object

Triggers the reply to the parent expression (of course, via the expression pool). Expressions do call this method when their job is done and the flow should resume without them.



179
180
181
182
# File 'lib/openwfe/expressions/flowexpression.rb', line 179

def reply_to_parent (workitem)

    get_expression_pool.reply_to_parent self, workitem
end

#set_variable(varname, value) ⇒ Object

Sets a variable in the current environment. Is usually called by the ‘set’ expression.

The variable name may be prefixed by / to indicate process level scope or by // to indicate engine level (global) scope.



317
318
319
320
321
322
323
324
325
326
327
# File 'lib/openwfe/expressions/flowexpression.rb', line 317

def set_variable (varname, value)

    env, var = lookup_environment(varname)

    ldebug do 
        "set_variable() '#{varname}' to '#{value}' " +
        "in  #{env.fei.to_debug_s}"
    end

    env[var] = value
end

#store_itselfObject

Stores itself in the expression pool. It’s very important for expressions in persisted context to save themselves as soon as their state changed. Else this information would be lost at engine restart or simply if the expression got swapped out of memory and reloaded later.



227
228
229
230
231
232
233
# File 'lib/openwfe/expressions/flowexpression.rb', line 227

def store_itself

    ldebug { "store_itself() for  #{@fei.to_debug_s}" }
    #ldebug { "store_itself() \n#{OpenWFE::caller_to_s(0, 6)}" }

    get_expression_pool.update self
end

#synchronizeObject

Used like the classical Ruby synchronize, but as the OpenWFE expression pool manages its own set of monitors, it’s one of those monitors that is used. But the synchronize code looks like the class just included the MonitorMixin. No hassle.



609
610
611
612
613
614
615
616
617
618
# File 'lib/openwfe/expressions/flowexpression.rb', line 609

def synchronize

    #ldebug { "synchronize() ---in--- for  #{@fei.to_debug_s}" }

    get_expression_pool.get_monitor(@fei).synchronize do
        yield
    end

    #ldebug { "synchronize() --out--  for  #{@fei.to_debug_s}" }
end

#to_sObject

Some eye candy



716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
# File 'lib/openwfe/expressions/flowexpression.rb', line 716

def to_s

    s =    "* #{@fei.to_debug_s} [#{self.class.name}]"

    s << "\n   `--p--> #{@parent_id.to_debug_s}" \
        if @parent_id

    s << "\n   `--e--> #{@environment_id.to_debug_s}" \
        if @environment_id

    return s unless @children

    @children.each do |c|
        sc = if c.kind_of?(OpenWFE::FlowExpressionId)
            c.to_debug_s
        else
            ">#{c.to_s}<"
        end
        s << "\n   `--c--> #{sc}"
    end

    s
end

#to_yaml_propertiesObject



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/openwfe/storage/yamlcustom.rb', line 55

def to_yaml_properties

    l = super()

    l.delete("@application_context")

    #l.delete("@timeout_job_id")
    #l.delete("@scheduler_job_id")
        # scheduler ids should not get persisted

    l
end