lib/openwfe/expressions/fe_concurrence.rb in ruote-0.9.18 vs lib/openwfe/expressions/fe_concurrence.rb in ruote-0.9.19

- old
+ new

@@ -1,34 +1,34 @@ # #-- # Copyright (c) 2006-2008, John Mettraux, OpenWFE.org # All rights reserved. -# -# Redistribution and use in source and binary forms, with or without +# +# Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # . Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# . Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation +# list of conditions and the following disclaimer. +# +# . Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. -# +# # . Neither the name of the "OpenWFE" nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #++ # # @@ -49,614 +49,614 @@ # base expressions like 'sequence' and 'concurrence' # module OpenWFE - # - # The concurrence expression will execute each of its (direct) children - # in parallel threads. - # - # Thus, - # - # <concurrence> - # <participant ref="pa" /> - # <participant ref="pb" /> - # </concurrence> - # - # Participants pa and pb will be 'treated' in parallel (quasi - # simultaneously). - # - # The concurrence expressions accept many attributes, that can get - # combined. By default, the concurrence waits for all its children to - # reply and returns the workitem of the first child that replied. - # The attributes tune this behaviour. - # - # <em>count</em> - # - # <concurrence count="1"> - # <participant ref="pa" /> - # <participant ref="pb" /> - # </concurrence> - # - # The concurrence will be over as soon as 'pa' or 'pb' replied, i.e. - # as soon as "1" child replied. - # - # <em>remaining</em> - # - # The attribute 'remaining' can take two values 'cancel' (the default) and - # 'forget'. - # Cancelled children are completely wiped away, forgotten ones continue - # to operate but their reply will simply get discarded. - # - # <em>over-if</em> - # - # 'over-if' accepts a 'boolean expression' (something replying 'true' or - # 'false'), if the expression evaluates to true, the concurrence will be - # over and the remaining children will get cancelled (the default) or - # forgotten. - # - # <em>merge</em> - # - # By default, the first child to reply to its parent 'concurrence' - # expression 'wins', i.e. its workitem is used for resuming the flow (after - # the concurrence). - # - # [first] The default : the first child to reply wins - # [last] The last child to reply wins - # [highest] The first 'defined' child (in the list of children) will win - # [lowest] The last 'defined' child (in the list of children) will win - # - # Thus, in that example - # - # <concurrence merge="lowest"> - # <participant ref="pa" /> - # <participant ref="pb" /> - # </concurrence> - # - # when the concurrence is done, the workitem of 'pb' is used to resume the - # flow after the concurrence. - # - # <em>merge-type</em> - # - # [override] The default : no mix of values between the workitems do occur - # [mix] Priority is given to the 'winning' workitem but their values - # get mixed - # [isolate] the attributes of the workitem of each branch is placed - # in a field in the resulting workitem. For example, the - # attributes of the first branch will be stored under the - # field named '0' of the resulting workitem. - # - # The merge occurs are the top level of workitem attributes. - # - # More complex merge behaviour can be obtained by extending the - # GenericSyncExpression class. But the default sync options are already - # numerous and powerful by their combinations. - # - class ConcurrenceExpression < SequenceExpression - include ConditionMixin + # + # The concurrence expression will execute each of its (direct) children + # in parallel threads. + # + # Thus, + # + # <concurrence> + # <participant ref="pa" /> + # <participant ref="pb" /> + # </concurrence> + # + # Participants pa and pb will be 'treated' in parallel (quasi + # simultaneously). + # + # The concurrence expressions accept many attributes, that can get + # combined. By default, the concurrence waits for all its children to + # reply and returns the workitem of the first child that replied. + # The attributes tune this behaviour. + # + # <em>count</em> + # + # <concurrence count="1"> + # <participant ref="pa" /> + # <participant ref="pb" /> + # </concurrence> + # + # The concurrence will be over as soon as 'pa' or 'pb' replied, i.e. + # as soon as "1" child replied. + # + # <em>remaining</em> + # + # The attribute 'remaining' can take two values 'cancel' (the default) and + # 'forget'. + # Cancelled children are completely wiped away, forgotten ones continue + # to operate but their reply will simply get discarded. + # + # <em>over-if</em> + # + # 'over-if' accepts a 'boolean expression' (something replying 'true' or + # 'false'), if the expression evaluates to true, the concurrence will be + # over and the remaining children will get cancelled (the default) or + # forgotten. + # + # <em>merge</em> + # + # By default, the first child to reply to its parent 'concurrence' + # expression 'wins', i.e. its workitem is used for resuming the flow (after + # the concurrence). + # + # [first] The default : the first child to reply wins + # [last] The last child to reply wins + # [highest] The first 'defined' child (in the list of children) will win + # [lowest] The last 'defined' child (in the list of children) will win + # + # Thus, in that example + # + # <concurrence merge="lowest"> + # <participant ref="pa" /> + # <participant ref="pb" /> + # </concurrence> + # + # when the concurrence is done, the workitem of 'pb' is used to resume the + # flow after the concurrence. + # + # <em>merge-type</em> + # + # [override] The default : no mix of values between the workitems do occur + # [mix] Priority is given to the 'winning' workitem but their values + # get mixed + # [isolate] the attributes of the workitem of each branch is placed + # in a field in the resulting workitem. For example, the + # attributes of the first branch will be stored under the + # field named '0' of the resulting workitem. + # + # The merge occurs are the top level of workitem attributes. + # + # More complex merge behaviour can be obtained by extending the + # GenericSyncExpression class. But the default sync options are already + # numerous and powerful by their combinations. + # + class ConcurrenceExpression < SequenceExpression + include ConditionMixin - names :concurrence + names :concurrence - attr_accessor \ - :sync_expression + attr_accessor \ + :sync_expression - def apply (workitem) + def apply (workitem) - sync = lookup_sym_attribute( - :sync, workitem, :default => :generic) + sync = lookup_sym_attribute( + :sync, workitem, :default => :generic) - @sync_expression = - get_expression_map.get_sync_class(sync).new(self, workitem) + @sync_expression = + get_expression_map.get_sync_class(sync).new(self, workitem) - @children.each do |child| - @sync_expression.add_child child - end + @children.each do |child| + @sync_expression.add_child child + end - store_itself + store_itself - #concurrence = self + #concurrence = self - @children.each_with_index do |child, index| + @children.each_with_index do |child, index| - get_expression_pool.apply( - child, - get_workitem(workitem, index)) + get_expression_pool.apply( + child, + get_workitem(workitem, index)) - #Thread.new do - # begin - # #ldebug { "apply() child : #{child.to_debug_s}" } - # concurrence.synchronize do - # get_expression_pool().apply( - # child, - # #workitem.dup) - # get_workitem(workitem, index)) - # end - # rescue Exception => e - # lwarn do - # "apply() " + - # "caught exception in concurrent child " + - # child.to_debug_s + "\n" + - # OpenWFE::exception_to_s(e) - # end - # end - #end - end + #Thread.new do + # begin + # #ldebug { "apply() child : #{child.to_debug_s}" } + # concurrence.synchronize do + # get_expression_pool().apply( + # child, + # #workitem.dup) + # get_workitem(workitem, index)) + # end + # rescue Exception => e + # lwarn do + # "apply() " + + # "caught exception in concurrent child " + + # child.to_debug_s + "\n" + + # OpenWFE::exception_to_s(e) + # end + # end + #end + end - #@sync_expression.ready(self) - # - # this is insufficient, have to do that : + #@sync_expression.ready(self) + # + # this is insufficient, have to do that : - #synchronize do - # - # Making sure the freshest version of the concurrence - # expression is used. - # This is especially important when using pure persistence. - # - reloaded_self, _fei = get_expression_pool.fetch @fei - reloaded_self.sync_expression.ready reloaded_self - #end - end + #synchronize do + # + # Making sure the freshest version of the concurrence + # expression is used. + # This is especially important when using pure persistence. + # + reloaded_self, _fei = get_expression_pool.fetch @fei + reloaded_self.sync_expression.ready reloaded_self + #end + end - def reply (workitem) - @sync_expression.reply(self, workitem) - end - - protected - - def get_workitem (workitem, index) - workitem.dup - end + def reply (workitem) + @sync_expression.reply(self, workitem) end - # - # This expression is a mix between a 'concurrence' and an 'iterator'. - # It understands the same attributes and behaves as an interator that - # forks its children concurrently. - # - # Some examples : - # - # <concurrent-iterator on-value="sales, logistics, lob2" to-field="p"> - # <participant field-ref="p" /> - # </concurrent-iterator> - # - # Within a Ruby process definition : - # - # sequence do - # set :field => f, :value => %w{ Alan, Bob, Clarence } - # #... - # concurrent_iterator :on_field => "f", :to_field => "p" do - # participant "${p}" - # end - # end - # - class ConcurrentIteratorExpression < ConcurrenceExpression + protected - names :concurrent_iterator + def get_workitem (workitem, index) + workitem.dup + end + end - #attr_accessor :template + # + # This expression is a mix between a 'concurrence' and an 'iterator'. + # It understands the same attributes and behaves as an interator that + # forks its children concurrently. + # + # Some examples : + # + # <concurrent-iterator on-value="sales, logistics, lob2" to-field="p"> + # <participant field-ref="p" /> + # </concurrent-iterator> + # + # Within a Ruby process definition : + # + # sequence do + # set :field => f, :value => %w{ Alan, Bob, Clarence } + # #... + # concurrent_iterator :on_field => "f", :to_field => "p" do + # participant "${p}" + # end + # end + # + class ConcurrentIteratorExpression < ConcurrenceExpression - uses_template + names :concurrent_iterator + #attr_accessor :template - def apply (workitem) + uses_template - return reply_to_parent(workitem) \ - if raw_children.length < 1 - @workitems = [] + def apply (workitem) - iterator = Iterator.new self, workitem + return reply_to_parent(workitem) \ + if raw_children.length < 1 - return reply_to_parent(workitem) \ - unless iterator.has_next? + @workitems = [] - while iterator.has_next? + iterator = Iterator.new self, workitem - wi = workitem.dup + return reply_to_parent(workitem) \ + unless iterator.has_next? - @workitems << wi + while iterator.has_next? - vars = iterator.next wi + wi = workitem.dup - #rawexp = get_expression_pool.prepare_from_template( - # self, nil, iterator.index, template, vars) - #@children << rawexp.fei + @workitems << wi - get_expression_pool.tprepare_child( - self, - raw_children.first, - iterator.index, - true, # register child - vars) - end + vars = iterator.next wi - super - end + #rawexp = get_expression_pool.prepare_from_template( + # self, nil, iterator.index, template, vars) + #@children << rawexp.fei - protected + get_expression_pool.tprepare_child( + self, + raw_children.first, + iterator.index, + true, # register child + vars) + end - def get_workitem (workitem, index) - - @workitems[index] - end + super end - # - # A base for sync expressions, currently empty. - # That may change. - # - class SyncExpression < ObjectWithMeta + protected - def initialize + def get_workitem (workitem, index) - super - end + @workitems[index] + end + end - def self.names (*exp_names) + # + # A base for sync expressions, currently empty. + # That may change. + # + class SyncExpression < ObjectWithMeta - exp_names = exp_names.collect do |n| - n.to_s - end - meta_def :expression_names do - exp_names - end - end + def initialize + + super end - # - # The classical OpenWFE sync expression. - # Used by 'concurrence' and 'concurrent-iterator' - # - class GenericSyncExpression < SyncExpression + def self.names (*exp_names) - names :generic + exp_names = exp_names.collect do |n| + n.to_s + end + meta_def :expression_names do + exp_names + end + end + end - attr_accessor \ - :remaining_children, - :count, - :reply_count, - :cancel_remaining, - :unready_queue + # + # The classical OpenWFE sync expression. + # Used by 'concurrence' and 'concurrent-iterator' + # + class GenericSyncExpression < SyncExpression - def initialize (synchable, workitem) + names :generic - super() + attr_accessor \ + :remaining_children, + :count, + :reply_count, + :cancel_remaining, + :unready_queue - @remaining_children = [] - @reply_count = 0 + def initialize (synchable, workitem) - @count = determine_count(synchable, workitem) - @cancel_remaining = cancel_remaining?(synchable, workitem) + super() - merge = synchable.lookup_sym_attribute( - :merge, workitem, :default => :first) + @remaining_children = [] + @reply_count = 0 - merge_type = synchable.lookup_sym_attribute( - :merge_type, workitem, :default => :mix) + @count = determine_count(synchable, workitem) + @cancel_remaining = cancel_remaining?(synchable, workitem) - synchable.ldebug { "new() merge_type is '#{merge_type}'" } + merge = synchable.lookup_sym_attribute( + :merge, workitem, :default => :first) - @merge_array = MergeArray.new synchable.fei, merge, merge_type + merge_type = synchable.lookup_sym_attribute( + :merge_type, workitem, :default => :mix) - @unready_queue = [] - end + synchable.ldebug { "new() merge_type is '#{merge_type}'" } - # - # when all the children got applied concurrently, the concurrence - # calls this method to notify the sync expression that replies - # can be processed - # - def ready (synchable) - #synchable.synchronize do + @merge_array = MergeArray.new synchable.fei, merge, merge_type - synchable.ldebug do - "ready() called by #{synchable.fei.to_debug_s} " + - "#{@unready_queue.length} wi waiting" - end + @unready_queue = [] + end - queue = @unready_queue - @unready_queue = nil - synchable.store_itself + # + # when all the children got applied concurrently, the concurrence + # calls this method to notify the sync expression that replies + # can be processed + # + def ready (synchable) + #synchable.synchronize do - queue.each do |workitem| - break if do_reply(synchable, workitem) - # - # do_reply() will return 'true' as soon as the - # concurrence is over, if this is the case, the - # queue should not be treated anymore - end - #end - end + synchable.ldebug do + "ready() called by #{synchable.fei.to_debug_s} " + + "#{@unready_queue.length} wi waiting" + end - def add_child (child) - @remaining_children << child - end + queue = @unready_queue + @unready_queue = nil + synchable.store_itself - def reply (synchable, workitem) - #synchable.synchronize do + queue.each do |workitem| + break if do_reply(synchable, workitem) + # + # do_reply() will return 'true' as soon as the + # concurrence is over, if this is the case, the + # queue should not be treated anymore + end + #end + end - if @unready_queue + def add_child (child) + @remaining_children << child + end - @unready_queue << workitem + def reply (synchable, workitem) + #synchable.synchronize do - synchable.store_itself + if @unready_queue - synchable.ldebug do - "#{self.class}.reply() "+ - "#{@unready_queue.length} wi waiting..." - end + @unready_queue << workitem - else - do_reply synchable, workitem - end - #end + synchable.store_itself + + synchable.ldebug do + "#{self.class}.reply() "+ + "#{@unready_queue.length} wi waiting..." end - protected + else + do_reply synchable, workitem + end + #end + end - def do_reply (synchable, workitem) + protected - synchable.ldebug do - "#{self.class}.do_reply() from " + - "#{workitem.last_expression_id.to_debug_s}" - end + def do_reply (synchable, workitem) - @merge_array.push(synchable, workitem) + synchable.ldebug do + "#{self.class}.do_reply() from " + + "#{workitem.last_expression_id.to_debug_s}" + end - @reply_count = @reply_count + 1 + @merge_array.push(synchable, workitem) - @remaining_children.delete(workitem.last_expression_id) + @reply_count = @reply_count + 1 - #synchable.ldebug do - # "#{self.class}.do_reply() "+ - # "remaining children : #{@remaining_children.length}" - #end + @remaining_children.delete(workitem.last_expression_id) - if @remaining_children.length <= 0 - reply_to_parent(synchable) - return true - end + #synchable.ldebug do + # "#{self.class}.do_reply() "+ + # "remaining children : #{@remaining_children.length}" + #end - if @count > 0 and @reply_count >= @count - treat_remaining_children(synchable) - reply_to_parent(synchable) - return true - end + if @remaining_children.length <= 0 + reply_to_parent(synchable) + return true + end - # - # over-if + if @count > 0 and @reply_count >= @count + treat_remaining_children(synchable) + reply_to_parent(synchable) + return true + end - conditional = - synchable.eval_condition("over-if", workitem, "over-unless") + # + # over-if - if conditional - treat_remaining_children(synchable) - reply_to_parent(synchable) - return true - end + conditional = + synchable.eval_condition("over-if", workitem, "over-unless") - # - # not over, resuming + if conditional + treat_remaining_children(synchable) + reply_to_parent(synchable) + return true + end - synchable.store_itself() + # + # not over, resuming - #synchable.ldebug do - # "#{self.class}.do_reply() not replying to parent "+ - # "#{workitem.last_expression_id.to_debug_s}" - #end + synchable.store_itself() - false - end + #synchable.ldebug do + # "#{self.class}.do_reply() not replying to parent "+ + # "#{workitem.last_expression_id.to_debug_s}" + #end - def reply_to_parent (synchable) + false + end - workitem = @merge_array.do_merge + def reply_to_parent (synchable) - synchable.reply_to_parent workitem - end + workitem = @merge_array.do_merge - def treat_remaining_children (synchable) + synchable.reply_to_parent workitem + end - expool = synchable.get_expression_pool + def treat_remaining_children (synchable) - @remaining_children.each do |child| + expool = synchable.get_expression_pool - synchable.ldebug do - "#{self.class}.treat_remainining_children() " + - "#{child.to_debug_s} " + - "(cancel ? #{@cancel_remaining})" - end + @remaining_children.each do |child| - if @cancel_remaining - expool.cancel(child) - else - expool.forget(synchable, child) - end - end - end + synchable.ldebug do + "#{self.class}.treat_remainining_children() " + + "#{child.to_debug_s} " + + "(cancel ? #{@cancel_remaining})" + end - def cancel_remaining? (synchable_expression, workitem) + if @cancel_remaining + expool.cancel(child) + else + expool.forget(synchable, child) + end + end + end - s = synchable_expression.lookup_sym_attribute( - :remaining, workitem, :default => :cancel) + def cancel_remaining? (synchable_expression, workitem) - (s == :cancel) - end + s = synchable_expression.lookup_sym_attribute( + :remaining, workitem, :default => :cancel) - def determine_count (synchable_expression, workitem) + (s == :cancel) + end - c = synchable_expression.lookup_attribute :count, workitem - return -1 if not c - i = c.to_i - return -1 if i < 1 - i - end + def determine_count (synchable_expression, workitem) - # - # This inner class is used to gather workitems (via push()) before - # the final merge - # This final merge is triggered by calling the do_merge() method - # which will return the resulting, merged workitem. - # - class MergeArray - include MergeMixin + c = synchable_expression.lookup_attribute :count, workitem + return -1 if not c + i = c.to_i + return -1 if i < 1 + i + end - attr_accessor \ - :synchable_fei, - :workitem, - :workitems_by_arrival, - :workitems_by_altitude, - :merge, - :merge_type + # + # This inner class is used to gather workitems (via push()) before + # the final merge + # This final merge is triggered by calling the do_merge() method + # which will return the resulting, merged workitem. + # + class MergeArray + include MergeMixin - def initialize (synchable_fei, merge, merge_type) + attr_accessor \ + :synchable_fei, + :workitem, + :workitems_by_arrival, + :workitems_by_altitude, + :merge, + :merge_type - @synchable_fei = synchable_fei + def initialize (synchable_fei, merge, merge_type) - @merge = merge - @merge_type = merge_type + @synchable_fei = synchable_fei - ensure_merge_settings + @merge = merge + @merge_type = merge_type - @workitem = nil + ensure_merge_settings - if highest? or lowest? - @workitems_by_arrival = [] - @workitems_by_altitude = [] - end - end + @workitem = nil - def push (synchable, wi) + if highest? or lowest? + @workitems_by_arrival = [] + @workitems_by_altitude = [] + end + end - #synchable.ldebug do - # "push() isolate? #{isolate?}" - #end + def push (synchable, wi) - if isolate? - push_in_isolation wi - elsif last? or first? - push_by_position wi - else - push_by_arrival wi - end - end + #synchable.ldebug do + # "push() isolate? #{isolate?}" + #end - def push_by_position (wi) + if isolate? + push_in_isolation wi + elsif last? or first? + push_by_position wi + else + push_by_arrival wi + end + end - source, target = if first? - [ @workitem, wi ] - else - [ wi, @workitem ] - end - @workitem = merge_workitems target, source, override? - end + def push_by_position (wi) - def push_in_isolation (wi) + source, target = if first? + [ @workitem, wi ] + else + [ wi, @workitem ] + end + @workitem = merge_workitems target, source, override? + end - unless @workitem - @workitem = wi.dup - att = @workitem.attributes - @workitem.attributes = {} - end + def push_in_isolation (wi) - #key = synchable.children.index wi.last_expression_id - #key = wi.last_expression_id.child_id - key = get_child_id wi + unless @workitem + @workitem = wi.dup + att = @workitem.attributes + @workitem.attributes = {} + end - @workitem.attributes[key.to_s] = - OpenWFE::fulldup(wi.attributes) - end + #key = synchable.children.index wi.last_expression_id + #key = wi.last_expression_id.child_id + key = get_child_id wi - def push_by_arrival (wi) + @workitem.attributes[key.to_s] = + OpenWFE::fulldup(wi.attributes) + end - #index = synchable.children.index wi.last_expression_id - #index = Integer(wi.last_expression_id.child_id) - index = Integer(get_child_id(wi)) + def push_by_arrival (wi) - @workitems_by_arrival << wi - @workitems_by_altitude[index] = wi - end + #index = synchable.children.index wi.last_expression_id + #index = Integer(wi.last_expression_id.child_id) + index = Integer(get_child_id(wi)) - # - # merges the workitems stored here - # - def do_merge + @workitems_by_arrival << wi + @workitems_by_altitude[index] = wi + end - return @workitem if @workitem + # + # merges the workitems stored here + # + def do_merge - list = if first? - @workitems_by_arrival.reverse - elsif last? - @workitems_by_arrival - elsif highest? - @workitems_by_altitude.reverse - elsif lowest? - @workitems_by_altitude - end + return @workitem if @workitem - result = nil + list = if first? + @workitems_by_arrival.reverse + elsif last? + @workitems_by_arrival + elsif highest? + @workitems_by_altitude.reverse + elsif lowest? + @workitems_by_altitude + end - list.each do |wi| - next unless wi - result = merge_workitems result, wi, override? - end + result = nil - #puts "___ result :" - #puts result.to_s - #puts + list.each do |wi| + next unless wi + result = merge_workitems result, wi, override? + end - result - end + #puts "___ result :" + #puts result.to_s + #puts - protected + result + end - def first? - @merge == :first - end - def last? - @merge == :last - end - def highest? - @merge == :highest - end - def lowest? - @merge == :lowest - end + protected - def mix? - @merge_type == :mix - end - def override? - @merge_type == :override - end - def isolate? - @merge_type == :isolate - end + def first? + @merge == :first + end + def last? + @merge == :last + end + def highest? + @merge == :highest + end + def lowest? + @merge == :lowest + end - # - # Returns the child id of the expression that just - # replied with the given workitem. - # - def get_child_id (workitem) + def mix? + @merge_type == :mix + end + def override? + @merge_type == :override + end + def isolate? + @merge_type == :isolate + end - return workitem.fei.child_id \ - if workitem.fei.wfid == @synchable_fei.wfid + # + # Returns the child id of the expression that just + # replied with the given workitem. + # + def get_child_id (workitem) - workitem.fei.last_sub_instance_id - end + return workitem.fei.child_id \ + if workitem.fei.wfid == @synchable_fei.wfid - # - # Making sure @merge and @merge_type are set to - # appropriate values. - # - def ensure_merge_settings + workitem.fei.last_sub_instance_id + end - @merge_type = :mix unless override? or isolate? - @merge = :first unless last? or highest? or lowest? - end - end + # + # Making sure @merge and @merge_type are set to + # appropriate values. + # + def ensure_merge_settings - end + @merge_type = :mix unless override? or isolate? + @merge = :first unless last? or highest? or lowest? + end + end + + end end