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

- old
+ new

@@ -1,34 +1,34 @@ # #-- # Copyright (c) 2007-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. #++ # # @@ -40,173 +40,184 @@ #require 'thread' module OpenWFE + # + # The 'reserve' expression ensures that its nested child expression + # executes while a reserved mutex is set. + # + # Thus + # + # concurrence do + # reserve :mutex => :m0 do + # sequence do + # participant :alpha + # participant :bravo + # end + # end + # reserve :mutex => :m0 do + # participant :charly + # end + # participant :delta + # end + # + # The sequence will not but run while the participant charly is active + # and vice versa. The participant delta is not concerned. + # + # The mutex is a regular variable name, thus a mutex named "//toto" could + # be used to prevent segments of totally different process instances from + # running. + # + class ReserveExpression < FlowExpression + # - # The 'reserve' expression ensures that its nested child expression - # executes while a reserved mutex is set. + # A mutex for the whole class, it's meant to prevent 'reserve' + # from reserving a workflow mutex simultaneaously. # - # Thus + #@@mutex = Mutex.new + + names :reserve + # - # concurrence do - # reserve :mutex => :m0 do - # sequence do - # participant :alpha - # participant :bravo - # end - # end - # reserve :mutex => :m0 do - # participant :charly - # end - # participant :delta - # end + # The name of the mutex this expressions uses. + # It's a variable name, that means it can be prefixed with + # {nothing} (local scope), '/' (process scope) and '//' (engine / + # global scope). # - # The sequence will not but run while the participant charly is active - # and vice versa. The participant delta is not concerned. + attr_accessor :mutex_name + # - # The mutex is a regular variable name, thus a mutex named "//toto" could - # be used to prevent segments of totally different process instances from - # running. + # An instance variable for storing the applied workitem if the 'reserve' + # cannot be entered immediately. # - class ReserveExpression < FlowExpression + attr_accessor :applied_workitem - # - # A mutex for the whole class, it's meant to prevent 'reserve' - # from reserving a workflow mutex simultaneaously. - # - #@@mutex = Mutex.new - names :reserve + def apply (workitem) - # - # The name of the mutex this expressions uses. - # It's a variable name, that means it can be prefixed with - # {nothing} (local scope), '/' (process scope) and '//' (engine / - # global scope). - # - attr_accessor :mutex_name + return reply_to_parent(workitem) \ + if @children.size < 1 - # - # An instance variable for storing the applied workitem if the 'reserve' - # cannot be entered immediately. - # - attr_accessor :applied_workitem + @mutex_name = lookup_string_attribute :mutex, workitem + #FlowMutex.synchronize do - def apply (workitem) + mutex = lookup_variable(@mutex_name) || FlowMutex.new(@mutex_name) - return reply_to_parent(workitem) \ - if @children.size < 1 + mutex.register self, workitem + #end + end - @mutex_name = lookup_string_attribute :mutex, workitem + def reply (workitem) - #FlowMutex.synchronize do + lookup_variable(@mutex_name).release self - mutex = lookup_variable(@mutex_name) || FlowMutex.new(@mutex_name) + reply_to_parent workitem + end - mutex.register self, workitem - #end - end + # + # takes care of exiting the critical section once the children + # have been cancelled + # + def cancel - def reply (workitem) + super - lookup_variable(@mutex_name).release self - - reply_to_parent workitem - end - - # - # Called by the FlowMutex to enter the 'reserved/critical' section. - # - def enter (workitem=nil) - - get_expression_pool.apply( - @children[0], workitem || @applied_workitem) - end + lookup_variable(@mutex_name).release self end # - # A FlowMutex is a process variable (thus serializable) that keeps - # track of the expressions in a critical section (1!) or waiting for - # entering it. + # Called by the FlowMutex to enter the 'reserved/critical' section. # - #-- - # The current syncrhonization scheme is 1 thread mutex for all the - # FlowMutex. Shouldn't be too costly and the operations under sync are - # quite tiny. - #++ - # - class FlowMutex + def enter (workitem=nil) - #-- - # Granularity level ? "big rock". Only one FlowMutex operation - # a a time for the whole business process engine... - # - #@@class_mutex = Mutex.new - #++ + get_expression_pool.apply( + @children[0], workitem || @applied_workitem) + end + end - attr_accessor :mutex_name - attr_accessor :feis + # + # A FlowMutex is a process variable (thus serializable) that keeps + # track of the expressions in a critical section (1!) or waiting for + # entering it. + # + #-- + # The current syncrhonization scheme is 1 thread mutex for all the + # FlowMutex. Shouldn't be too costly and the operations under sync are + # quite tiny. + #++ + # + class FlowMutex - def initialize (mutex_name) + #-- + # Granularity level ? "big rock". Only one FlowMutex operation + # a a time for the whole business process engine... + # + #@@class_mutex = Mutex.new + #++ - @mutex_name = mutex_name - @feis = [] - end + attr_accessor :mutex_name + attr_accessor :feis - def register (fexp, workitem) + def initialize (mutex_name) - @feis << fexp.fei + @mutex_name = mutex_name + @feis = [] + end - fexp.set_variable @mutex_name, self + def register (fexp, workitem) - if @feis.size == 1 - # - # immediately let the expression enter the critical section - # - fexp.store_itself - fexp.enter workitem - else - # - # later... - # - fexp.applied_workitem = workitem - fexp.store_itself - end - end + @feis << fexp.fei - def release (releaser) + fexp.set_variable @mutex_name, self - next_fei = nil + if @feis.size == 1 + # + # immediately let the expression enter the critical section + # + fexp.store_itself + fexp.enter workitem + else + # + # later... + # + fexp.applied_workitem = workitem + fexp.store_itself + end + end - #@@class_mutex.synchronize do + def release (releaser) - current_fei = @feis.delete_at 0 + next_fei = nil - releaser.set_variable @mutex_name, self + #@@class_mutex.synchronize do - log.warn "release() BAD! c:#{current_fei} r:#{releaser.fei}" \ - if releaser.fei != current_fei + current_fei = @feis.delete_at 0 - next_fei = @feis.first - #end + releaser.set_variable @mutex_name, self - return unless next_fei + log.warn "release() BAD! c:#{current_fei} r:#{releaser.fei}" \ + if releaser.fei != current_fei - releaser.get_expression_pool.fetch_expression(next_fei).enter - end + next_fei = @feis.first + #end - #-- - # Used by the ReserveExpression when looking up for a FlowMutex - # and registering into it. - # - #def self.synchronize (&block) - # @@class_mutex.synchronize do - # block.call - # end - #end - #++ + return unless next_fei + + releaser.get_expression_pool.fetch_expression(next_fei).enter end + + #-- + # Used by the ReserveExpression when looking up for a FlowMutex + # and registering into it. + # + #def self.synchronize (&block) + # @@class_mutex.synchronize do + # block.call + # end + #end + #++ + end end