# #-- # Copyright (c) 2007, John Mettraux, OpenWFE.org # All rights reserved. # # 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 # 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 # POSSIBILITY OF SUCH DAMAGE. #++ # # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $ # # # "made in Japan" # # John Mettraux at openwfe.org # require 'rexml/document' require 'openwfe/expressions/fe_raw' require 'openwfe/expressions/fe_utils' module OpenWFE # # A raw representation for a process definition, programmatic # process definitions are turned into trees of instances of this class. # class ProgExpRepresentation attr_reader \ :name, :attributes, :children def initialize (name, attributes) super() @name = name @attributes = attributes @children = [] end # # Adds a child to this expression representation. # def << (child) @children << child end # # Always return the ProgRawExpression class. # def rawExpressionClass return ProgRawExpression end # # Returns an XML string, containing the equivalent process definition # in the classical OpenWFE process definition language. # def to_s doc = REXML::Document.new() doc << to_xml s = "" doc.write(s, 0) return s end # # Returns this representation tree as an XML element (and its children). # def to_xml elt = REXML::Element.new(@name) #elt.attributes.update(@attributes) @attributes.each do |k, v| elt.attributes[k] = v end @children.each do |child| if child.kind_of? ProgExpRepresentation elt << child.to_xml else elt << REXML::Text.new(child.to_s) end end return elt end # # Returns a string containing the ruby code that generated this # raw representation tree. # def to_code_s (indentation = 0) s = "" tab = " " ind = tab * indentation s << ind s << OpenWFE.make_safe(@name) sa = "" @attributes.each do |k, v| sa << ", :#{k} => '#{v}'" end s << sa[1..-1] if sa.length > 0 if @children.length > 0 s << " do\n" @children.each do |child| if child.respond_to? :to_code_s s << child.to_code_s(indentation + 1) else s << ind s << tab s << "'#{child.to_s}'" end s << "\n" end s << ind s << "end" end return s end end # # This is the class to extend to create a programmatic process definition. # # A short example : # # class MyProcessDefinition < OpenWFE::ProcessDefinition # def make # process_definition :name => "test1", :revision => "0" do # sequence do # set :variable => "toto", :value => "nada" # print "toto:${toto}" # end # end # end # end # # li = OpenWFE::LaunchItem.new(MyProcessDefinition) # engine.launch(li) # # class ProcessDefinition def initialize (exp_names=nil) super() if not exp_names exp_names = $EXPRESSION_NAMES if $EXPRESSION_NAMES else if exp_names.kind_of? ExpressionMap exp_names = exp_names.expression_names elsif exp_names.kind_of? Engine exp_names = exp_names.get_expression_map.expression_names elsif exp_names.kind_of? Hash exp_names = exp_names[S_EXPRESSION_MAP].expression_names elsif not exp_names.kind_of? Array exp_names = $EXPRESSION_NAMES end end if not exp_names raise "no expression names found, please provide them" end @exp_names = exp_names #exp_names.each do |exp_name| # register_expression(exp_name) #end @previous_parent_expression = [] end # # previous trick # # kept for the record. # #def register_expression (expression_name) # _exp_name = OpenWFE.make_safe(exp_name) # self.instance_eval """ # def #{_exp_name} (params={}, &block) # make_expression('#{exp_name}', params, &block) # end # """ #end def method_missing (m, *args, &block) methodname = m.to_s expname = OpenWFE.to_expression_name(methodname) if not @exp_names.include? expname #raise "No expression named '#{methodname}' (#{expname}) found" #raise "No expression named '#{expname}' found" params = args[0] params = {} if not params params["ref"] = methodname return make_expression("subprocess", params, &block) end make_expression(expname, args[0], &block) end # # This method has to be overriden in order to define # a process definition. # def make raise "make() implementation is missing, please provide one" end def make_expression (exp_name, params, &block) exp_name = exp_name.to_s string_child = nil attributes = {} #puts " ... params.class is #{params.class}" if params.kind_of? Hash params.each do |k, v| #attributes[k.to_s] = v.to_s attributes[OpenWFE.to_dash(k.to_s)] = v.to_s end elsif params string_child = params.to_s end exp = ProgExpRepresentation.new(exp_name, attributes) exp.children << string_child \ if string_child @parent_expression << exp \ if @parent_expression return exp if not block @previous_parent_expression.push(@parent_expression) \ if @parent_expression @parent_expression = exp result = block.call #if result and result.kind_of? String and result.length > 0 # puts " ... child is >#{result}<" # exp.children << result #end #exp.children << result \ # if result and not result.kind_of? ProgExpRepresentation exp.children << result \ if result and result.kind_of? String @parent_expression = @previous_parent_expression.pop return exp end # # A class method for actually "making" the process # segment raw representation # def ProcessDefinition.do_make (exp_names=nil) self.new(exp_names).make end end # # The actual 'programmatic' raw expression. # Its raw_representation being an instance of ProgExpRepresentation. # class ProgRawExpression < RawExpression attr_accessor \ :raw_representation def initialize \ (fei, parent_id, env_id, application_context, raw_representation) super( fei, parent_id, env_id, application_context, raw_representation) end protected def extract_attributes () return raw_representation.attributes end def extract_children () i = 0 raw_representation.children.collect do |child| if child.kind_of? ProgExpRepresentation cfei = @fei.dup cfei.expression_name = child.name cfei.expression_id = "#{cfei.expression_id}.#{i}" efei = @environment_id rawexp = ProgRawExpression\ .new(cfei, @fei, efei, @application_context, child) get_expression_pool.update(rawexp) i = i + 1 rawexp.fei else child end end end end private # # 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 ] # # Ensures the method name is not conflicting with Ruby keywords # and turn dashes to underscores. # def OpenWFE.make_safe (method_name) method_name = to_underscore(method_name) return "_" + method_name \ if KEYWORDS.include? eval(":"+method_name) return method_name end def OpenWFE.to_expression_name (method_name) method_name = method_name[1..-1] if method_name[0, 1] == "_" method_name = to_dash(method_name) return method_name end end