lib/openwfe/expressions/raw.rb in ruote-0.9.19 vs lib/openwfe/expressions/raw.rb in ruote-0.9.20

- old
+ new

@@ -1,47 +1,32 @@ -# #-- -# Copyright (c) 2006-2008, John Mettraux, OpenWFE.org -# All rights reserved. +# Copyright (c) 2006-2009, John Mettraux, jmettraux@gmail.com # -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: # -# . Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# . 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. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. # -# . 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 -# POSSIBILITY OF SUCH DAMAGE. +# Made in Japan. #++ -# -# -# "made in Japan" -# -# John Mettraux at openwfe.org -# -require 'openwfe/exceptions' -require 'openwfe/expressions/flowexpression' require 'openwfe/rudefinitions' +require 'openwfe/expressions/flowexpression' module OpenWFE # @@ -52,12 +37,11 @@ class RawExpression < FlowExpression # # A [static] method for creating new RawExpression instances. # - def self.new_raw ( - fei, parent_id, env_id, app_context, raw_representation) + def self.new_raw (fei, parent_id, env_id, app_context, raw_tree) re = self.new re.fei = fei re.parent_id = parent_id @@ -65,95 +49,30 @@ re.application_context = app_context re.attributes = nil re.children = [] re.apply_time = nil - re.raw_representation = raw_representation + re.raw_representation = raw_tree re end - #-- - # A duplication method that duplicates everything, except - # the application context # - #def dup - # self.class.new_raw( - # @fei.dup, - # @parent_id ? @parent_id.dup : nil, - # @environment_id ? @environment_id.dup : nil, - # @application_context, - # raw_representation) - #end - #alias :fulldup :dup - #++ - - def instantiate_real_expression ( - workitem, exp_name=nil, exp_class=nil, attributes=nil) - - exp_name ||= expression_name - exp_class ||= expression_class - - raise "unknown expression '#{exp_name}'" \ - unless exp_class - - #ldebug do - # "instantiate_real_expression() exp_class is #{exp_class}" - #end - - attributes ||= raw_representation[1] - - exp = exp_class.new - exp.fei = @fei - exp.parent_id = @parent_id - exp.environment_id = @environment_id - exp.application_context = @application_context - exp.attributes = attributes - - exp.raw_representation = raw_representation - exp.raw_rep_updated = raw_rep_updated - # - # keeping track of how the expression look at apply / - # instantiation time - - consider_tag workitem, exp - - exp.children = extract_children \ - unless exp_class.uses_template? - - exp - end - - # # When a raw expression is applied, it gets turned into the # real expression which then gets applied. # def apply (workitem) - exp_name, exp_class, attributes = determine_real_expression + exp_class, val = determine_real_expression_class - expression = instantiate_real_expression( - workitem, exp_name, exp_class, attributes) + expression = instantiate_real_expression(workitem, exp_class, val) expression.apply_time = Time.now expression.store_itself - expression.apply workitem + expression.apply(workitem) end - # - # This method is called by the expression pool when it is about - # to launch a process, it will interpret the 'parameter' statements - # in the process definition and raise an exception if the requirements - # are not met. - # - def check_parameters (workitem) - - extract_parameters.each do |param| - param.check(workitem) - end - end - #-- #def reply (workitem) # no implementation necessary #end #++ @@ -191,356 +110,221 @@ # # This method has been made public in order to have quick look # at the attributes of an expression before it's really # 'instantiated'. # + # (overriden by ExpExpression) + # def extract_attributes raw_representation[1] end - protected + # + # This method is called by the expression pool when it is about + # to launch a process, it will interpret the 'parameter' statements + # in the process definition and raise an exception if the requirements + # are not met. + # + def check_parameters (workitem) - # - # looks up a participant in the participant map, considers - # "my-participant" and "my_participant" as the same - # (by doing two lookups). - # - def lookup_participant (name) + #extract_parameters.each { |param| param.check(workitem) } + ExpressionTree.check_parameters(raw_representation, workitem) + end - p = get_participant_map.lookup_participant(name) + protected - unless p - name = OpenWFE::to_underscore(name) - p = get_participant_map.lookup_participant(name) - end + # + # Looks up a key as a variable or a participant. + # + def lookup (kind, key, underscore=false) - return name if p + val = (kind == :variable) ? + lookup_variable(key) : get_participant_map.lookup_participant(key) - nil - end + return lookup(:participant, val) || lookup(:variable, val) \ + if kind == :variable and val.is_a?(String) # alias lookup - # - # Determines if this raw expression points to a classical - # expression, a participant or a subprocess, or nothing at all... - # - def determine_real_expression + return val, key if val - exp_name = expression_name() - exp_class = expression_class() - var_value = lookup_variable exp_name - attributes = extract_attributes + return nil if underscore - unless var_value - # - # accomodating "sub_process_name" and "sub-process-name" - # - alt = OpenWFE::to_underscore exp_name - var_value = lookup_variable(alt) if alt != exp_name + lookup(kind, OpenWFE::to_underscore(key), true) + end - exp_name = alt if var_value - end + # + # Determines if this raw expression points to a classical + # expression, a participant or a subprocess, or nothing at all... + # + def determine_real_expression_class - var_value = exp_name \ - if (not exp_class and not var_value) + exp_name = expression_name() - if var_value.is_a?(String) + val, key = + lookup(:variable, exp_name) || + expression_class() || + lookup(:participant, exp_name) + # priority to variables - participant_name = lookup_participant var_value + if val.is_a?(Array) - if participant_name - exp_name = participant_name - exp_class = ParticipantExpression - attributes['ref'] = participant_name - end + [ SubProcessRefExpression, val ] - elsif var_value.is_a?(FlowExpressionId) \ - or var_value.is_a?(RawExpression) + elsif val.respond_to?(:consume) - exp_class = SubProcessRefExpression - attributes['ref'] = exp_name - end - # else, it's a standard expression + [ ParticipantExpression, key ] - [ exp_name, exp_class, attributes ] + else + + [ val, nil ] end + end - def extract_children + def instantiate_real_expression (workitem, exp_class, val) - i = 0 - result = [] - raw_representation.last.each do |child| + raise "unknown expression '#{expression_name}'" unless exp_class - if is_not_a_node?(child) + exp = exp_class.new + exp.fei = @fei + exp.parent_id = @parent_id + exp.environment_id = @environment_id + exp.application_context = @application_context + exp.attributes = extract_attributes() - result << child - else + exp.raw_representation = @raw_representation + exp.raw_rep_updated = @raw_rep_updated - cname = child.first.intern + consider_tag(workitem, exp) + consider_on_error(workitem, exp) + consider_on_cancel(workitem, exp) - next if cname == :param - next if cname == :parameter - #next if cname == :description + if val + class << exp + attr_accessor :hint + end + exp.hint = val + end # later sparing a variable/participant lookup - cfei = @fei.dup - cfei.expression_name = child.first - cfei.expression_id = "#{cfei.expression_id}.#{i}" + exp + end - efei = @environment_id + # + # Expressions can get tagged. Tagged expressions can easily + # be cancelled (undone) or redone. + # + def consider_tag (workitem, new_expression) - rawexp = RawExpression.new_raw( - cfei, @fei, efei, @application_context, child) + tagname = new_expression.lookup_string_attribute(:tag, workitem) - get_expression_pool.update rawexp + return unless tagname - i = i + 1 + #ldebug { "consider_tag() tag is '#{tagname}'" } - result << rawexp.fei - end - end - result - end + set_variable(tagname, Tag.new(self, workitem)) + # + # keep copy of raw expression and workitem as applied - def extract_parameters + new_expression.attributes['tag'] = tagname + # + # making sure that the value of tag doesn't change anymore + end - r = [] - raw_representation.last.each do |child| + # + # A small class wrapping a tag (a raw expression and the workitem + # it received at apply time. + # + class Tag - #next unless child.is_a?(SimpleExpRepresentation) - #next unless child.is_a?(Array) - next if is_not_a_node?(child) + attr_reader :raw_expression, :workitem - name = child.first.to_sym - next unless (name == :parameter or name == :param) - - attributes = child[1] - - r << Parameter.new( - attributes['field'], - attributes['match'], - attributes['default'], - attributes['type']) - end - r + def flow_expression_id + @raw_expression.fei end + alias :fei :flow_expression_id - def is_not_a_node? (child) + def initialize (raw_expression, workitem) - (( ! child.is_a?(Array)) || - child.size != 3 || - ( ! child.first.is_a?(String))) + @raw_expression = raw_expression.dup + @workitem = workitem.dup end + end - # - # Expressions can get tagged. Tagged expressions can easily - # be cancelled (undone) or redone. - # - def consider_tag (workitem, new_expression) + # + # manages 'on-error' expression tags + # + def consider_on_error (workitem, new_expression) - tagname = new_expression.lookup_string_attribute :tag, workitem + on_error = new_expression.lookup_string_attribute(:on_error, workitem) - return unless tagname + return unless on_error - ldebug { "consider_tag() tag is '#{tagname}'" } + on_error = on_error.to_s - set_variable tagname, Tag.new(self, workitem) - # - # keep copy of raw expression and workitem as applied + handlers = lookup_variable('error_handlers') || [] - new_expression.attributes["tag"] = tagname - # - # making sure that the value of tag doesn't change anymore - end + handlers << [ fei.dup, on_error ] + # not using a hash to preserve insertion order + # "deeper last" - # - # A small class wrapping a tag (a raw expression and the workitem - # it received at apply time. - # - class Tag + set_variable('error_handlers', handlers) - attr_reader \ - :raw_expression, - :workitem + new_expression.attributes['on_error'] = on_error + # + # making sure that the value of tag doesn't change anymore + end - def flow_expression_id - @raw_expression.fei - end - alias :fei :flow_expression_id + # + # manages 'on-cancel' + # + def consider_on_cancel (workitem, new_expression) - def initialize (raw_expression, workitem) + on_cancel = new_expression.lookup_string_attribute(:on_cancel, workitem) - @raw_expression = raw_expression.dup - @workitem = workitem.dup - end - end + return unless on_cancel - # - # Encapsulating - # <parameter field="x" default="y" type="z" match="m" /> - # - # Somehow I have that : OpenWFEru is not a strongly typed language - # ... Anyway I implemented that to please Pat. - # - class Parameter - - def initialize (field, match, default, type) - - @field = to_s field - @match = to_s match - @default = to_s default - @type = to_s type - end - + new_expression.attributes['on_cancel'] = [ on_cancel, workitem.dup ] # - # Will raise an exception if this param requirement is not - # met by the workitem. + # storing the on_cancel value (a participant name or a subprocess + # name along with a copy of the workitem as applied among the + # attributes of the new expression) # - def check (workitem) - - unless @field - raise \ - OpenWFE::ParameterException, - "'parameter'/'param' without a 'field' attribute" - end - - field_value = workitem.attributes[@field] - field_value = @default unless field_value - - unless field_value - raise \ - OpenWFE::ParameterException, - "field '#{@field}' is missing" \ - end - - check_match(field_value) - - enforce_type(workitem, field_value) - end - - protected - - # - # Used in the constructor to flatten everything to strings. - # - def to_s (o) - return nil unless o - o.to_s - end - - # - # Will raise an exception if it cannot coerce the type - # of the value to the one desired. - # - def enforce_type (workitem, value) - - value = if not @type - value - elsif @type == "string" - value.to_s - elsif @type == "int" or @type == "integer" - Integer(value) - elsif @type == "float" - Float(value) - else - raise - "unknown type '#{@type}' for field '#{@field}'" - end - - workitem.attributes[@field] = value - end - - def check_match (value) - - return unless @match - - unless value.to_s.match(@match) - raise \ - OpenWFE::ParameterException, - "value of field '#{@field}' doesn't match" - end - end - end - end - - # - # This class is only present to ensure that OpenWFEru 0.9.17 can read - # previous (<= 0.9.16) expools. - # - class ProgRawExpression < RawExpression - - def raw_representation - - @raw_representation.to_a + # (note 'on_cancel' and not 'on-cancel' as we're specifically storing + # more info and not just the initial string value of the attribute) end end + private + # - # This class is only present to ensure that OpenWFEru 0.9.17 can read - # previous (<= 0.9.16) expools. + # OpenWFE process definitions do use some + # Ruby keywords... The workaround is to put an underscore + # just before the name to 'escape' it. # - class XmlRawExpression < RawExpression + # 'undo' isn't reserved by Ruby, but lets keep it in line + # with 'do' and 'redo' that are. + # + KEYWORDS = [ + :if, :do, :redo, :undo, :print, :sleep, :loop, :break, :when + #:until, :while + ] - def raw_representation - - get_def_parser.parse @raw_representation_s - end - end - # - # This class is only present to ensure that OpenWFEru 0.9.17 can read - # previous (<= 0.9.16) expools. + # Ensures the method name is not conflicting with Ruby keywords + # and turn dashes to underscores. # - class SimpleExpRepresentation + def OpenWFE.make_safe (method_name) - def to_a + method_name = OpenWFE::to_underscore(method_name) - children = @children.collect do |c| - if c.is_a?(SimpleExpRepresentation) - c.to_a - else - c - end - end - - a = [ @name, @attributes, children ] - end + KEYWORDS.include?(method_name.to_sym) ? "_#{method_name}" : method_name end - private + def OpenWFE.to_expression_name (method_name) - # - # OpenWFE process definitions do use some - # Ruby keywords... The workaround is to put an underscore - # just before the name to 'escape' it. - # - # 'undo' isn't reserved by Ruby, but lets keep it in line - # with 'do' and 'redo' that are. - # - KEYWORDS = [ - :if, :do, :redo, :undo, :print, :sleep, :loop, :break, :when - #:until, :while - ] - - # - # Ensures the method name is not conflicting with Ruby keywords - # and turn dashes to underscores. - # - def OpenWFE.make_safe (method_name) - - method_name = OpenWFE::to_underscore(method_name) - - return "_" + method_name \ - if KEYWORDS.include? eval(":"+method_name) - - method_name - end - - def OpenWFE.to_expression_name (method_name) - - method_name = method_name.to_s - method_name = method_name[1..-1] if method_name[0, 1] == "_" - method_name = OpenWFE::to_dash(method_name) - method_name - end + method_name = method_name.to_s + method_name = method_name[1..-1] if method_name[0, 1] == '_' + method_name = OpenWFE::to_dash(method_name) + method_name + end end