diff options
author | Rajith Muditha Attapattu <rajith@apache.org> | 2011-05-27 15:44:23 +0000 |
---|---|---|
committer | Rajith Muditha Attapattu <rajith@apache.org> | 2011-05-27 15:44:23 +0000 |
commit | 66765100f4257159622cefe57bed50125a5ad017 (patch) | |
tree | a88ee23bb194eb91f0ebb2d9b23ff423e3ea8e37 /cpp/rubygen/amqpgen.rb | |
parent | 1aeaa7b16e5ce54f10c901d75c4d40f9f88b9db6 (diff) | |
parent | 88b98b2f4152ef59a671fad55a0d08338b6b78ca (diff) | |
download | qpid-python-rajith_jms_client.tar.gz |
Creating a branch for experimenting with some ideas for JMS client.rajith_jms_client
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rajith_jms_client@1128369 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/rubygen/amqpgen.rb')
-rwxr-xr-x | cpp/rubygen/amqpgen.rb | 550 |
1 files changed, 0 insertions, 550 deletions
diff --git a/cpp/rubygen/amqpgen.rb b/cpp/rubygen/amqpgen.rb deleted file mode 100755 index 20aac35194..0000000000 --- a/cpp/rubygen/amqpgen.rb +++ /dev/null @@ -1,550 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# Generic AMQP code generation library. -# -# TODO aconway 2008-02-21: -# -# The amqp_attr_reader and amqp_child_reader for each Amqp* class -# should correspond exactly to ampq.dtd. Currently they are more -# permissive so we can parse 0-10 preview and 0-10 final XML. -# -# Code marked with "# preview" should be removed/modified when final 0-10 -# is complete and we are ready to remove preview-related code. -# - -require 'delegate' -require 'rexml/document' -require 'pathname' -require 'set' -include REXML - -# Handy String functions for converting names. -class String - # Convert to CapitalizedForm. - def caps() gsub( /(^|\W)(\w)/ ) { |m| $2.upcase } end - - # Convert to underbar_separated_form. - def bars() tr('- .','_'); end - - # Convert to ALL_UPPERCASE_FORM - def shout() bars.upcase; end - - # Convert to lowerCaseCapitalizedForm - def lcaps() gsub( /\W(\w)/ ) { |m| $1.upcase } end - - def plural() self + (/[xs]$/ === self ? 'es' : 's'); end -end - -# Sort an array by name. -module Enumerable - def sort_by_name() sort { |a,b| a.name <=> b.name }; end -end - -# Add functions similar to attr_reader for AMQP attributes/children. -# Symbols that are ruby Object function names (e.g. class) get -# an "_" suffix. -class Module - # Add trailing _ to avoid conflict with Object methods. - def mangle(sym) - sym = (sym.to_s+"_").to_sym if (Object.method_defined?(sym) or sym == :type) - sym - end - - # Add attribute reader for XML attribute. - def amqp_attr_reader(*attrs) - attrs.each { |a| - case a - when Symbol - define_method(mangle(a)) { - @amqp_attr_reader||={ } - @amqp_attr_reader[a] ||= xml.attributes[a.to_s] - } - when Hash - a.each { |attr, default| - define_method(mangle(attr)) { - @amqp_attr_reader||={ } - value = xml.attributes[attr.to_s] - if value - @amqp_attr_reader[attr] ||= value - else - @amqp_attr_reader[attr] ||= default - end - } - } - end - } - end - - # Add 2 child readers: - # elname(name) == child('elname',name) - # elnames() == children('elname') - def amqp_child_reader(*element_names) - element_names.each { |e| - define_method(mangle(e)) { |name| child(e.to_s, name) } - define_method(mangle(e.to_s.plural)) { children(e.to_s) } } - end - - # When there can only be one child instance - def amqp_single_child_reader(*element_names) - element_names.each { |e| - define_method(mangle(e)) { children(e.to_s)[0] } } - end -end - -# An AmqpElement contains an XML element and provides a convenient -# API to access AMQP data. -# -# NB: AmqpElements cache values from XML, they assume that -# the XML model does not change after the AmqpElement has -# been created. -class AmqpElement - - def wrap(xml) - return nil if ["assert","rule"].include? xml.name - eval("Amqp"+xml.name.caps).new(xml, self) or raise "nil wrapper" - end - - public - - def initialize(xml, parent) - @xml, @parent=xml, parent - @children=xml.elements.map { |e| wrap e }.compact - @cache_child={} - @cache_child_named={} - @cache_children={} - @cache_children[nil]=@children - end - - attr_reader :parent, :xml, :children, :doc - amqp_attr_reader :name, :label - - # List of children of type elname, or all children if elname - # not specified. - def children(elname=nil) - if elname - @cache_children[elname] ||= @children.select { |c| elname==c.xml.name } - else - @children - end - end - - def each_descendant(&block) - yield self - @children.each { |c| c.each_descendant(&block) } - end - - def collect_all(amqp_type) - collect=[] - each_descendant { |d| collect << d if d.is_a? amqp_type } - collect - end - - # Look up child of type elname with attribute name. - def child(elname, name) - @cache_child[[elname,name]] ||= children(elname).find { |c| c.name==name } - end - - # Look up any child with name - def child_named(name) - @cache_child_named[name] ||= @children.find { |c| c.name==name } - end - - # The root <amqp> element. - def root() @root ||=parent ? parent.root : self; end - - def to_s() "#<#{self.class}(#{fqname})>"; end - def inspect() to_s; end - - # Text of doc child if there is one. - def doc() d=xml.elements["doc"]; d and d.text; end - - def fqname() - throw "fqname: #{self} #{parent.fqname} has no name" unless name - p=parent && parent.fqname - p ? p+"."+name : name; - end - - def containing_class() - return self if is_a? AmqpClass - return parent && parent.containing_class - end - - # 0-10 array domains are missing element type information, add it here. - ArrayTypes={ - "str16-array" => "str-16", - "amqp-host-array" => "connection.amqp-host-url", - "command-fragments" => "session.command-fragment", - "in-doubt" => "dtx.xid", - "tx-publish" => "str-8", - "queues" => "str-8" - } - - def array_type(name) - return ArrayTypes[name] if ArrayTypes[name] - raise "Missing ArrayType entry for " + name - end - -end - -class AmqpResponse < AmqpElement - def initialize(xml, parent) super; end - def fqname() (parent ? parent.dotted_name+"." : "") + "response"; end -end - -class AmqpDoc < AmqpElement - def initialize(xml,parent) super; end - def text() @xml.text end -end - -class AmqpChoice < AmqpElement - def initialize(xml,parent) super; end - amqp_attr_reader :name, :value -end - -class AmqpEnum < AmqpElement - def initialize(xml,parent) super; end - amqp_child_reader :choice -end - -class AmqpDomain < AmqpElement - def initialize(xml, parent) - super - root.used_by[uses].push(fqname) if uses and uses.index('.') - end - - amqp_attr_reader :type - amqp_single_child_reader :struct # preview - amqp_single_child_reader :enum - - def uses() type_=="array" ? ArrayTypes[name] : type_; end -end - -class AmqpException < AmqpElement - def initialize(xml, amqp) super; end; - amqp_attr_reader :error_code -end - -class AmqpField < AmqpElement - def initialize(xml, amqp) - super; - root.used_by[type_].push(parent.fqname) if type_ and type_.index('.') - end - amqp_single_child_reader :struct # preview - amqp_child_reader :exception - amqp_attr_reader :type, :default, :code, :required -end - -class AmqpChassis < AmqpElement # preview - def initialize(xml, parent) super; end - amqp_attr_reader :implement -end - -class AmqpConstant < AmqpElement - def initialize(xml, parent) super; end - amqp_attr_reader :value, :class -end - -class AmqpResult < AmqpElement - def initialize(xml, parent) super; end - amqp_single_child_reader :struct # preview - amqp_attr_reader :type - def name() "result"; end -end - -class AmqpEntry < AmqpElement - def initialize(xml,parent) super; end - amqp_attr_reader :type -end - -class AmqpHeader < AmqpElement - def initialize(xml,parent) super; end - amqp_child_reader :entry - amqp_attr_reader :required -end - -class AmqpBody < AmqpElement - def initialize(xml,parent) super; end - amqp_attr_reader :required -end - -class AmqpSegments < AmqpElement - def initialize(xml,parent) super; end - amqp_child_reader :header, :body -end - -class AmqpStruct < AmqpElement - def initialize(xml, parent) super; end - amqp_attr_reader :type # preview - amqp_attr_reader :size, :code, :pack - amqp_child_reader :field - - def result?() parent.xml.name == "result"; end - def domain?() parent.xml.name == "domain"; end -end - -class AmqpMethod < AmqpElement - def initialize(xml, parent) super; end - - amqp_attr_reader :content, :index, :synchronous - amqp_child_reader :field, :chassis,:response - amqp_single_child_reader :result - - def on_chassis?(chassis) child("chassis", chassis); end - def on_client?() on_chassis? "client"; end - def on_server?() on_chassis? "server"; end -end - -# preview: Map command/control to preview method. -class AmqpFakeMethod < AmqpMethod - def initialize(action) - super(action.xml, action.parent); - @action=action - end - - def content() return "1" if @action.is_a? AmqpCommand and @action.segments end - def index() @action.code end - def code() @action.code end - def synchronous() end - def on_chassis?(chassis) - @action.received_by?(chassis) - end - def pack() "2" end # Encode pack=2, size=4 struct - def size() "4" end -end - -class AmqpImplement < AmqpElement - def initialize(xml,amqp) super; end - amqp_attr_reader :handle, :send -end - -class AmqpRole < AmqpElement - def initialize(xml,amqp) super; end - amqp_attr_reader :implement -end - -# Base class for command and control. -class AmqpAction < AmqpElement - def initialize(xml,amqp) super; end - amqp_child_reader :implement, :field, :response - amqp_attr_reader :code - def implement?(role) - # we can't use xpath for this because it triggers a bug in some - # versions of ruby, including version 1.8.6.110 - xml.elements.each {|el| - return true if el.name == "implement" and el.attributes["role"] == role - } - return false - end - def received_by?(client_or_server) - return (implement?(client_or_server) or implement?("sender") or implement?("receiver")) - end - def pack() "2" end - def size() "4" end # Encoded as a size 4 Struct -end - -class AmqpControl < AmqpAction - def initialize(xml,amqp) super; end -end - -class AmqpCommand < AmqpAction - def initialize(xml,amqp) super; end - amqp_child_reader :exception - amqp_single_child_reader :result, :segments -end - -class AmqpClass < AmqpElement - def initialize(xml,amqp) super; end - - amqp_attr_reader :index # preview - - amqp_child_reader :struct, :domain, :control, :command, :role, :method - amqp_attr_reader :code - - def actions() controls+commands; end - - # preview - command/control as methods - def methods_() - return (controls + commands).map { |a| AmqpFakeMethod.new(a) } - end - - def method(name) - a = (command(name) or control(name)) - return AmqpFakeMethod.new(a) - end - - # chassis should be "client" or "server" - def methods_on(chassis) # preview - @methods_on ||= { } - @methods_on[chassis] ||= methods_.select { |m| m.on_chassis? chassis } - end - - # FIXME aconway 2008-04-11: - def l4?() # preview - !["connection", "session", "execution"].include?(name) && !control? - end - - # FIXME aconway 2008-04-11: - def control?() - ["connection", "session"].include?(name) - end -end - -class AmqpType < AmqpElement - def initialize(xml,amqp) super; end - amqp_attr_reader :code, :fixed_width, :variable_width -end - -class AmqpXref < AmqpElement - def initialize(xml,amqp) super; end -end - -# AMQP root element. -class AmqpRoot < AmqpElement - amqp_attr_reader :major, :minor, :port, :comment - amqp_child_reader :doc, :type, :struct, :domain, :constant, :class - - def get_root(x) - case x - when Element then x - when Document then x.root - else Document.new(x).root - end - end - - # Initialize with output directory and spec files from ARGV. - def initialize(*specs) - raise "No XML spec files." if specs.empty? - xml=get_root(specs.shift) - specs.each { |s| xml_merge(xml, get_root(s)) } - @used_by=Hash.new{ |h,k| h[k]=[] } - super(xml, nil) - end - - attr_reader :used_by - - def merge(root) xml_merge(xml, root.xml); end - - def version() major + "-" + minor; end - - def methods_() classes.map { |c| c.methods_ }.flatten; end - - #preview - # Return all methods on chassis for all classes. - def methods_on(chassis) - @methods_on ||= { } - @methods_on[chassis] ||= classes.map { |c| c.methods_on(chassis) }.flatten - end - - def fqname() nil; end - - private - - # Merge contents of elements. - def xml_merge(to,from) - from.elements.each { |from_child| - tag,name = from_child.name, from_child.attributes["name"] - to_child=to.elements["./#{tag}[@name='#{name}']"] - to_child ? xml_merge(to_child, from_child) : to.add(from_child.deep_clone) } - end -end - -# Collect information about generated files. -class GenFiles - @@files = Set.new - @@public_api = [] - def GenFiles.add(f) @@files.add(f); end - def GenFiles.get() @@files; end - def GenFiles.public_api(file) @@public_api << file; end - def GenFiles.public_api?(file) @@public_api.find { |f| f == file }; end -end - -# Base class for code generators. -# Supports setting a per-line prefix, useful for e.g. indenting code. -# -class Generator - # Takes directory for output or "-", meaning print file names that - # would be generated. - def initialize (outdir, amqp) - @outdir=outdir[0] - @apidir=outdir[1] - @amqp=amqp - raise "outdir is not an array" unless outdir.class == Array - @prefix=[''] # For indentation or comments. - @indentstr=' ' # One indent level. - @outdent=2 - end - - # Declare next file to be public API - def public_api(file) GenFiles.public_api(file); end - - # Create a new file, set @out. - def file(file, &block) - GenFiles.add(file) - dir = GenFiles.public_api?(file) ? @apidir : @outdir - if (dir != "-") - @path=Pathname.new "#{dir}/#{file}" - @path.parent.mkpath - @out=String.new # Generate in memory first - yield if block - if @path.exist? and @path.read == @out - puts "Skipped #{@path} - unchanged" # Dont generate if unchanged - else - @path.open('w') { |f| f << @out } - puts "Generated #{@path}" - end - end - end - - # Append multi-line string to generated code, prefixing each line. - def gen(str) - str.each_line { |line| - @out << @prefix.last unless @midline - @out << line - @midline = nil - } - # Note if we stopped mid-line - @midline = /[^\n]\z/ === str - end - - # Append str + '\n' to generated code. - def genl(str="") gen str+"\n"; end - - # Generate code with added prefix. - def prefix(add, &block) - @prefix.push @prefix.last+add - if block then yield; endprefix; end - end - - def endprefix() - @prefix.pop - end - - # Generate indented code - def indent(n=1,&block) prefix(@indentstr * n,&block); end - alias :endindent :endprefix - - # Generate outdented code - def outdent(&block) - @prefix.push @prefix.last[0...-2] - if block then yield; endprefix; end - end - alias :endoutdent :endprefix - - attr_accessor :out -end - |